'use client'

import { useState, useMemo, useCallback, useRef, useEffect } from 'react'
import { useParams } from 'next/navigation'
import Link from 'next/link'
import type { Route } from 'next'
import { trpc } from '@/lib/trpc/client'
import { toast } from 'sonner'
import { cn } from '@/lib/utils'
import { Button } from '@/components/ui/button'
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'
import { Skeleton } from '@/components/ui/skeleton'
import { Badge } from '@/components/ui/badge'
import { Checkbox } from '@/components/ui/checkbox'
import { Input } from '@/components/ui/input'
import { Switch } from '@/components/ui/switch'
import { Label } from '@/components/ui/label'
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuSeparator,
  DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu'
import {
  AlertDialog,
  AlertDialogAction,
  AlertDialogCancel,
  AlertDialogContent,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogHeader,
  AlertDialogTitle,
  AlertDialogTrigger,
} from '@/components/ui/alert-dialog'
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from '@/components/ui/dialog'
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from '@/components/ui/select'
import {
  ArrowLeft,
  Save,
  Loader2,
  ChevronDown,
  Play,
  Square,
  Archive,
  Layers,
  Users,
  CalendarDays,
  BarChart3,
  ClipboardList,
  Settings,
  Zap,
  Shield,
  UserPlus,
  CheckCircle2,
  AlertTriangle,
  FileText,
  Trophy,
  Clock,
  Send,
  Download,
  Plus,
  Trash2,
  ArrowRight,
  RotateCcw,
  X,
  Check,
  ChevronsUpDown,
  Search,
  MoreHorizontal,
  ShieldAlert,
  Eye,
  Pencil,
  Mail,
} from 'lucide-react'
import {
  Command,
  CommandEmpty,
  CommandGroup,
  CommandInput,
  CommandItem,
  CommandList,
} from '@/components/ui/command'
import {
  Popover,
  PopoverContent,
  PopoverTrigger,
} from '@/components/ui/popover'
import { ScrollArea } from '@/components/ui/scroll-area'
import {
  Tooltip,
  TooltipContent,
  TooltipProvider,
  TooltipTrigger,
} from '@/components/ui/tooltip'
import { RoundConfigForm } from '@/components/admin/competition/round-config-form'
import { ProjectStatesTable } from '@/components/admin/round/project-states-table'
// SubmissionWindowManager removed — round dates + file requirements in Config are sufficient
import { FileRequirementsEditor } from '@/components/admin/round/file-requirements-editor'
import { FilteringDashboard } from '@/components/admin/round/filtering-dashboard'
import { CoverageReport } from '@/components/admin/assignment/coverage-report'
import { AssignmentPreviewSheet } from '@/components/admin/assignment/assignment-preview-sheet'
import { CsvExportDialog } from '@/components/shared/csv-export-dialog'
import { AnimatedCard } from '@/components/shared/animated-container'
import { DateTimePicker } from '@/components/ui/datetime-picker'
import { AddMemberDialog } from '@/components/admin/jury/add-member-dialog'
import { motion } from 'motion/react'
import { EvaluationFormBuilder } from '@/components/forms/evaluation-form-builder'
import type { Criterion } from '@/components/forms/evaluation-form-builder'

// ── Helpers ────────────────────────────────────────────────────────────────

function getRelativeTime(date: Date): string {
  const now = new Date()
  const diffMs = date.getTime() - now.getTime()
  const absDiffMs = Math.abs(diffMs)
  const minutes = Math.floor(absDiffMs / 60_000)
  const hours = Math.floor(absDiffMs / 3_600_000)
  const days = Math.floor(absDiffMs / 86_400_000)

  const label = days > 0 ? `${days}d` : hours > 0 ? `${hours}h` : `${minutes}m`
  return diffMs > 0 ? `in ${label}` : `${label} ago`
}

// ── Status & type config maps ──────────────────────────────────────────────
const roundStatusConfig = {
  ROUND_DRAFT: {
    label: 'Draft',
    bgClass: 'bg-gray-100 text-gray-700',
    dotClass: 'bg-gray-500',
    description: 'Not yet active. Configure before launching.',
  },
  ROUND_ACTIVE: {
    label: 'Active',
    bgClass: 'bg-emerald-100 text-emerald-700',
    dotClass: 'bg-emerald-500 animate-pulse',
    description: 'Round is live. Projects can be processed.',
  },
  ROUND_CLOSED: {
    label: 'Closed',
    bgClass: 'bg-blue-100 text-blue-700',
    dotClass: 'bg-blue-500',
    description: 'No longer accepting changes. Results are final.',
  },
  ROUND_ARCHIVED: {
    label: 'Archived',
    bgClass: 'bg-muted text-muted-foreground',
    dotClass: 'bg-muted-foreground',
    description: 'Historical record only.',
  },
} as const

const roundTypeConfig: Record<string, { label: string; color: string; description: string }> = {
  INTAKE: { label: 'Intake', color: 'bg-gray-100 text-gray-700', description: 'Collecting applications' },
  FILTERING: { label: 'Filtering', color: 'bg-amber-100 text-amber-700', description: 'AI + manual screening' },
  EVALUATION: { label: 'Evaluation', color: 'bg-blue-100 text-blue-700', description: 'Jury evaluation & scoring' },
  SUBMISSION: { label: 'Submission', color: 'bg-purple-100 text-purple-700', description: 'Document submission' },
  MENTORING: { label: 'Mentoring', color: 'bg-teal-100 text-teal-700', description: 'Mentor-guided development' },
  LIVE_FINAL: { label: 'Live Final', color: 'bg-red-100 text-red-700', description: 'Live presentations & voting' },
  DELIBERATION: { label: 'Deliberation', color: 'bg-indigo-100 text-indigo-700', description: 'Final jury deliberation' },
}

const stateColors: Record<string, string> = {
  PENDING: 'bg-gray-400',
  IN_PROGRESS: 'bg-blue-500',
  PASSED: 'bg-green-500',
  REJECTED: 'bg-red-500',
  COMPLETED: 'bg-emerald-500',
  WITHDRAWN: 'bg-orange-400',
}

// ═══════════════════════════════════════════════════════════════════════════
// Main Page Component
// ═══════════════════════════════════════════════════════════════════════════

export default function RoundDetailPage() {
  const params = useParams()
  const roundId = params.roundId as string

  const [config, setConfig] = useState<Record<string, unknown>>({})
  const [autosaveStatus, setAutosaveStatus] = useState<'idle' | 'saving' | 'saved' | 'error'>('idle')
  const [activeTab, setActiveTab] = useState('overview')
  const [previewSheetOpen, setPreviewSheetOpen] = useState(false)

  // AI assignment generation (lifted to page level so it persists when sheet closes)
  const aiAssignmentMutation = trpc.roundAssignment.aiPreview.useMutation({
    onSuccess: () => {
      toast.success('AI assignments ready!', {
        action: {
          label: 'Review',
          onClick: () => setPreviewSheetOpen(true),
        },
        duration: 10000,
      })
    },
    onError: (err) => {
      toast.error(`AI generation failed: ${err.message}`, { duration: 15000 })
      console.error('[AI Assignment]', err)
    },
  })
  const [exportOpen, setExportOpen] = useState(false)
  const [advanceDialogOpen, setAdvanceDialogOpen] = useState(false)
  const [aiRecommendations, setAiRecommendations] = useState<{
    STARTUP: Array<{ projectId: string; rank: number; score: number; category: string; strengths: string[]; concerns: string[]; recommendation: string }>
    BUSINESS_CONCEPT: Array<{ projectId: string; rank: number; score: number; category: string; strengths: string[]; concerns: string[]; recommendation: string }>
  } | null>(null)
  const [shortlistDialogOpen, setShortlistDialogOpen] = useState(false)
  const [createJuryOpen, setCreateJuryOpen] = useState(false)
  const [newJuryName, setNewJuryName] = useState('')
  const [addMemberOpen, setAddMemberOpen] = useState(false)
  const [closeAndAdvance, setCloseAndAdvance] = useState(false)
  const [editingName, setEditingName] = useState(false)
  const [nameValue, setNameValue] = useState('')
  const nameInputRef = useRef<HTMLInputElement>(null)
  const [statusConfirmAction, setStatusConfirmAction] = useState<'activate' | 'close' | 'reopen' | 'archive' | null>(null)

  const utils = trpc.useUtils()

  // ── Core data queries ──────────────────────────────────────────────────
  const { data: round, isLoading } = trpc.round.getById.useQuery(
    { id: roundId },
    { refetchInterval: 15_000, refetchOnWindowFocus: true },
  )
  const { data: projectStates } = trpc.roundEngine.getProjectStates.useQuery(
    { roundId },
    { refetchInterval: 10_000, refetchOnWindowFocus: true },
  )

  const competitionId = round?.competitionId ?? ''

  const { data: juryGroups } = trpc.juryGroup.list.useQuery(
    { competitionId },
    { enabled: !!competitionId, refetchInterval: 30_000, refetchOnWindowFocus: true },
  )
  const { data: fileRequirements } = trpc.file.listRequirements.useQuery(
    { roundId },
    { refetchInterval: 15_000, refetchOnWindowFocus: true },
  )

  // Fetch awards linked to this round
  const { data: competition } = trpc.competition.getById.useQuery(
    { id: competitionId },
    { enabled: !!competitionId, refetchInterval: 60_000 },
  )
  const programId = competition?.programId
  const { data: awards } = trpc.specialAward.list.useQuery(
    { programId: programId! },
    { enabled: !!programId, refetchInterval: 60_000 },
  )
  const roundAwards = awards?.filter((a) => a.evaluationRoundId === roundId) ?? []

  // Filtering results stats (only for FILTERING rounds)
  const { data: filteringStats } = trpc.filtering.getResultStats.useQuery(
    { roundId },
    { enabled: round?.roundType === 'FILTERING', refetchInterval: 5_000 },
  )

  // Initialize config from server on load; re-sync after saves
  const serverConfig = useMemo(() => (round?.configJson as Record<string, unknown>) ?? {}, [round?.configJson])
  const configInitialized = useRef(false)
  const savingRef = useRef(false)

  // Sync local config with server: on initial load AND whenever serverConfig
  // changes after a save completes (so Zod-applied defaults get picked up)
  useEffect(() => {
    if (!round) return
    if (!configInitialized.current) {
      configInitialized.current = true
      setConfig(serverConfig)
    } else if (!savingRef.current) {
      // Server changed (e.g. after save invalidation) — re-sync
      setConfig(serverConfig)
    }
  }, [serverConfig, round])

  const hasUnsavedConfig = useMemo(
    () => configInitialized.current && JSON.stringify(config) !== JSON.stringify(serverConfig),
    [config, serverConfig],
  )

  // ── Mutations ──────────────────────────────────────────────────────────
  const updateMutation = trpc.round.update.useMutation({
    onSuccess: () => {
      savingRef.current = false
      utils.round.getById.invalidate({ id: roundId })
      setAutosaveStatus('saved')
      setTimeout(() => setAutosaveStatus('idle'), 2000)
    },
    onError: (err) => {
      savingRef.current = false
      setAutosaveStatus('error')
      toast.error(err.message)
    },
  })

  const activateMutation = trpc.roundEngine.activate.useMutation({
    onSuccess: () => {
      utils.round.getById.invalidate({ id: roundId })
      toast.success('Round activated')
    },
    onError: (err) => toast.error(err.message),
  })

  const closeMutation = trpc.roundEngine.close.useMutation({
    onSuccess: () => {
      utils.round.getById.invalidate({ id: roundId })
      toast.success('Round closed')
      if (closeAndAdvance) {
        setCloseAndAdvance(false)
        // Small delay to let cache invalidation complete before opening dialog
        setTimeout(() => setAdvanceDialogOpen(true), 300)
      }
    },
    onError: (err) => {
      setCloseAndAdvance(false)
      toast.error(err.message)
    },
  })

  const reopenMutation = trpc.roundEngine.reopen.useMutation({
    onSuccess: (data) => {
      utils.round.getById.invalidate({ id: roundId })
      utils.roundEngine.getProjectStates.invalidate({ roundId })
      const msg = data.pausedRounds?.length
        ? `Round reopened. Paused: ${data.pausedRounds.join(', ')}`
        : 'Round reopened'
      toast.success(msg)
    },
    onError: (err) => toast.error(err.message),
  })

  const archiveMutation = trpc.roundEngine.archive.useMutation({
    onSuccess: () => {
      utils.round.getById.invalidate({ id: roundId })
      toast.success('Round archived')
    },
    onError: (err) => toast.error(err.message),
  })

  const assignJuryMutation = trpc.round.update.useMutation({
    onSuccess: () => {
      utils.round.getById.invalidate({ id: roundId })
      utils.juryGroup.list.invalidate({ competitionId })
      toast.success('Jury group updated')
    },
    onError: (err) => toast.error(err.message),
  })

  // Jury group detail query (for the assigned group)
  const juryGroupId = round?.juryGroupId ?? ''
  const { data: juryGroupDetail } = trpc.juryGroup.getById.useQuery(
    { id: juryGroupId },
    { enabled: !!juryGroupId, refetchInterval: 10_000 },
  )

  const createJuryMutation = trpc.juryGroup.create.useMutation({
    onSuccess: (newGroup) => {
      utils.juryGroup.list.invalidate({ competitionId })
      // Auto-assign the new jury group to this round
      assignJuryMutation.mutate({ id: roundId, juryGroupId: newGroup.id })
      toast.success(`Jury "${newGroup.name}" created and assigned`)
      setCreateJuryOpen(false)
      setNewJuryName('')
    },
    onError: (err) => toast.error(err.message),
  })

  const deleteJuryMutation = trpc.juryGroup.delete.useMutation({
    onSuccess: (result) => {
      utils.juryGroup.list.invalidate({ competitionId })
      utils.round.getById.invalidate({ id: roundId })
      toast.success(`Jury "${result.name}" deleted`)
    },
    onError: (err) => toast.error(err.message),
  })

  const removeJuryMemberMutation = trpc.juryGroup.removeMember.useMutation({
    onSuccess: () => {
      if (juryGroupId) utils.juryGroup.getById.invalidate({ id: juryGroupId })
      toast.success('Member removed')
    },
    onError: (err) => toast.error(err.message),
  })

  const updateJuryMemberMutation = trpc.juryGroup.updateMember.useMutation({
    onSuccess: () => {
      if (juryGroupId) utils.juryGroup.getById.invalidate({ id: juryGroupId })
      toast.success('Cap updated')
    },
    onError: (err) => toast.error(err.message),
  })

  const advanceMutation = trpc.round.advanceProjects.useMutation({
    onSuccess: (data) => {
      utils.round.getById.invalidate({ id: roundId })
      utils.roundEngine.getProjectStates.invalidate({ roundId })
      const msg = data.autoPassedCount
        ? `Passed ${data.autoPassedCount} and advanced ${data.advancedCount} project(s) to ${data.targetRoundName}`
        : `Advanced ${data.advancedCount} project(s) to ${data.targetRoundName}`
      toast.success(msg)
      setAdvanceDialogOpen(false)
    },
    onError: (err) => toast.error(err.message),
  })

  const shortlistMutation = trpc.round.generateAIRecommendations.useMutation({
    onSuccess: (data) => {
      if (data.success) {
        setAiRecommendations(data.recommendations)
        toast.success(
          `AI recommendations generated: ${data.recommendations.STARTUP.length} startups, ${data.recommendations.BUSINESS_CONCEPT.length} concepts` +
          (data.tokensUsed ? ` (${data.tokensUsed} tokens)` : ''),
        )
      } else {
        toast.error(data.errors?.join('; ') || 'AI shortlist failed')
      }
      setShortlistDialogOpen(false)
    },
    onError: (err) => {
      toast.error(err.message)
      setShortlistDialogOpen(false)
    },
  })

  const isTransitioning = activateMutation.isPending || closeMutation.isPending || reopenMutation.isPending || archiveMutation.isPending

  const handleConfigChange = useCallback((newConfig: Record<string, unknown>) => {
    setConfig(newConfig)
  }, [])

  const saveConfig = useCallback(() => {
    savingRef.current = true
    setAutosaveStatus('saving')
    updateMutation.mutate({ id: roundId, configJson: config })
  }, [config, roundId, updateMutation])

  // ── Auto-save: debounce config changes and save automatically ────────
  const configJson = JSON.stringify(config)
  const serverJson = JSON.stringify(serverConfig)
  useEffect(() => {
    if (!configInitialized.current) return
    if (configJson === serverJson) return

    const timer = setTimeout(() => {
      savingRef.current = true
      setAutosaveStatus('saving')
      updateMutation.mutate({ id: roundId, configJson: config })
    }, 800)

    return () => clearTimeout(timer)
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [configJson])

  // ── Computed values ────────────────────────────────────────────────────
  const projectCount = projectStates?.length ?? round?._count?.projectRoundStates ?? 0
  const stateCounts = useMemo(() =>
    projectStates?.reduce((acc: Record<string, number>, ps: any) => {
      acc[ps.state] = (acc[ps.state] || 0) + 1
      return acc
    }, {} as Record<string, number>) ?? {},
  [projectStates])
  const passedCount = stateCounts['PASSED'] ?? 0
  const juryGroup = round?.juryGroup
  const juryMemberCount = juryGroupDetail?.members?.length ?? 0

  const isFiltering = round?.roundType === 'FILTERING'
  const isEvaluation = round?.roundType === 'EVALUATION'
  const hasJury = ['EVALUATION', 'LIVE_FINAL', 'DELIBERATION'].includes(round?.roundType ?? '')
  const hasAwards = hasJury
  const isSimpleAdvance = ['INTAKE', 'SUBMISSION', 'MENTORING'].includes(round?.roundType ?? '')

  const poolLink = `/admin/projects/pool?roundId=${roundId}&competitionId=${competitionId}` as Route

  // ── Loading state ──────────────────────────────────────────────────────
  if (isLoading) {
    return (
      <div className="space-y-6">
        {/* Header skeleton — dark gradient placeholder */}
        <div className="rounded-xl bg-gradient-to-r from-[#053d57]/20 to-[#0a5a7c]/20 p-6 animate-pulse">
          <div className="flex items-center gap-3">
            <Skeleton className="h-8 w-8 rounded bg-white/20" />
            <div className="space-y-2">
              <Skeleton className="h-7 w-64 bg-white/20" />
              <Skeleton className="h-4 w-40 bg-white/20" />
            </div>
          </div>
        </div>
        <div className="grid gap-3 grid-cols-2 sm:grid-cols-4">
          {[1, 2, 3, 4].map((i) => <Skeleton key={i} className="h-28 rounded-lg" />)}
        </div>
        <Skeleton className="h-10 w-full" />
        <Skeleton className="h-96 w-full rounded-lg" />
      </div>
    )
  }

  if (!round) {
    return (
      <div className="space-y-6">
        <div className="flex items-center gap-3">
          <Link href={'/admin/rounds' as Route}>
            <Button variant="ghost" size="icon" className="h-8 w-8" aria-label="Back">
              <ArrowLeft className="h-4 w-4" />
            </Button>
          </Link>
          <div>
            <h1 className="text-xl font-bold">Round Not Found</h1>
            <p className="text-sm text-muted-foreground">This round does not exist.</p>
          </div>
        </div>
      </div>
    )
  }

  const status = round.status as keyof typeof roundStatusConfig
  const statusCfg = roundStatusConfig[status] || roundStatusConfig.ROUND_DRAFT
  const typeCfg = roundTypeConfig[round.roundType] || roundTypeConfig.INTAKE

  // ── Readiness checklist ────────────────────────────────────────────────
  const readinessItems = [
    {
      label: 'Projects assigned',
      ready: projectCount > 0,
      detail: projectCount > 0 ? `${projectCount} projects` : 'No projects yet',
      action: projectCount === 0 ? poolLink : undefined,
      actionLabel: 'Assign Projects',
    },
    ...(hasJury
      ? [{
          label: 'Jury group set',
          ready: !!juryGroup,
          detail: juryGroup ? `${juryGroup.name} (${juryMemberCount} members)` : 'No jury group assigned',
          action: undefined as Route | undefined,
          actionLabel: undefined as string | undefined,
        }]
      : []),
    {
      label: 'Dates configured',
      ready: !!round.windowOpenAt && !!round.windowCloseAt,
      detail:
        round.windowOpenAt && round.windowCloseAt
          ? `${new Date(round.windowOpenAt).toLocaleDateString()} \u2014 ${new Date(round.windowCloseAt).toLocaleDateString()}`
          : 'No dates set \u2014 configure in Config tab',
      action: undefined as Route | undefined,
      actionLabel: undefined as string | undefined,
    },
    ...((isEvaluation && !(config.requireDocumentUpload as boolean))
      ? []
      : [{
          label: 'File requirements set',
          ready: (fileRequirements?.length ?? 0) > 0,
          detail:
            (fileRequirements?.length ?? 0) > 0
              ? `${fileRequirements?.length} requirement(s)`
              : 'No file requirements \u2014 configure in Config tab',
          action: undefined as Route | undefined,
          actionLabel: undefined as string | undefined,
        }]),
  ]
  const readyCount = readinessItems.filter((i) => i.ready).length

  // ═════════════════════════════════════════════════════════════════════════
  // Render
  // ═════════════════════════════════════════════════════════════════════════

  return (
    <div className="space-y-6">
      {/* ===== HEADER — Dark Blue gradient banner ===== */}
      <motion.div
        initial={{ opacity: 0, y: -8 }}
        animate={{ opacity: 1, y: 0 }}
        transition={{ duration: 0.4, ease: 'easeOut' }}
        className="rounded-xl bg-gradient-to-r from-[#053d57] to-[#0a5a7c] p-5 sm:p-6 text-white shadow-lg"
      >
        <div className="flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between">
          <div className="flex items-start gap-3 min-w-0">
            <Link href={(round.specialAwardId ? `/admin/awards/${round.specialAwardId}` : '/admin/rounds') as Route} className="mt-0.5 shrink-0">
              <Button variant="ghost" size="sm" className="h-8 text-white/80 hover:text-white hover:bg-white/10 gap-1.5" aria-label={round.specialAwardId ? 'Back to Award' : 'Back to rounds'}>
                <ArrowLeft className="h-4 w-4" />
                <span className="text-xs hidden sm:inline">{round.specialAwardId ? 'Back to Award' : 'Back to Rounds'}</span>
              </Button>
            </Link>
            <div className="min-w-0">
              <div className="flex flex-wrap items-center gap-2.5">
                {/* 4.6 Inline-editable round name */}
                {editingName ? (
                  <Input
                    ref={nameInputRef}
                    value={nameValue}
                    onChange={(e) => setNameValue(e.target.value)}
                    onBlur={() => {
                      const trimmed = nameValue.trim()
                      if (trimmed && trimmed !== round.name) {
                        updateMutation.mutate({ id: roundId, name: trimmed })
                      }
                      setEditingName(false)
                    }}
                    onKeyDown={(e) => {
                      if (e.key === 'Enter') {
                        (e.target as HTMLInputElement).blur()
                      }
                      if (e.key === 'Escape') {
                        setNameValue(round.name)
                        setEditingName(false)
                      }
                    }}
                    className="text-xl font-bold tracking-tight bg-white/10 border-white/30 text-white h-8 w-64"
                    autoFocus
                  />
                ) : (
                  <button
                    type="button"
                    className="text-xl font-bold tracking-tight truncate hover:bg-white/10 rounded px-1 -mx-1 transition-colors cursor-text"
                    onClick={() => {
                      setNameValue(round.name)
                      setEditingName(true)
                      setTimeout(() => nameInputRef.current?.focus(), 0)
                    }}
                    title="Click to edit round name"
                  >
                    {round.name}
                  </button>
                )}
                <Badge variant="secondary" className="text-xs shrink-0 bg-white/15 text-white border-white/20 hover:bg-white/20">
                  {typeCfg.label}
                </Badge>

                {/* Status dropdown with confirmation dialogs (4.1) */}
                <TooltipProvider>
                  <Tooltip>
                    <TooltipTrigger asChild>
                      <span>
                        <DropdownMenu>
                          <DropdownMenuTrigger asChild>
                            <button
                              className={cn(
                                'inline-flex items-center gap-1.5 text-[11px] font-medium px-2.5 py-1 rounded-full transition-colors shrink-0',
                                'bg-white/15 text-white hover:bg-white/25',
                              )}
                            >
                              <span className={cn('h-1.5 w-1.5 rounded-full', statusCfg.dotClass)} />
                              {statusCfg.label}
                              <ChevronDown className="h-3 w-3" />
                            </button>
                          </DropdownMenuTrigger>
                          <DropdownMenuContent align="start">
                            {status === 'ROUND_DRAFT' && (
                              <DropdownMenuItem
                                onClick={() => setStatusConfirmAction('activate')}
                                disabled={isTransitioning}
                              >
                                <Play className="h-4 w-4 mr-2 text-emerald-600" />
                                Activate Round
                              </DropdownMenuItem>
                            )}
                            {status === 'ROUND_ACTIVE' && (
                              <DropdownMenuItem
                                onClick={() => setStatusConfirmAction('close')}
                                disabled={isTransitioning}
                              >
                                <Square className="h-4 w-4 mr-2 text-blue-600" />
                                Close Round
                              </DropdownMenuItem>
                            )}
                            {status === 'ROUND_CLOSED' && (
                              <>
                                <DropdownMenuItem
                                  onClick={() => setStatusConfirmAction('reopen')}
                                  disabled={isTransitioning}
                                >
                                  <Play className="h-4 w-4 mr-2 text-emerald-600" />
                                  Reopen Round
                                </DropdownMenuItem>
                                <DropdownMenuSeparator />
                                <DropdownMenuItem
                                  onClick={() => setStatusConfirmAction('archive')}
                                  disabled={isTransitioning}
                                >
                                  <Archive className="h-4 w-4 mr-2" />
                                  Archive Round
                                </DropdownMenuItem>
                              </>
                            )}
                            {isTransitioning && (
                              <div className="flex items-center gap-2 px-2 py-1.5 text-xs text-muted-foreground">
                                <Loader2 className="h-3 w-3 animate-spin" />
                                Updating...
                              </div>
                            )}
                          </DropdownMenuContent>
                        </DropdownMenu>
                      </span>
                    </TooltipTrigger>
                    <TooltipContent side="bottom">
                      <p>{statusCfg.description}</p>
                    </TooltipContent>
                  </Tooltip>
                </TooltipProvider>

                {/* Status change confirmation dialog (4.1) */}
                <AlertDialog open={!!statusConfirmAction} onOpenChange={(open) => { if (!open) setStatusConfirmAction(null) }}>
                  <AlertDialogContent>
                    <AlertDialogHeader>
                      <AlertDialogTitle>
                        {statusConfirmAction === 'activate' && 'Activate this round?'}
                        {statusConfirmAction === 'close' && 'Close this round?'}
                        {statusConfirmAction === 'reopen' && 'Reopen this round?'}
                        {statusConfirmAction === 'archive' && 'Archive this round?'}
                      </AlertDialogTitle>
                      <AlertDialogDescription>
                        {statusConfirmAction === 'activate' && 'The round will go live. Projects can be processed and jury members will be able to see their assignments.'}
                        {statusConfirmAction === 'close' && 'No further changes will be accepted. You can reactivate later if needed.'}
                        {statusConfirmAction === 'reopen' && 'The round will become active again. Any rounds after this one that are currently active will be paused automatically.'}
                        {statusConfirmAction === 'archive' && 'The round will be archived. It will only be available as a historical record.'}
                      </AlertDialogDescription>
                    </AlertDialogHeader>
                    <AlertDialogFooter>
                      <AlertDialogCancel>Cancel</AlertDialogCancel>
                      <AlertDialogAction
                        onClick={() => {
                          if (statusConfirmAction === 'activate') activateMutation.mutate({ roundId })
                          else if (statusConfirmAction === 'close') closeMutation.mutate({ roundId })
                          else if (statusConfirmAction === 'reopen') reopenMutation.mutate({ roundId })
                          else if (statusConfirmAction === 'archive') archiveMutation.mutate({ roundId })
                          setStatusConfirmAction(null)
                        }}
                      >
                        {statusConfirmAction === 'activate' && 'Activate'}
                        {statusConfirmAction === 'close' && 'Close Round'}
                        {statusConfirmAction === 'reopen' && 'Reopen'}
                        {statusConfirmAction === 'archive' && 'Archive'}
                      </AlertDialogAction>
                    </AlertDialogFooter>
                  </AlertDialogContent>
                </AlertDialog>
              </div>
              <p className="text-sm text-white/60 mt-1">{typeCfg.description}</p>
            </div>
          </div>

          {/* Action buttons */}
          <div className="flex items-center gap-2 shrink-0 flex-wrap">
            {autosaveStatus === 'saved' && (
              <span className="flex items-center gap-1.5 text-xs text-emerald-300">
                <CheckCircle2 className="h-3.5 w-3.5" />
                Saved
              </span>
            )}
            <Link href={poolLink}>
              <Button variant="outline" size="sm" className="border-white/40 bg-white/15 text-white hover:bg-white/30 hover:text-white">
                <Layers className="h-4 w-4 mr-1.5" />
                Project Pool
              </Button>
            </Link>
          </div>
        </div>
      </motion.div>

      {/* ===== STATS BAR — Accent-bordered cards ===== */}
      <div className={cn("grid gap-3 grid-cols-2", hasJury ? "sm:grid-cols-4" : "sm:grid-cols-3")}>
        {/* Projects */}
        <AnimatedCard index={0}>
          <Card className="border-l-4 border-l-[#557f8c] hover:shadow-md transition-shadow">
            <CardContent className="pt-4 pb-3">
              <div className="flex items-center gap-2.5">
                <div className="rounded-full bg-[#557f8c]/10 p-1.5">
                  <Layers className="h-4 w-4 text-[#557f8c]" />
                </div>
                <span className="text-sm font-medium text-muted-foreground">Projects</span>
              </div>
              <p className="text-3xl font-bold mt-2">{projectCount}</p>
              <div className="flex flex-wrap gap-1.5 mt-1.5">
                {Object.entries(stateCounts).map(([state, count]) => (
                  <span key={state} className="text-[10px] text-muted-foreground">
                    {String(count)} {state.toLowerCase().replace('_', ' ')}
                  </span>
                ))}
              </div>
            </CardContent>
          </Card>
        </AnimatedCard>

        {/* Jury (with inline group selector) — only for jury-relevant rounds */}
        {hasJury && (
          <AnimatedCard index={1}>
            <Card className="border-l-4 border-l-purple-500 hover:shadow-md transition-shadow">
              <CardContent className="pt-4 pb-3">
                <div className="flex items-center gap-2.5 mb-1" data-jury-select>
                  <div className="rounded-full bg-purple-50 p-1.5">
                    <Users className="h-4 w-4 text-purple-500" />
                  </div>
                  <span className="text-sm font-medium text-muted-foreground">Jury</span>
                </div>
                {juryGroup ? (
                  <>
                    <p className="text-3xl font-bold mt-2">{juryMemberCount}</p>
                    <div className="flex items-center gap-2">
                      <p className="text-xs text-muted-foreground truncate">{juryGroup.name}</p>
                      <button
                        type="button"
                        className="text-[10px] text-[#557f8c] hover:underline shrink-0"
                        onClick={() => setActiveTab('jury')}
                      >
                        Change
                      </button>
                    </div>
                  </>
                ) : (
                  <>
                    <p className="text-3xl font-bold mt-2 text-muted-foreground">&mdash;</p>
                    <button
                      type="button"
                      className="text-xs text-[#557f8c] hover:underline"
                      onClick={() => setActiveTab('jury')}
                    >
                      Assign jury group
                    </button>
                  </>
                )}
              </CardContent>
            </Card>
          </AnimatedCard>
        )}

        {/* Window */}
        <AnimatedCard index={hasJury ? 2 : 1}>
          <Card className="border-l-4 border-l-emerald-500 hover:shadow-md transition-shadow">
            <CardContent className="pt-4 pb-3">
              <div className="flex items-center gap-2.5">
                <div className="rounded-full bg-emerald-50 p-1.5">
                  <CalendarDays className="h-4 w-4 text-emerald-500" />
                </div>
                <span className="text-sm font-medium text-muted-foreground">Window</span>
              </div>
              {round.windowOpenAt || round.windowCloseAt ? (
                <>
                  <p className="text-sm font-bold mt-2">
                    {round.windowOpenAt
                      ? new Date(round.windowOpenAt).toLocaleDateString()
                      : 'No start'}
                  </p>
                  <p className="text-xs text-muted-foreground">
                    {round.windowCloseAt
                      ? `Closes ${new Date(round.windowCloseAt).toLocaleDateString()}`
                      : 'No deadline'}
                  </p>
                  {(() => {
                    const now = new Date()
                    const openAt = round.windowOpenAt ? new Date(round.windowOpenAt) : null
                    const closeAt = round.windowCloseAt ? new Date(round.windowCloseAt) : null
                    if (openAt && now < openAt) {
                      return <p className="text-[10px] text-[#557f8c] font-medium mt-0.5">Opens {getRelativeTime(openAt)}</p>
                    }
                    if (closeAt && now < closeAt) {
                      return <p className="text-[10px] text-amber-600 font-medium mt-0.5">Closes {getRelativeTime(closeAt)}</p>
                    }
                    if (closeAt && now >= closeAt) {
                      return <p className="text-[10px] text-muted-foreground mt-0.5">Closed {getRelativeTime(closeAt)}</p>
                    }
                    return null
                  })()}
                </>
              ) : (
                <>
                  <p className="text-3xl font-bold mt-2 text-muted-foreground">&mdash;</p>
                  <p className="text-xs text-muted-foreground">No dates set</p>
                </>
              )}
            </CardContent>
          </Card>
        </AnimatedCard>

        {/* Advancement */}
        <AnimatedCard index={hasJury ? 3 : 2}>
          <Card className="border-l-4 border-l-amber-500 hover:shadow-md transition-shadow">
            <CardContent className="pt-4 pb-3">
              <div className="flex items-center gap-2.5">
                <div className="rounded-full bg-amber-50 p-1.5">
                  <BarChart3 className="h-4 w-4 text-amber-500" />
                </div>
                <span className="text-sm font-medium text-muted-foreground">Advancement</span>
              </div>
              {round.advancementRules && round.advancementRules.length > 0 ? (
                <>
                  <p className="text-3xl font-bold mt-2">{round.advancementRules.length}</p>
                  <p className="text-xs text-muted-foreground">
                    {round.advancementRules.map((r: any) => r.ruleType.replace('_', ' ').toLowerCase()).join(', ')}
                  </p>
                </>
              ) : (
                <>
                  <p className="text-3xl font-bold mt-2 text-muted-foreground">&mdash;</p>
                  <p className="text-xs text-muted-foreground">Admin selection</p>
                </>
              )}
            </CardContent>
          </Card>
        </AnimatedCard>
      </div>

      {/* ===== TABS — Underline style ===== */}
      <Tabs value={activeTab} onValueChange={setActiveTab} className="space-y-4">
        <div className="border-b overflow-x-auto">
          <TabsList className="bg-transparent h-auto p-0 gap-0 w-full sm:w-auto">
            {[
              { value: 'overview', label: 'Overview', icon: Zap },
              { value: 'projects', label: 'Projects', icon: Layers },
              ...(isFiltering ? [{ value: 'filtering', label: 'Filtering', icon: Shield }] : []),
              ...(isEvaluation ? [{ value: 'assignments', label: 'Assignments', icon: ClipboardList }] : []),
              ...(hasJury ? [{ value: 'jury', label: 'Jury', icon: Users }] : []),
              { value: 'config', label: 'Config', icon: Settings },
              ...(hasAwards ? [{ value: 'awards', label: 'Awards', icon: Trophy }] : []),
            ].map((tab) => (
              <TabsTrigger
                key={tab.value}
                value={tab.value}
                className={cn(
                  'relative rounded-none border-b-2 border-transparent px-4 py-2.5 text-sm font-medium transition-all',
                  'data-[state=active]:border-b-[#de0f1e] data-[state=active]:text-[#053d57] data-[state=active]:font-semibold data-[state=active]:shadow-none',
                  'text-muted-foreground hover:text-foreground',
                  'bg-transparent data-[state=active]:bg-transparent',
                )}
              >
                <tab.icon className={cn('h-3.5 w-3.5 mr-1.5', activeTab === tab.value ? 'text-[#557f8c]' : '')} />
                {tab.label}
                {tab.value === 'awards' && roundAwards.length > 0 && (
                  <Badge variant="secondary" className="ml-1.5 h-5 min-w-5 text-[10px] px-1.5 bg-[#de0f1e] text-white">
                    {roundAwards.length}
                  </Badge>
                )}
              </TabsTrigger>
            ))}
          </TabsList>
        </div>

        {/* ═══════════ OVERVIEW TAB ═══════════ */}
        <TabsContent value="overview" className="space-y-6">
          {/* Readiness Checklist with Progress Ring */}
          <AnimatedCard index={0}>
            <Card>
              <CardHeader>
                <div className="flex items-center justify-between">
                  <div className="flex items-center gap-4">
                    {/* SVG Progress Ring */}
                    <div className="relative h-14 w-14 shrink-0">
                      <svg className="h-14 w-14 -rotate-90" viewBox="0 0 56 56">
                        <circle cx="28" cy="28" r="24" fill="none" stroke="currentColor" strokeWidth="3" className="text-muted/30" />
                        <circle
                          cx="28" cy="28" r="24" fill="none"
                          strokeWidth="3" strokeLinecap="round"
                          stroke={readyCount === readinessItems.length ? '#10b981' : '#de0f1e'}
                          strokeDasharray={`${(readyCount / readinessItems.length) * 150.8} 150.8`}
                          className="transition-all duration-700"
                        />
                      </svg>
                      <span className="absolute inset-0 flex items-center justify-center text-xs font-bold">
                        {readyCount}/{readinessItems.length}
                      </span>
                    </div>
                    <div>
                      <CardTitle className="text-base">Launch Readiness</CardTitle>
                      <CardDescription>
                        {readyCount === readinessItems.length
                          ? 'All checks passed — ready to go'
                          : `${readinessItems.length - readyCount} item(s) remaining`}
                      </CardDescription>
                    </div>
                  </div>
                  <Badge
                    variant={readyCount === readinessItems.length ? 'default' : 'secondary'}
                    className={cn(
                      'text-xs',
                      readyCount === readinessItems.length
                        ? 'bg-emerald-100 text-emerald-700'
                        : 'bg-amber-100 text-amber-700',
                    )}
                  >
                    {readyCount === readinessItems.length ? 'Ready' : 'Incomplete'}
                  </Badge>
                </div>
              </CardHeader>
              <CardContent>
                <div className="space-y-3">
                  {readinessItems.map((item) => (
                    <div key={item.label} className="flex items-start gap-3">
                      {item.ready ? (
                        <CheckCircle2 className="h-4 w-4 text-emerald-500 mt-0.5 shrink-0" />
                      ) : (
                        <AlertTriangle className="h-4 w-4 text-amber-500 mt-0.5 shrink-0" />
                      )}
                      <div className="flex-1 min-w-0">
                        <p className={cn('text-sm font-medium', item.ready && 'text-emerald-600 opacity-80')}>
                          {item.label}
                        </p>
                        <p className="text-xs text-muted-foreground">{item.detail}</p>
                      </div>
                      {item.action && (
                        <Link href={item.action}>
                          <Button size="sm" className="shrink-0 text-xs bg-[#de0f1e] hover:bg-[#c00d1a] text-white">
                            {item.actionLabel}
                          </Button>
                        </Link>
                      )}
                    </div>
                  ))}
                </div>
              </CardContent>
            </Card>
          </AnimatedCard>

          {/* Filtering Results Summary — only for FILTERING rounds with results */}
          {isFiltering && filteringStats && filteringStats.total > 0 && (
            <AnimatedCard index={1}>
              <Card className="border-l-4 border-l-purple-500">
                <CardHeader className="pb-3">
                  <div className="flex items-center justify-between">
                    <div className="flex items-center gap-3">
                      <div className="rounded-full bg-purple-50 p-2">
                        <Shield className="h-5 w-5 text-purple-600" />
                      </div>
                      <div>
                        <CardTitle className="text-base">Filtering Results</CardTitle>
                        <CardDescription>
                          {filteringStats.total} projects evaluated
                        </CardDescription>
                      </div>
                    </div>
                    <Button
                      size="sm"
                      variant="outline"
                      onClick={() => setActiveTab('filtering')}
                    >
                      View Details
                      <ArrowRight className="h-3.5 w-3.5 ml-1.5" />
                    </Button>
                  </div>
                </CardHeader>
                <CardContent>
                  <div className="grid grid-cols-3 gap-4 mb-4">
                    <div className="text-center p-3 rounded-lg bg-emerald-50">
                      <p className="text-2xl font-bold text-emerald-700">{filteringStats.passed}</p>
                      <p className="text-xs text-emerald-600 font-medium">Passed</p>
                    </div>
                    <div className="text-center p-3 rounded-lg bg-red-50">
                      <p className="text-2xl font-bold text-red-700">{filteringStats.filteredOut}</p>
                      <p className="text-xs text-red-600 font-medium">Filtered Out</p>
                    </div>
                    <div className="text-center p-3 rounded-lg bg-amber-50">
                      <p className="text-2xl font-bold text-amber-700">{filteringStats.flagged}</p>
                      <p className="text-xs text-amber-600 font-medium">Flagged</p>
                    </div>
                  </div>
                  {/* Progress bar showing pass rate */}
                  <div className="space-y-1.5">
                    <div className="flex justify-between text-xs text-muted-foreground">
                      <span>Pass rate</span>
                      <span>{Math.round((filteringStats.passed / filteringStats.total) * 100)}%</span>
                    </div>
                    <div className="h-2.5 rounded-full bg-muted overflow-hidden flex">
                      <div
                        className="bg-emerald-500 transition-all duration-500"
                        style={{ width: `${(filteringStats.passed / filteringStats.total) * 100}%` }}
                      />
                      <div
                        className="bg-red-400 transition-all duration-500"
                        style={{ width: `${(filteringStats.filteredOut / filteringStats.total) * 100}%` }}
                      />
                      <div
                        className="bg-amber-400 transition-all duration-500"
                        style={{ width: `${(filteringStats.flagged / filteringStats.total) * 100}%` }}
                      />
                    </div>
                    {filteringStats.overridden > 0 && (
                      <p className="text-xs text-muted-foreground">
                        {filteringStats.overridden} result(s) manually overridden
                      </p>
                    )}
                  </div>
                </CardContent>
              </Card>
            </AnimatedCard>
          )}

          {/* Quick Actions — Grouped & styled */}
          <AnimatedCard index={2}>
            <Card>
              <CardHeader>
                <CardTitle className="text-base">Quick Actions</CardTitle>
                <CardDescription>Common operations for this round</CardDescription>
              </CardHeader>
              <CardContent className="space-y-4">
                {/* Round Control Group */}
                {(status === 'ROUND_DRAFT' || status === 'ROUND_ACTIVE' || status === 'ROUND_CLOSED') && (
                  <div>
                    <p className="text-[11px] font-semibold uppercase tracking-wider text-muted-foreground mb-2">Round Control</p>
                    <div className="grid gap-3 sm:grid-cols-2 lg:grid-cols-3">
                      {status === 'ROUND_DRAFT' && (
                        <AlertDialog>
                          <AlertDialogTrigger asChild>
                            <button className="flex items-start gap-3 p-4 rounded-lg border border-l-4 border-l-emerald-500 hover:-translate-y-0.5 hover:shadow-md transition-all text-left">
                              <Play className="h-5 w-5 text-emerald-600 mt-0.5 shrink-0" />
                              <div>
                                <p className="text-sm font-medium">Activate Round</p>
                                <p className="text-xs text-muted-foreground mt-0.5">
                                  Start this round and allow project processing
                                </p>
                              </div>
                            </button>
                          </AlertDialogTrigger>
                          <AlertDialogContent>
                            <AlertDialogHeader>
                              <AlertDialogTitle>Activate this round?</AlertDialogTitle>
                              <AlertDialogDescription>
                                The round will go live. Projects can be processed and jury members will be able to see their assignments.
                              </AlertDialogDescription>
                            </AlertDialogHeader>
                            <AlertDialogFooter>
                              <AlertDialogCancel>Cancel</AlertDialogCancel>
                              <AlertDialogAction onClick={() => activateMutation.mutate({ roundId })}>
                                Activate
                              </AlertDialogAction>
                            </AlertDialogFooter>
                          </AlertDialogContent>
                        </AlertDialog>
                      )}

                      {status === 'ROUND_ACTIVE' && (
                        <AlertDialog>
                          <AlertDialogTrigger asChild>
                            <button className="flex items-start gap-3 p-4 rounded-lg border border-l-4 border-l-blue-500 hover:-translate-y-0.5 hover:shadow-md transition-all text-left">
                              <Square className="h-5 w-5 text-blue-600 mt-0.5 shrink-0" />
                              <div>
                                <p className="text-sm font-medium">Close Round</p>
                                <p className="text-xs text-muted-foreground mt-0.5">
                                  Stop accepting changes and finalize results
                                </p>
                              </div>
                            </button>
                          </AlertDialogTrigger>
                          <AlertDialogContent>
                            <AlertDialogHeader>
                              <AlertDialogTitle>Close this round?</AlertDialogTitle>
                              <AlertDialogDescription>
                                No further changes will be accepted. You can reactivate later if needed.
                                {projectCount > 0 && (
                                  <span className="block mt-2">
                                    {projectCount} projects are currently in this round.
                                  </span>
                                )}
                              </AlertDialogDescription>
                            </AlertDialogHeader>
                            <AlertDialogFooter>
                              <AlertDialogCancel>Cancel</AlertDialogCancel>
                              <AlertDialogAction onClick={() => closeMutation.mutate({ roundId })}>
                                Close Round
                              </AlertDialogAction>
                            </AlertDialogFooter>
                          </AlertDialogContent>
                        </AlertDialog>
                      )}

                      {status === 'ROUND_CLOSED' && (
                        <AlertDialog>
                          <AlertDialogTrigger asChild>
                            <button className="flex items-start gap-3 p-4 rounded-lg border border-l-4 border-l-amber-500 bg-amber-50/30 hover:-translate-y-0.5 hover:shadow-md transition-all text-left">
                              <RotateCcw className="h-5 w-5 text-amber-600 mt-0.5 shrink-0" />
                              <div>
                                <p className="text-sm font-medium">Reopen Round</p>
                                <p className="text-xs text-muted-foreground mt-0.5">
                                  Reactivate this round. Any subsequent active rounds will be paused.
                                </p>
                              </div>
                            </button>
                          </AlertDialogTrigger>
                          <AlertDialogContent>
                            <AlertDialogHeader>
                              <AlertDialogTitle>Reopen this round?</AlertDialogTitle>
                              <AlertDialogDescription>
                                The round will become active again. Any rounds after this one that are currently active will be paused (closed) automatically.
                              </AlertDialogDescription>
                            </AlertDialogHeader>
                            <AlertDialogFooter>
                              <AlertDialogCancel>Cancel</AlertDialogCancel>
                              <AlertDialogAction onClick={() => reopenMutation.mutate({ roundId })}>
                                Reopen
                              </AlertDialogAction>
                            </AlertDialogFooter>
                          </AlertDialogContent>
                        </AlertDialog>
                      )}
                    </div>
                  </div>
                )}

                {/* Project Management Group */}
                <div>
                  <p className="text-[11px] font-semibold uppercase tracking-wider text-muted-foreground mb-2">Project Management</p>
                  <div className="grid gap-3 sm:grid-cols-2 lg:grid-cols-3">
                    <Link href={poolLink}>
                      <button className="flex items-start gap-3 p-4 rounded-lg border hover:-translate-y-0.5 hover:shadow-md transition-all text-left w-full">
                        <Layers className="h-5 w-5 text-[#557f8c] mt-0.5 shrink-0" />
                        <div>
                          <p className="text-sm font-medium">Assign Projects</p>
                          <p className="text-xs text-muted-foreground mt-0.5">
                            Add projects from the pool to this round
                          </p>
                        </div>
                      </button>
                    </Link>

                    <button
                      onClick={() => setActiveTab('projects')}
                      className="flex items-start gap-3 p-4 rounded-lg border hover:-translate-y-0.5 hover:shadow-md transition-all text-left"
                    >
                      <BarChart3 className="h-5 w-5 text-[#557f8c] mt-0.5 shrink-0" />
                      <div>
                        <p className="text-sm font-medium">Manage Projects</p>
                        <p className="text-xs text-muted-foreground mt-0.5">
                          View, filter, and transition project states
                        </p>
                      </div>
                    </button>

                    {/* Advance projects (always visible when projects exist) */}
                    {projectCount > 0 && (
                      <button
                        onClick={() => (isSimpleAdvance || passedCount > 0)
                          ? setAdvanceDialogOpen(true)
                          : toast.info('Mark projects as "Passed" first in the Projects tab')}
                        className={cn(
                          'flex items-start gap-3 p-4 rounded-lg border hover:-translate-y-0.5 hover:shadow-md transition-all text-left',
                          (isSimpleAdvance || passedCount > 0)
                            ? 'border-l-4 border-l-emerald-500 bg-emerald-50/30'
                            : 'border-dashed opacity-60',
                        )}
                      >
                        <ArrowRight className={cn('h-5 w-5 mt-0.5 shrink-0', (isSimpleAdvance || passedCount > 0) ? 'text-emerald-600' : 'text-muted-foreground')} />
                        <div>
                          <p className="text-sm font-medium">Advance Projects</p>
                          <p className="text-xs text-muted-foreground mt-0.5">
                            {isSimpleAdvance
                              ? `Advance all ${projectCount} project(s) to the next round`
                              : passedCount > 0
                                ? `Move ${passedCount} passed project(s) to the next round`
                                : 'Mark projects as "Passed" first, then advance'}
                          </p>
                        </div>
                        <Badge className="ml-auto shrink-0 bg-emerald-100 text-emerald-700 text-[10px]">{isSimpleAdvance ? projectCount : passedCount}</Badge>
                      </button>
                    )}

                    {/* Close & Advance (active rounds with passed projects) */}
                    {status === 'ROUND_ACTIVE' && passedCount > 0 && (
                      <button
                        onClick={() => {
                          setCloseAndAdvance(true)
                          closeMutation.mutate({ roundId })
                        }}
                        disabled={isTransitioning}
                        className="flex items-start gap-3 p-4 rounded-lg border border-l-4 border-l-purple-500 bg-purple-50/30 hover:-translate-y-0.5 hover:shadow-md transition-all text-left"
                      >
                        <Square className="h-5 w-5 text-purple-600 mt-0.5 shrink-0" />
                        <div>
                          <p className="text-sm font-medium">Close & Advance</p>
                          <p className="text-xs text-muted-foreground mt-0.5">
                            Close this round and advance {passedCount} passed project(s) to the next round
                          </p>
                        </div>
                      </button>
                    )}

                    {/* Jury assignment for rounds that use jury */}
                    {hasJury && !juryGroup && (
                      <button
                        onClick={() => {
                          const el = document.querySelector('[data-jury-select]')
                          if (el) el.scrollIntoView({ behavior: 'smooth', block: 'center' })
                        }}
                        className="flex items-start gap-3 p-4 rounded-lg border border-l-4 border-l-amber-500 bg-amber-50/30 hover:-translate-y-0.5 hover:shadow-md transition-all text-left"
                      >
                        <UserPlus className="h-5 w-5 text-amber-600 mt-0.5 shrink-0" />
                        <div>
                          <p className="text-sm font-medium">Assign Jury Group</p>
                          <p className="text-xs text-muted-foreground mt-0.5">
                            No jury group assigned. Select one in the Jury card above.
                          </p>
                        </div>
                      </button>
                    )}

                    {/* Evaluation: manage assignments */}
                    {isEvaluation && (
                      <button
                        onClick={() => setActiveTab('assignments')}
                        className="flex items-start gap-3 p-4 rounded-lg border hover:-translate-y-0.5 hover:shadow-md transition-all text-left"
                      >
                        <ClipboardList className="h-5 w-5 text-[#557f8c] mt-0.5 shrink-0" />
                        <div>
                          <p className="text-sm font-medium">Manage Assignments</p>
                          <p className="text-xs text-muted-foreground mt-0.5">
                            Generate and review jury-project assignments
                          </p>
                        </div>
                      </button>
                    )}
                  </div>
                </div>

                {/* AI Tools Group */}
                {((isFiltering || isEvaluation) && projectCount > 0) && (
                  <div>
                    <p className="text-[11px] font-semibold uppercase tracking-wider text-muted-foreground mb-2">AI Tools</p>
                    <div className="grid gap-3 sm:grid-cols-2 lg:grid-cols-3">
                      {isFiltering && (
                        <button
                          onClick={() => setActiveTab('filtering')}
                          className="flex items-start gap-3 p-4 rounded-lg border bg-gradient-to-br from-purple-50/50 to-blue-50/50 hover:-translate-y-0.5 hover:shadow-md transition-all text-left"
                        >
                          <Shield className="h-5 w-5 text-purple-600 mt-0.5 shrink-0" />
                          <div>
                            <p className="text-sm font-medium">Run AI Filtering</p>
                            <p className="text-xs text-muted-foreground mt-0.5">
                              Screen projects with AI and manual review
                            </p>
                          </div>
                        </button>
                      )}

                      <button
                        onClick={() => setShortlistDialogOpen(true)}
                        className="flex items-start gap-3 p-4 rounded-lg border bg-gradient-to-br from-purple-50/50 to-blue-50/50 hover:-translate-y-0.5 hover:shadow-md transition-all text-left"
                        disabled={shortlistMutation.isPending}
                      >
                        <Zap className="h-5 w-5 text-purple-600 mt-0.5 shrink-0" />
                        <div>
                          <p className="text-sm font-medium">
                            {shortlistMutation.isPending ? 'Generating...' : 'AI Recommendations'}
                          </p>
                          <p className="text-xs text-muted-foreground mt-0.5">
                            Generate ranked shortlist per category using AI analysis
                          </p>
                        </div>
                      </button>
                    </div>
                  </div>
                )}
              </CardContent>
            </Card>
          </AnimatedCard>

          {/* Advance Projects Dialog */}
          <AdvanceProjectsDialog
            open={advanceDialogOpen}
            onOpenChange={setAdvanceDialogOpen}
            roundId={roundId}
            roundType={round?.roundType}
            projectStates={projectStates}
            config={config}
            advanceMutation={advanceMutation}
            competitionRounds={competition?.rounds?.map((r: any) => ({
              id: r.id,
              name: r.name,
              sortOrder: r.sortOrder,
              roundType: r.roundType,
            }))}
            currentSortOrder={round?.sortOrder}
          />

          {/* AI Shortlist Confirmation Dialog */}
          <AlertDialog open={shortlistDialogOpen} onOpenChange={setShortlistDialogOpen}>
            <AlertDialogContent>
              <AlertDialogHeader>
                <AlertDialogTitle>Generate AI Recommendations?</AlertDialogTitle>
                <AlertDialogDescription>
                  The AI will analyze all project evaluations and generate a ranked shortlist
                  for each category independently.
                  {config.startupAdvanceCount ? (
                    <span className="block mt-1">
                      Startup target: top {String(config.startupAdvanceCount)}
                    </span>
                  ) : null}
                  {config.conceptAdvanceCount ? (
                    <span className="block">
                      Business Concept target: top {String(config.conceptAdvanceCount)}
                    </span>
                  ) : null}
                  {config.aiParseFiles ? (
                    <span className="block mt-1 text-amber-600">
                      Document parsing is enabled — the AI will read uploaded file contents.
                    </span>
                  ) : null}
                </AlertDialogDescription>
              </AlertDialogHeader>
              <AlertDialogFooter>
                <AlertDialogCancel>Cancel</AlertDialogCancel>
                <AlertDialogAction
                  onClick={() => shortlistMutation.mutate({ roundId })}
                  disabled={shortlistMutation.isPending}
                >
                  {shortlistMutation.isPending && <Loader2 className="h-4 w-4 mr-1.5 animate-spin" />}
                  Generate
                </AlertDialogAction>
              </AlertDialogFooter>
            </AlertDialogContent>
          </AlertDialog>

          {/* AI Recommendations Display */}
          {aiRecommendations && (
            <AIRecommendationsDisplay
              recommendations={aiRecommendations}
              projectStates={projectStates}
              roundId={roundId}
              onClear={() => setAiRecommendations(null)}
              onApplied={() => {
                setAiRecommendations(null)
                utils.roundEngine.getProjectStates.invalidate({ roundId })
              }}
            />
          )}

          {/* Round Info + Project Breakdown */}
          <div className="grid gap-4 sm:grid-cols-2">
            <AnimatedCard index={2}>
              <Card>
                <CardHeader>
                  <CardTitle className="text-sm">Round Details</CardTitle>
                </CardHeader>
                <CardContent className="space-y-0 text-sm">
                  {[
                    { label: 'Type', value: <Badge variant="secondary" className={cn('text-xs', typeCfg.color)}>{typeCfg.label}</Badge> },
                    { label: 'Status', value: <span className="font-medium">{statusCfg.label}</span> },
                    { label: 'Position', value: <span className="font-medium">{`Round ${(round.sortOrder ?? 0) + 1}${competition?.rounds ? ` of ${competition.rounds.length}` : ''}`}</span> },
                    ...(round.purposeKey ? [{ label: 'Purpose', value: <span className="font-medium">{round.purposeKey}</span> }] : []),
                    { label: 'Jury Group', value: <span className="font-medium">{juryGroup ? juryGroup.name : '\u2014'}</span> },
                    { label: 'Opens', value: <span className="font-medium">{round.windowOpenAt ? new Date(round.windowOpenAt).toLocaleString() : '\u2014'}</span> },
                    { label: 'Closes', value: <span className="font-medium">{round.windowCloseAt ? new Date(round.windowCloseAt).toLocaleString() : '\u2014'}</span> },
                  ].map((row, i) => (
                    <div key={row.label} className={cn('flex justify-between items-center py-2.5', i > 0 && 'border-t border-dotted border-muted')}>
                      <span className="text-muted-foreground">{row.label}</span>
                      {row.value}
                    </div>
                  ))}
                </CardContent>
              </Card>
            </AnimatedCard>

            <AnimatedCard index={3}>
              <Card>
                <CardHeader>
                  <div className="flex items-center justify-between">
                    <CardTitle className="text-sm">Project Breakdown</CardTitle>
                    {projectCount > 0 && (
                      <span className="text-xs font-mono text-muted-foreground">{projectCount} total</span>
                    )}
                  </div>
                </CardHeader>
                <CardContent>
                  {projectCount === 0 ? (
                    <p className="text-sm text-muted-foreground py-4 text-center">
                      No projects assigned yet
                    </p>
                  ) : (
                    <div className="space-y-3">
                      {['PENDING', 'IN_PROGRESS', 'PASSED', 'REJECTED', 'COMPLETED', 'WITHDRAWN'].map((state) => {
                        const count = stateCounts[state] || 0
                        if (count === 0) return null
                        const pct = ((count / projectCount) * 100).toFixed(0)
                        return (
                          <div key={state}>
                            <div className="flex justify-between text-xs mb-1.5">
                              <span className="text-muted-foreground capitalize font-medium">{state.toLowerCase().replace('_', ' ')}</span>
                              <span className="font-bold tabular-nums">{count} <span className="font-normal text-muted-foreground">({pct}%)</span></span>
                            </div>
                            <div className="h-2 bg-muted rounded-full overflow-hidden">
                              <div
                                className={cn('h-full rounded-full transition-all duration-500', stateColors[state])}
                                style={{ width: `${pct}%` }}
                              />
                            </div>
                          </div>
                        )
                      })}
                    </div>
                  )}
                </CardContent>
              </Card>
            </AnimatedCard>
          </div>
        </TabsContent>

        {/* ═══════════ PROJECTS TAB ═══════════ */}
        <TabsContent value="projects" className="space-y-4">
          <ProjectStatesTable competitionId={competitionId} roundId={roundId} />
        </TabsContent>

        {/* ═══════════ FILTERING TAB ═══════════ */}
        {isFiltering && (
          <TabsContent value="filtering" className="space-y-4">
            <FilteringDashboard competitionId={competitionId} roundId={roundId} />
          </TabsContent>
        )}

        {/* ═══════════ JURY TAB ═══════════ */}
        {hasJury && (
        <TabsContent value="jury" className="space-y-6">
          {/* Jury Group Selector + Create */}
          <Card>
            <CardHeader>
              <div className="flex items-center justify-between">
                <div>
                  <CardTitle className="text-base">Jury Group</CardTitle>
                  <CardDescription>
                    Select or create a jury group for this round
                  </CardDescription>
                </div>
                <div className="flex items-center gap-2">
                  <Button size="sm" variant="outline" onClick={() => setCreateJuryOpen(true)}>
                    <Plus className="h-4 w-4 mr-1.5" />
                    New Jury
                  </Button>
                </div>
              </div>
            </CardHeader>
            <CardContent>
              {juryGroups && juryGroups.length > 0 ? (
                <div className="space-y-4">
                  <Select
                    value={round.juryGroupId ?? '__none__'}
                    onValueChange={(value) => {
                      assignJuryMutation.mutate({
                        id: roundId,
                        juryGroupId: value === '__none__' ? null : value,
                      })
                    }}
                    disabled={assignJuryMutation.isPending}
                  >
                    <SelectTrigger className="w-full sm:w-80">
                      <SelectValue placeholder="Select jury group..." />
                    </SelectTrigger>
                    <SelectContent>
                      <SelectItem value="__none__">No jury assigned</SelectItem>
                      {juryGroups.map((jg: any) => (
                        <SelectItem key={jg.id} value={jg.id}>
                          {jg.name} ({jg._count?.members ?? 0} members)
                        </SelectItem>
                      ))}
                    </SelectContent>
                  </Select>

                  {/* Delete button for currently selected jury group */}
                  {round.juryGroupId && (
                    <AlertDialog>
                      <AlertDialogTrigger asChild>
                        <Button size="sm" variant="ghost" className="text-destructive hover:text-destructive">
                          <Trash2 className="h-4 w-4 mr-1.5" />
                          Delete &quot;{juryGroup?.name}&quot;
                        </Button>
                      </AlertDialogTrigger>
                      <AlertDialogContent>
                        <AlertDialogHeader>
                          <AlertDialogTitle>Delete jury group?</AlertDialogTitle>
                          <AlertDialogDescription>
                            This will permanently delete &quot;{juryGroup?.name}&quot; and remove all its members.
                            Rounds using this jury group will be unlinked. This action cannot be undone.
                          </AlertDialogDescription>
                        </AlertDialogHeader>
                        <AlertDialogFooter>
                          <AlertDialogCancel>Cancel</AlertDialogCancel>
                          <AlertDialogAction
                            onClick={() => deleteJuryMutation.mutate({ id: round.juryGroupId! })}
                            className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
                            disabled={deleteJuryMutation.isPending}
                          >
                            {deleteJuryMutation.isPending && <Loader2 className="h-4 w-4 mr-1.5 animate-spin" />}
                            Delete Jury
                          </AlertDialogAction>
                        </AlertDialogFooter>
                      </AlertDialogContent>
                    </AlertDialog>
                  )}
                </div>
              ) : (
                <div className="flex flex-col items-center justify-center py-10 text-center">
                  <div className="rounded-full bg-purple-50 p-4 mb-4">
                    <Users className="h-8 w-8 text-purple-400" />
                  </div>
                  <p className="text-sm font-medium">No Jury Groups</p>
                  <p className="text-xs text-muted-foreground mt-1 max-w-sm">
                    Create a jury group to assign members who will evaluate projects in this round.
                  </p>
                  <Button size="sm" className="mt-4" onClick={() => setCreateJuryOpen(true)}>
                    <Plus className="h-4 w-4 mr-1.5" />
                    Create First Jury
                  </Button>
                </div>
              )}
            </CardContent>
          </Card>

          {/* Members list (only if a jury group is assigned) */}
          {juryGroupDetail && (
            <Card>
              <CardHeader>
                <div className="flex items-center justify-between">
                  <div>
                    <CardTitle className="text-base">
                      Members &mdash; {juryGroupDetail.name}
                    </CardTitle>
                    <CardDescription>
                      {juryGroupDetail.members.length} member{juryGroupDetail.members.length !== 1 ? 's' : ''}
                    </CardDescription>
                  </div>
                  <Button size="sm" onClick={() => setAddMemberOpen(true)}>
                    <UserPlus className="h-4 w-4 mr-1.5" />
                    Add Member
                  </Button>
                </div>
              </CardHeader>
              <CardContent>
                {juryGroupDetail.members.length === 0 ? (
                  <div className="flex flex-col items-center justify-center py-10 text-center">
                    <div className="rounded-full bg-muted p-4 mb-4">
                      <UserPlus className="h-8 w-8 text-muted-foreground" />
                    </div>
                    <p className="text-sm font-medium">No Members Yet</p>
                    <p className="text-xs text-muted-foreground mt-1">
                      Add jury members to start assigning projects for evaluation.
                    </p>
                    <Button size="sm" variant="outline" className="mt-4" onClick={() => setAddMemberOpen(true)}>
                      <UserPlus className="h-4 w-4 mr-1.5" />
                      Add First Member
                    </Button>
                  </div>
                ) : (
                  <div className="space-y-1">
                    {juryGroupDetail.members.map((member: any, idx: number) => (
                      <div
                        key={member.id}
                        className={cn(
                          'flex items-center justify-between py-2.5 px-3 rounded-md transition-colors',
                          idx % 2 === 1 && 'bg-muted/30',
                        )}
                      >
                        <div className="min-w-0 flex-1">
                          <p className="text-sm font-medium truncate">
                            {member.user.name || 'Unnamed User'}
                          </p>
                          <p className="text-xs text-muted-foreground truncate">{member.user.email}</p>
                        </div>
                        <div className="flex items-center gap-2 shrink-0">
                          <InlineMemberCap
                            memberId={member.id}
                            currentValue={member.maxAssignmentsOverride as number | null}
                            onSave={(val) => updateJuryMemberMutation.mutate({
                              id: member.id,
                              maxAssignmentsOverride: val,
                            })}
                          />
                        <AlertDialog>
                          <AlertDialogTrigger asChild>
                            <Button
                              variant="ghost"
                              size="icon"
                              className="h-7 w-7 text-destructive hover:text-destructive shrink-0"
                            >
                              <Trash2 className="h-3.5 w-3.5" />
                            </Button>
                          </AlertDialogTrigger>
                          <AlertDialogContent>
                            <AlertDialogHeader>
                              <AlertDialogTitle>Remove member?</AlertDialogTitle>
                              <AlertDialogDescription>
                                Remove {member.user.name || member.user.email} from {juryGroupDetail.name}?
                              </AlertDialogDescription>
                            </AlertDialogHeader>
                            <AlertDialogFooter>
                              <AlertDialogCancel>Cancel</AlertDialogCancel>
                              <AlertDialogAction
                                onClick={() => removeJuryMemberMutation.mutate({ id: member.id })}
                                className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
                              >
                                Remove
                              </AlertDialogAction>
                            </AlertDialogFooter>
                          </AlertDialogContent>
                        </AlertDialog>
                        </div>
                      </div>
                    ))}
                  </div>
                )}
              </CardContent>
            </Card>
          )}

          {/* Create Jury Dialog */}
          <Dialog open={createJuryOpen} onOpenChange={setCreateJuryOpen}>
            <DialogContent>
              <DialogHeader>
                <DialogTitle>Create Jury Group</DialogTitle>
                <DialogDescription>
                  Create a new jury group for this competition. It will be automatically assigned to this round.
                </DialogDescription>
              </DialogHeader>
              <div className="space-y-4">
                <div className="space-y-2">
                  <label className="text-sm font-medium">Name</label>
                  <Input
                    placeholder="e.g. Round 1 Jury, Expert Panel, Final Jury"
                    value={newJuryName}
                    onChange={(e) => setNewJuryName(e.target.value)}
                    onKeyDown={(e) => {
                      if (e.key === 'Enter' && newJuryName.trim()) {
                        createJuryMutation.mutate({
                          competitionId,
                          name: newJuryName.trim(),
                          slug: newJuryName.trim().toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/(^-|-$)/g, ''),
                        })
                      }
                    }}
                  />
                </div>
              </div>
              <DialogFooter>
                <Button variant="outline" onClick={() => setCreateJuryOpen(false)}>Cancel</Button>
                <Button
                  onClick={() => {
                    createJuryMutation.mutate({
                      competitionId,
                      name: newJuryName.trim(),
                      slug: newJuryName.trim().toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/(^-|-$)/g, ''),
                    })
                  }}
                  disabled={createJuryMutation.isPending || !newJuryName.trim()}
                >
                  {createJuryMutation.isPending && <Loader2 className="h-4 w-4 mr-1.5 animate-spin" />}
                  Create
                </Button>
              </DialogFooter>
            </DialogContent>
          </Dialog>

          {/* Add Member Dialog */}
          {juryGroupId && (
            <AddMemberDialog
              juryGroupId={juryGroupId}
              open={addMemberOpen}
              onOpenChange={(open) => {
                setAddMemberOpen(open)
                if (!open) utils.juryGroup.getById.invalidate({ id: juryGroupId })
              }}
            />
          )}
        </TabsContent>
        )}

        {/* ═══════════ ASSIGNMENTS TAB (Evaluation rounds) ═══════════ */}
        {isEvaluation && (
          <TabsContent value="assignments" className="space-y-6">
            {/* 4.9 Gate assignments when no jury group */}
            {!round?.juryGroupId ? (
              <Card className="border-dashed">
                <CardContent className="flex flex-col items-center justify-center py-12 text-center">
                  <div className="rounded-full bg-amber-50 p-4 mb-4">
                    <Users className="h-8 w-8 text-amber-400" />
                  </div>
                  <p className="text-sm font-medium">No Jury Group Assigned</p>
                  <p className="text-xs text-muted-foreground mt-1 max-w-sm">
                    Assign a jury group first to manage assignments.
                  </p>
                  <Button size="sm" className="mt-4" onClick={() => setActiveTab('jury')}>
                    <Users className="h-4 w-4 mr-1.5" />
                    Go to Jury Tab
                  </Button>
                </CardContent>
              </Card>
            ) : (
            <>
            {/* Card 1: Coverage & Generation */}
            <Card>
              <CardHeader>
                <CardTitle className="text-base">Coverage & Generation</CardTitle>
                <CardDescription>Assignment coverage overview and AI generation</CardDescription>
              </CardHeader>
              <CardContent className="space-y-6">
                <CoverageReport roundId={roundId} requiredReviews={(config.requiredReviewsPerProject as number) || 3} />

                {/* Generate Assignments */}
                <div className={cn('rounded-lg border p-4 space-y-3', aiAssignmentMutation.isPending && 'border-violet-300 bg-violet-50/30')}>
                  <div className="flex items-center justify-between">
                    <div>
                      <p className="text-sm font-medium flex items-center gap-2">
                        Assignment Generation
                        {aiAssignmentMutation.isPending && (
                          <Badge variant="outline" className="gap-1.5 text-violet-600 border-violet-300 animate-pulse">
                            <Loader2 className="h-3 w-3 animate-spin" />
                            AI generating...
                          </Badge>
                        )}
                        {aiAssignmentMutation.data && !aiAssignmentMutation.isPending && (
                          <Badge variant="outline" className="gap-1 text-emerald-600 border-emerald-300">
                            <CheckCircle2 className="h-3 w-3" />
                            {aiAssignmentMutation.data.stats.assignmentsGenerated} ready
                          </Badge>
                        )}
                      </p>
                      <p className="text-xs text-muted-foreground mt-0.5">
                        AI-suggested jury-to-project assignments based on expertise and workload
                      </p>
                    </div>
                    <div className="flex items-center gap-2">
                      {aiAssignmentMutation.data && !aiAssignmentMutation.isPending && (
                        <Button
                          size="sm"
                          variant="outline"
                          onClick={() => setPreviewSheetOpen(true)}
                        >
                          Review Assignments
                        </Button>
                      )}
                      <Button
                        size="sm"
                        onClick={() => {
                          aiAssignmentMutation.mutate({
                            roundId,
                            requiredReviews: (config.requiredReviewsPerProject as number) || 3,
                          })
                        }}
                        disabled={projectCount === 0 || !juryGroup || aiAssignmentMutation.isPending}
                      >
                        {aiAssignmentMutation.isPending ? (
                          <>
                            <Loader2 className="h-4 w-4 mr-1.5 animate-spin" />
                            Generating...
                          </>
                        ) : (
                          <>
                            <Zap className="h-4 w-4 mr-1.5" />
                            {aiAssignmentMutation.data ? 'Regenerate' : 'Generate with AI'}
                          </>
                        )}
                      </Button>
                    </div>
                  </div>
                  {projectCount === 0 && (
                    <div className="flex items-center gap-2 p-3 rounded-lg bg-amber-50 border border-amber-200 text-sm text-amber-800">
                      <AlertTriangle className="h-4 w-4 shrink-0" />
                      Add projects to this round first.
                    </div>
                  )}
                  {juryGroup && projectCount > 0 && !aiAssignmentMutation.isPending && !aiAssignmentMutation.data && (
                    <p className="text-sm text-muted-foreground">
                      Click &quot;Generate with AI&quot; to create assignments using GPT analysis of juror expertise, project descriptions, and documents. Or open the preview to use the algorithm instead.
                    </p>
                  )}
                  {aiAssignmentMutation.isPending && (
                    <div className="flex items-center gap-3 p-3 rounded-lg bg-violet-50 border border-violet-200 dark:bg-violet-950/20 dark:border-violet-800">
                      <div className="relative">
                        <div className="h-8 w-8 rounded-full border-2 border-violet-300 border-t-violet-600 animate-spin" />
                      </div>
                      <div>
                        <p className="text-sm font-medium text-violet-800 dark:text-violet-200">AI is analyzing projects and jurors...</p>
                        <p className="text-xs text-violet-600 dark:text-violet-400">
                          Matching expertise, reviewing bios, and balancing workloads
                        </p>
                      </div>
                    </div>
                  )}
                  {aiAssignmentMutation.error && !aiAssignmentMutation.isPending && (
                    <div className="flex items-center gap-3 p-3 rounded-lg bg-red-50 border border-red-200 dark:bg-red-950/20 dark:border-red-800">
                      <AlertTriangle className="h-5 w-5 text-red-600 shrink-0" />
                      <div className="flex-1">
                        <p className="text-sm font-medium text-red-800 dark:text-red-200">
                          AI generation failed
                        </p>
                        <p className="text-xs text-red-600 dark:text-red-400">
                          {aiAssignmentMutation.error.message}
                        </p>
                      </div>
                    </div>
                  )}
                  {aiAssignmentMutation.data && !aiAssignmentMutation.isPending && (
                    <div className="flex items-center gap-3 p-3 rounded-lg bg-emerald-50 border border-emerald-200 dark:bg-emerald-950/20 dark:border-emerald-800">
                      <CheckCircle2 className="h-5 w-5 text-emerald-600 shrink-0" />
                      <div className="flex-1">
                        <p className="text-sm font-medium text-emerald-800 dark:text-emerald-200">
                          {aiAssignmentMutation.data.stats.assignmentsGenerated} assignments generated
                        </p>
                        <p className="text-xs text-emerald-600 dark:text-emerald-400">
                          {aiAssignmentMutation.data.stats.totalJurors} jurors, {aiAssignmentMutation.data.stats.totalProjects} projects
                          {aiAssignmentMutation.data.fallbackUsed && ' (algorithm fallback)'}
                        </p>
                      </div>
                      <Button size="sm" variant="outline" onClick={() => setPreviewSheetOpen(true)}>
                        Review &amp; Execute
                      </Button>
                    </div>
                  )}
                </div>
              </CardContent>
            </Card>

            {/* Jury Progress + Score Distribution (standalone 2-col grid) */}
            <div className="grid gap-4 lg:grid-cols-2">
              <JuryProgressTable roundId={roundId} />
              <ScoreDistribution roundId={roundId} />
            </div>

            {/* Card 2: Assignments — with action buttons in header */}
            <Card>
              <CardHeader>
                <div className="flex items-center justify-between">
                  <div>
                    <CardTitle className="text-base">Assignments</CardTitle>
                    <CardDescription>Individual jury-project assignments and actions</CardDescription>
                  </div>
                  <div className="flex flex-wrap items-center gap-2">
                    <SendRemindersButton roundId={roundId} />
                    <NotifyJurorsButton roundId={roundId} />
                    <Button variant="outline" size="sm" onClick={() => setExportOpen(true)}>
                      <Download className="h-4 w-4 mr-1.5" />
                      Export
                    </Button>
                  </div>
                </div>
              </CardHeader>
              <CardContent>
                <IndividualAssignmentsTable roundId={roundId} projectStates={projectStates} />
              </CardContent>
            </Card>

            {/* Card 3: Monitoring — COI + Unassigned Queue */}
            <Card>
              <CardHeader>
                <CardTitle className="text-base">Monitoring</CardTitle>
                <CardDescription>Conflict of interest declarations and unassigned projects</CardDescription>
              </CardHeader>
              <CardContent className="space-y-6">
                <COIReviewSection roundId={roundId} />
                <RoundUnassignedQueue roundId={roundId} requiredReviews={(config.requiredReviewsPerProject as number) || 3} />
              </CardContent>
            </Card>

            {/* Assignment Preview Sheet */}
            <AssignmentPreviewSheet
              roundId={roundId}
              open={previewSheetOpen}
              onOpenChange={setPreviewSheetOpen}
              requiredReviews={(config.requiredReviewsPerProject as number) || 3}
              aiResult={aiAssignmentMutation.data ?? null}
              isAIGenerating={aiAssignmentMutation.isPending}
              onGenerateAI={() => aiAssignmentMutation.mutate({
                roundId,
                requiredReviews: (config.requiredReviewsPerProject as number) || 3,
              })}
              onResetAI={() => aiAssignmentMutation.reset()}
            />

            {/* CSV Export Dialog */}
            <ExportEvaluationsDialog roundId={roundId} open={exportOpen} onOpenChange={setExportOpen} />
            </>
            )}
          </TabsContent>
        )}

        {/* ═══════════ CONFIG TAB ═══════════ */}
        <TabsContent value="config" className="space-y-6">
          {/* Round Dates */}
          <Card>
            <CardHeader className="border-b">
              <CardTitle className="text-base">Round Dates</CardTitle>
              <CardDescription>
                When this round starts and ends. Defines the active period for document uploads and evaluations.
              </CardDescription>
            </CardHeader>
            <CardContent className="pt-4">
              <div className="grid gap-4 sm:grid-cols-2">
                <div className="space-y-2">
                  <Label>Start Date</Label>
                  <DateTimePicker
                    value={round.windowOpenAt ? new Date(round.windowOpenAt) : null}
                    onChange={(date) => updateMutation.mutate({ id: roundId, windowOpenAt: date }, { onSuccess: () => toast.success('Dates saved') })}
                    placeholder="Select start date & time"
                    clearable
                  />
                </div>
                <div className="space-y-2">
                  <Label>End Date</Label>
                  <DateTimePicker
                    value={round.windowCloseAt ? new Date(round.windowCloseAt) : null}
                    onChange={(date) => updateMutation.mutate({ id: roundId, windowCloseAt: date }, { onSuccess: () => toast.success('Dates saved') })}
                    placeholder="Select end date & time"
                    clearable
                  />
                </div>
              </div>
            </CardContent>
          </Card>

          {/* General Round Settings */}
          <Card>
            <CardHeader className="border-b">
              <CardTitle className="text-base">General Settings</CardTitle>
              <CardDescription>Settings that apply to this round regardless of type</CardDescription>
            </CardHeader>
            <CardContent className="space-y-0 pt-0">
              <div className="flex items-center justify-between p-4 rounded-md">
                <div className="space-y-0.5">
                  <Label htmlFor="notify-on-entry" className="text-sm font-medium">
                    Notify on round entry
                  </Label>
                  <p className="text-xs text-muted-foreground">
                    Send an automated email to project applicants when their project enters this round
                  </p>
                </div>
                <Switch
                  id="notify-on-entry"
                  checked={!!config.notifyOnEntry}
                  onCheckedChange={(checked) => {
                    handleConfigChange({ ...config, notifyOnEntry: checked })
                  }}
                />
              </div>

              <div className="flex items-center justify-between p-4 rounded-md bg-muted/30">
                <div className="space-y-0.5">
                  <Label htmlFor="notify-on-advance" className="text-sm font-medium">
                    Notify on advance
                  </Label>
                  <p className="text-xs text-muted-foreground">
                    Send an email to project applicants when their project advances from this round to the next
                  </p>
                </div>
                <Switch
                  id="notify-on-advance"
                  checked={!!config.notifyOnAdvance}
                  onCheckedChange={(checked) => {
                    handleConfigChange({ ...config, notifyOnAdvance: checked })
                  }}
                />
              </div>

              <div className="border-t mt-2 pt-4 px-4 pb-2 bg-[#053d57]/[0.03] rounded-b-lg -mx-6 -mb-6 p-6">
                <Label className="text-sm font-medium">Advancement Targets</Label>
                <p className="text-xs text-muted-foreground mb-3">
                  Target number of projects per category to advance from this round
                </p>
                <div className="grid grid-cols-2 gap-4">
                  <div className="space-y-1.5">
                    <Label htmlFor="startup-advance-count" className="text-xs text-muted-foreground">
                      Startup Projects
                    </Label>
                    <Input
                      id="startup-advance-count"
                      type="number"
                      min={0}
                      className="h-9"
                      placeholder="No limit"
                      value={(config.startupAdvanceCount as number) ?? ''}
                      onChange={(e) => {
                        const val = e.target.value ? parseInt(e.target.value, 10) : undefined
                        handleConfigChange({ ...config, startupAdvanceCount: val })
                      }}
                    />
                  </div>
                  <div className="space-y-1.5">
                    <Label htmlFor="concept-advance-count" className="text-xs text-muted-foreground">
                      Concept Projects
                    </Label>
                    <Input
                      id="concept-advance-count"
                      type="number"
                      min={0}
                      className="h-9"
                      placeholder="No limit"
                      value={(config.conceptAdvanceCount as number) ?? ''}
                      onChange={(e) => {
                        const val = e.target.value ? parseInt(e.target.value, 10) : undefined
                        handleConfigChange({ ...config, conceptAdvanceCount: val })
                      }}
                    />
                  </div>
                </div>
              </div>
            </CardContent>
          </Card>

          {/* Round-type-specific config */}
          <RoundConfigForm
            roundType={round.roundType}
            config={config}
            onChange={handleConfigChange}
            juryGroups={juryGroups?.map((jg: any) => ({ id: jg.id, name: jg.name }))}
          />

          {/* Evaluation Criteria Editor (EVALUATION rounds only) */}
          {isEvaluation && <EvaluationCriteriaEditor roundId={roundId} />}

          {/* Document Requirements — hidden for EVALUATION rounds unless requireDocumentUpload is on */}
          {(!isEvaluation || !!(config.requireDocumentUpload as boolean)) && (
            <Card>
              <CardHeader>
                <CardTitle className="text-base">Document Requirements</CardTitle>
                <CardDescription>
                  Files applicants must submit for this round
                  {round.windowCloseAt && (
                    <> &mdash; due by {new Date(round.windowCloseAt).toLocaleDateString()}</>
                  )}
                </CardDescription>
              </CardHeader>
              <CardContent>
                <FileRequirementsEditor
                  roundId={roundId}
                  windowOpenAt={round.windowOpenAt}
                  windowCloseAt={round.windowCloseAt}
                />
              </CardContent>
            </Card>
          )}
        </TabsContent>

        {/* ═══════════ AWARDS TAB ═══════════ */}
        {hasAwards && (
        <TabsContent value="awards" className="space-y-4">
          <Card>
            <CardContent className="p-6">
              {roundAwards.length === 0 ? (
                <div className="text-center py-12 text-muted-foreground">
                  <div className="rounded-full bg-[#de0f1e]/10 p-4 w-fit mx-auto mb-4">
                    <Trophy className="h-8 w-8 text-[#de0f1e]/60" />
                  </div>
                  <p className="text-sm font-medium text-foreground">No Awards Linked</p>
                  <p className="text-xs mt-1 max-w-sm mx-auto">
                    Create an award and set this round as its evaluation round to see it here
                  </p>
                </div>
              ) : (
                <div className="space-y-3">
                  {roundAwards.map((award) => {
                    const eligibleCount = award._count?.eligibilities || 0

                    return (
                      <Link
                        key={award.id}
                        href={`/admin/awards/${award.id}` as Route}
                        className="block"
                      >
                        <div className="flex items-start justify-between gap-4 rounded-lg border border-l-4 border-l-[#de0f1e] p-4 transition-all hover:shadow-md hover:-translate-y-0.5">
                          <div className="flex-1 min-w-0">
                            <div className="flex items-center gap-2 mb-1">
                              <h3 className="font-medium truncate">{award.name}</h3>
                              <Badge
                                variant={
                                  award.eligibilityMode === 'SEPARATE_POOL'
                                    ? 'default'
                                    : 'secondary'
                                }
                                className="shrink-0"
                              >
                                {award.eligibilityMode === 'SEPARATE_POOL'
                                  ? 'Separate Pool'
                                  : 'Stay in Main'}
                              </Badge>
                            </div>
                            {award.description && (
                              <p className="text-sm text-muted-foreground line-clamp-1">
                                {award.description}
                              </p>
                            )}
                          </div>
                          <div className="flex items-center gap-4 text-sm text-muted-foreground shrink-0">
                            <div className="text-right">
                              <div className="font-medium text-foreground">{eligibleCount}</div>
                              <div className="text-xs">eligible</div>
                            </div>
                          </div>
                        </div>
                      </Link>
                    )
                  })}
                </div>
              )}
            </CardContent>
          </Card>
        </TabsContent>
        )}
      </Tabs>

      {/* Autosave error bar — only shows when save fails */}
      {autosaveStatus === 'error' && (
        <div className="fixed bottom-0 left-0 right-0 z-50 border-t bg-red-50 dark:bg-red-950/50 shadow-[0_-4px_12px_rgba(0,0,0,0.1)]">
          <div className="container flex items-center justify-between py-3 px-4 max-w-5xl mx-auto">
            <div className="flex items-center gap-2 text-sm text-red-700 dark:text-red-300">
              <AlertTriangle className="h-4 w-4" />
              <span>Auto-save failed</span>
            </div>
            <Button
              size="sm"
              onClick={saveConfig}
              disabled={updateMutation.isPending}
              className="bg-[#de0f1e] hover:bg-[#c00d1a] text-white"
            >
              {updateMutation.isPending ? (
                <><Loader2 className="h-3.5 w-3.5 mr-1.5 animate-spin" />Retrying...</>
              ) : (
                <><Save className="h-3.5 w-3.5 mr-1.5" />Retry Save</>
              )}
            </Button>
          </div>
        </div>
      )}
    </div>
  )
}

// ═══════════════════════════════════════════════════════════════════════════
// Sub-components
// ═══════════════════════════════════════════════════════════════════════════

// ── Inline cap editor for jury members on round page ─────────────────────

function InlineMemberCap({
  memberId,
  currentValue,
  onSave,
}: {
  memberId: string
  currentValue: number | null
  onSave: (val: number | null) => void
}) {
  const [editing, setEditing] = useState(false)
  const [value, setValue] = useState(currentValue?.toString() ?? '')
  const inputRef = useRef<HTMLInputElement>(null)

  useEffect(() => {
    if (editing) inputRef.current?.focus()
  }, [editing])

  const save = () => {
    const trimmed = value.trim()
    const newVal = trimmed === '' ? null : parseInt(trimmed, 10)
    if (newVal !== null && (isNaN(newVal) || newVal < 1)) {
      toast.error('Enter a positive number or leave empty for no cap')
      return
    }
    if (newVal === currentValue) {
      setEditing(false)
      return
    }
    onSave(newVal)
    setEditing(false)
  }

  if (editing) {
    return (
      <Input
        ref={inputRef}
        type="number"
        min={1}
        className="h-6 w-16 text-xs"
        value={value}
        placeholder="\u221E"
        onChange={(e) => setValue(e.target.value)}
        onBlur={save}
        onKeyDown={(e) => {
          if (e.key === 'Enter') save()
          if (e.key === 'Escape') { setValue(currentValue?.toString() ?? ''); setEditing(false) }
        }}
      />
    )
  }

  return (
    <button
      type="button"
      className="inline-flex items-center gap-1 rounded px-1.5 py-0.5 text-xs hover:bg-muted transition-colors group"
      title="Click to set max assignment cap"
      onClick={() => { setValue(currentValue?.toString() ?? ''); setEditing(true) }}
    >
      <span className="text-muted-foreground">max:</span>
      <span className="font-medium">{currentValue ?? '\u221E'}</span>
      <Pencil className="h-2.5 w-2.5 text-muted-foreground" />
    </button>
  )
}

// ── Unassigned projects queue ────────────────────────────────────────────

function RoundUnassignedQueue({ roundId, requiredReviews = 3 }: { roundId: string; requiredReviews?: number }) {
  const { data: unassigned, isLoading } = trpc.roundAssignment.unassignedQueue.useQuery(
    { roundId, requiredReviews },
    { refetchInterval: 15_000 },
  )

  return (
    <div className="space-y-3">
      <div>
        <p className="text-sm font-medium">Unassigned Projects</p>
        <p className="text-xs text-muted-foreground">Projects with fewer than {requiredReviews} jury assignments</p>
      </div>
      <div>
        {isLoading ? (
          <div className="space-y-2">
            {[1, 2, 3].map((i) => <Skeleton key={i} className="h-14 w-full" />)}
          </div>
        ) : unassigned && unassigned.length > 0 ? (
          <div className="space-y-2 max-h-[400px] overflow-y-auto">
            {unassigned.map((project: any) => (
              <div
                key={project.id}
                className={cn(
                  'flex justify-between items-center p-3 border rounded-md hover:bg-muted/30 transition-colors',
                  (project.assignmentCount || 0) === 0 && 'border-l-4 border-l-red-500',
                )}
              >
                <div className="min-w-0">
                  <p className="text-sm font-medium truncate">{project.title}</p>
                  <p className="text-xs text-muted-foreground">
                    {project.competitionCategory || 'No category'}
                    {project.teamName && ` \u00b7 ${project.teamName}`}
                  </p>
                </div>
                <Badge variant="outline" className={cn(
                  'text-xs shrink-0 ml-3',
                  (project.assignmentCount || 0) === 0
                    ? 'bg-red-50 text-red-700 border-red-200'
                    : 'bg-amber-50 text-amber-700 border-amber-200',
                )}>
                  {project.assignmentCount || 0} / {requiredReviews}
                </Badge>
              </div>
            ))}
          </div>
        ) : (
          <p className="text-sm text-muted-foreground text-center py-6">
            All projects have sufficient assignments
          </p>
        )}
      </div>
    </div>
  )
}

// ── Jury Progress Table ──────────────────────────────────────────────────

function JuryProgressTable({ roundId }: { roundId: string }) {
  const utils = trpc.useUtils()
  const { data: workload, isLoading } = trpc.analytics.getJurorWorkload.useQuery(
    { roundId },
    { refetchInterval: 15_000 },
  )

  const notifyMutation = trpc.assignment.notifySingleJurorOfAssignments.useMutation({
    onSuccess: (data) => {
      toast.success(`Notified juror of ${data.projectCount} assignment(s)`)
    },
    onError: (err) => toast.error(err.message),
  })

  const reshuffleMutation = trpc.assignment.reassignDroppedJuror.useMutation({
    onSuccess: (data) => {
      utils.assignment.listByStage.invalidate({ roundId })
      utils.roundEngine.getProjectStates.invalidate({ roundId })
      utils.analytics.getJurorWorkload.invalidate({ roundId })

      if (data.failedCount > 0) {
        toast.warning(`Reassigned ${data.movedCount} project(s). ${data.failedCount} could not be reassigned (all remaining jurors at cap/blocked).`)
      } else {
        toast.success(`Reassigned ${data.movedCount} project(s) evenly across available jurors.`)
      }
    },
    onError: (err) => toast.error(err.message),
  })

  return (
    <Card>
      <CardHeader>
        <CardTitle className="text-base">Jury Progress</CardTitle>
        <CardDescription>Evaluation completion per juror. Click the mail icon to notify an individual juror.</CardDescription>
      </CardHeader>
      <CardContent>
        {isLoading ? (
          <div className="space-y-3">
            {[1, 2, 3].map((i) => <Skeleton key={i} className="h-10 w-full" />)}
          </div>
        ) : !workload || workload.length === 0 ? (
          <p className="text-sm text-muted-foreground text-center py-6">
            No assignments yet
          </p>
        ) : (
          <div className="space-y-3 max-h-[350px] overflow-y-auto">
            {workload.map((juror) => {
              const pct = juror.completionRate
              const barGradient = pct === 100
                ? 'bg-gradient-to-r from-emerald-400 to-emerald-600'
                : pct >= 50
                  ? 'bg-gradient-to-r from-blue-400 to-blue-600'
                  : pct > 0
                    ? 'bg-gradient-to-r from-amber-400 to-amber-600'
                    : 'bg-gray-300'

              return (
                <div key={juror.id} className="space-y-1 hover:bg-muted/20 rounded px-1 py-0.5 -mx-1 transition-colors group">
                  <div className="flex justify-between items-center text-xs">
                    <span className="font-medium truncate max-w-[50%]">{juror.name}</span>
                    <div className="flex items-center gap-2 shrink-0">
                      <span className="text-muted-foreground tabular-nums">
                        {juror.completed}/{juror.assigned} ({pct}%)
                      </span>
                      <TooltipProvider delayDuration={200}>
                        <Tooltip>
                          <TooltipTrigger asChild>
                            <Button
                              variant="ghost"
                              size="icon"
                              className="h-5 w-5 text-muted-foreground hover:text-foreground"
                              disabled={notifyMutation.isPending}
                              onClick={() => notifyMutation.mutate({ roundId, userId: juror.id })}
                            >
                              {notifyMutation.isPending && notifyMutation.variables?.userId === juror.id ? (
                                <Loader2 className="h-3 w-3 animate-spin" />
                              ) : (
                                <Mail className="h-3 w-3" />
                              )}
                            </Button>
                          </TooltipTrigger>
                          <TooltipContent side="left"><p>Notify this juror of their assignments</p></TooltipContent>
                        </Tooltip>
                      </TooltipProvider>

                      <TooltipProvider delayDuration={200}>
                        <Tooltip>
                          <TooltipTrigger asChild>
                            <Button
                              variant="ghost"
                              size="icon"
                              className="h-5 w-5 text-muted-foreground hover:text-destructive"
                              disabled={reshuffleMutation.isPending}
                              onClick={() => {
                                const ok = window.confirm(
                                  `Reassign all pending/draft projects from ${juror.name} to other jurors within their caps? This cannot be undone.`
                                )
                                if (!ok) return
                                reshuffleMutation.mutate({ roundId, jurorId: juror.id })
                              }}
                            >
                              {reshuffleMutation.isPending && reshuffleMutation.variables?.jurorId === juror.id ? (
                                <Loader2 className="h-3 w-3 animate-spin" />
                              ) : (
                                <UserPlus className="h-3 w-3" />
                              )}
                            </Button>
                          </TooltipTrigger>
                          <TooltipContent side="left"><p>Drop juror + reshuffle pending projects</p></TooltipContent>
                        </Tooltip>
                      </TooltipProvider>
                    </div>
                  </div>
                  <div className="h-2 bg-muted rounded-full overflow-hidden">
                    <div
                      className={cn('h-full rounded-full transition-all duration-500', barGradient)}
                      style={{ width: `${pct}%` }}
                    />
                  </div>
                </div>
              )
            })}
          </div>
        )}
      </CardContent>
    </Card>
  )
}

// ── Score Distribution ───────────────────────────────────────────────────

function ScoreDistribution({ roundId }: { roundId: string }) {
  const { data: dist, isLoading } = trpc.analytics.getRoundScoreDistribution.useQuery(
    { roundId },
    { refetchInterval: 15_000 },
  )

  const maxCount = useMemo(() =>
    dist ? Math.max(...dist.globalDistribution.map((b) => b.count), 1) : 1,
  [dist])

  return (
    <Card>
      <CardHeader>
        <CardTitle className="text-base">Score Distribution</CardTitle>
        <CardDescription>
          {dist ? `${dist.totalEvaluations} evaluations \u2014 avg ${dist.averageGlobalScore.toFixed(1)}` : 'Loading...'}
        </CardDescription>
      </CardHeader>
      <CardContent>
        {isLoading ? (
          <div className="flex items-end gap-1 h-32">
            {Array.from({ length: 10 }).map((_, i) => <Skeleton key={i} className="flex-1 h-full" />)}
          </div>
        ) : !dist || dist.totalEvaluations === 0 ? (
          <p className="text-sm text-muted-foreground text-center py-6">
            No evaluations submitted yet
          </p>
        ) : (
          <div className="flex items-end gap-1 h-32">
            {dist.globalDistribution.map((bucket) => {
              const heightPct = (bucket.count / maxCount) * 100
              return (
                <div key={bucket.score} className="flex-1 flex flex-col items-center gap-1">
                  <span className="text-[9px] text-muted-foreground">{bucket.count || ''}</span>
                  <div className="w-full relative rounded-t" style={{ height: `${Math.max(heightPct, 2)}%` }}>
                    <div className={cn(
                      'absolute inset-0 rounded-t transition-all',
                      bucket.score <= 3 ? 'bg-red-400' :
                      bucket.score <= 6 ? 'bg-amber-400' :
                      'bg-emerald-400',
                    )} />
                  </div>
                  <span className="text-[10px] text-muted-foreground">{bucket.score}</span>
                </div>
              )
            })}
          </div>
        )}
      </CardContent>
    </Card>
  )
}

// ── Send Reminders Button ────────────────────────────────────────────────

function SendRemindersButton({ roundId }: { roundId: string }) {
  const [open, setOpen] = useState(false)
  const mutation = trpc.evaluation.triggerReminders.useMutation({
    onSuccess: (data) => {
      toast.success(`Sent ${data.sent} reminder(s)`)
      setOpen(false)
    },
    onError: (err) => toast.error(err.message),
  })

  return (
    <>
      <Button variant="outline" size="sm" onClick={() => setOpen(true)}>
        <Send className="h-4 w-4 mr-1.5" />
        Send Reminders
      </Button>
      <AlertDialog open={open} onOpenChange={setOpen}>
        <AlertDialogContent>
          <AlertDialogHeader>
            <AlertDialogTitle>Send evaluation reminders?</AlertDialogTitle>
            <AlertDialogDescription>
              This will send reminder emails to all jurors who have incomplete evaluations for this round.
            </AlertDialogDescription>
          </AlertDialogHeader>
          <AlertDialogFooter>
            <AlertDialogCancel>Cancel</AlertDialogCancel>
            <AlertDialogAction
              onClick={() => mutation.mutate({ roundId })}
              disabled={mutation.isPending}
            >
              {mutation.isPending && <Loader2 className="h-4 w-4 mr-1.5 animate-spin" />}
              Send Reminders
            </AlertDialogAction>
          </AlertDialogFooter>
        </AlertDialogContent>
      </AlertDialog>
    </>
  )
}

// ── Notify Jurors of Assignments Button ──────────────────────────────────

function NotifyJurorsButton({ roundId }: { roundId: string }) {
  const [open, setOpen] = useState(false)
  const mutation = trpc.assignment.notifyJurorsOfAssignments.useMutation({
    onSuccess: (data) => {
      toast.success(`Notified ${data.jurorCount} juror(s) of their assignments`)
      setOpen(false)
    },
    onError: (err) => toast.error(err.message),
  })

  return (
    <>
      <Button variant="outline" size="sm" onClick={() => setOpen(true)}>
        <Mail className="h-4 w-4 mr-1.5" />
        Notify Jurors
      </Button>
      <AlertDialog open={open} onOpenChange={setOpen}>
        <AlertDialogContent>
          <AlertDialogHeader>
            <AlertDialogTitle>Notify jurors of their assignments?</AlertDialogTitle>
            <AlertDialogDescription>
              This will send an email to every juror assigned to this round, reminding them of how many projects they need to evaluate.
            </AlertDialogDescription>
          </AlertDialogHeader>
          <AlertDialogFooter>
            <AlertDialogCancel>Cancel</AlertDialogCancel>
            <AlertDialogAction
              onClick={() => mutation.mutate({ roundId })}
              disabled={mutation.isPending}
            >
              {mutation.isPending && <Loader2 className="h-4 w-4 mr-1.5 animate-spin" />}
              Notify Jurors
            </AlertDialogAction>
          </AlertDialogFooter>
        </AlertDialogContent>
      </AlertDialog>
    </>
  )
}

// ── Export Evaluations Dialog ─────────────────────────────────────────────

function ExportEvaluationsDialog({
  roundId,
  open,
  onOpenChange,
}: {
  roundId: string
  open: boolean
  onOpenChange: (open: boolean) => void
}) {
  const [exportData, setExportData] = useState<any>(undefined)
  const [isLoadingExport, setIsLoadingExport] = useState(false)
  const utils = trpc.useUtils()

  const handleRequestData = async () => {
    setIsLoadingExport(true)
    try {
      const data = await utils.export.evaluations.fetch({ roundId, includeDetails: true })
      setExportData(data)
      return data
    } finally {
      setIsLoadingExport(false)
    }
  }

  return (
    <CsvExportDialog
      open={open}
      onOpenChange={onOpenChange}
      exportData={exportData}
      isLoading={isLoadingExport}
      filename={`evaluations-${roundId}`}
      onRequestData={handleRequestData}
    />
  )
}

// ── Individual Assignments Table ─────────────────────────────────────────

function IndividualAssignmentsTable({
  roundId,
  projectStates,
}: {
  roundId: string
  projectStates: any[] | undefined
}) {
  const [addDialogOpen, setAddDialogOpen] = useState(false)
  const [confirmAction, setConfirmAction] = useState<{ type: 'reset' | 'delete'; assignment: any } | null>(null)
  const [assignMode, setAssignMode] = useState<'byJuror' | 'byProject'>('byJuror')
  // ── By Juror mode state ──
  const [selectedJurorId, setSelectedJurorId] = useState('')
  const [selectedProjectIds, setSelectedProjectIds] = useState<Set<string>>(new Set())
  const [jurorPopoverOpen, setJurorPopoverOpen] = useState(false)
  const [projectSearch, setProjectSearch] = useState('')
  // ── By Project mode state ──
  const [selectedProjectId, setSelectedProjectId] = useState('')
  const [selectedJurorIds, setSelectedJurorIds] = useState<Set<string>>(new Set())
  const [projectPopoverOpen, setProjectPopoverOpen] = useState(false)
  const [jurorSearch, setJurorSearch] = useState('')

  const utils = trpc.useUtils()
  const { data: assignments, isLoading } = trpc.assignment.listByStage.useQuery(
    { roundId },
    { refetchInterval: 15_000 },
  )

  const { data: juryMembers } = trpc.user.getJuryMembers.useQuery(
    { roundId },
    { enabled: addDialogOpen },
  )

  const deleteMutation = trpc.assignment.delete.useMutation({
    onSuccess: () => {
      utils.assignment.listByStage.invalidate({ roundId })
      utils.roundEngine.getProjectStates.invalidate({ roundId })
      toast.success('Assignment removed')
    },
    onError: (err) => toast.error(err.message),
  })

  const resetEvalMutation = trpc.evaluation.resetEvaluation.useMutation({
    onSuccess: () => {
      utils.assignment.listByStage.invalidate({ roundId })
      toast.success('Evaluation reset — juror can now start over')
    },
    onError: (err) => toast.error(err.message),
  })

  const reassignCOIMutation = trpc.assignment.reassignCOI.useMutation({
    onSuccess: (data) => {
      utils.assignment.listByStage.invalidate({ roundId })
      utils.roundEngine.getProjectStates.invalidate({ roundId })
      utils.analytics.getJurorWorkload.invalidate({ roundId })
      utils.evaluation.listCOIByStage.invalidate({ roundId })
      toast.success(`Reassigned to ${data.newJurorName}`)
    },
    onError: (err) => toast.error(err.message),
  })

  const createMutation = trpc.assignment.create.useMutation({
    onSuccess: () => {
      utils.assignment.listByStage.invalidate({ roundId })
      utils.roundEngine.getProjectStates.invalidate({ roundId })
      utils.user.getJuryMembers.invalidate({ roundId })
      toast.success('Assignment created')
      resetDialog()
    },
    onError: (err) => toast.error(err.message),
  })

  const bulkCreateMutation = trpc.assignment.bulkCreate.useMutation({
    onSuccess: (result) => {
      utils.assignment.listByStage.invalidate({ roundId })
      utils.roundEngine.getProjectStates.invalidate({ roundId })
      utils.user.getJuryMembers.invalidate({ roundId })
      toast.success(`${result.created} assignment(s) created`)
      resetDialog()
    },
    onError: (err) => toast.error(err.message),
  })

  const resetDialog = useCallback(() => {
    setAddDialogOpen(false)
    setAssignMode('byJuror')
    setSelectedJurorId('')
    setSelectedProjectIds(new Set())
    setProjectSearch('')
    setSelectedProjectId('')
    setSelectedJurorIds(new Set())
    setJurorSearch('')
  }, [])

  const selectedJuror = useMemo(
    () => juryMembers?.find((j: any) => j.id === selectedJurorId),
    [juryMembers, selectedJurorId],
  )

  // Filter projects by search term
  const filteredProjects = useMemo(() => {
    const items = projectStates ?? []
    if (!projectSearch) return items
    const q = projectSearch.toLowerCase()
    return items.filter((ps: any) =>
      ps.project?.title?.toLowerCase().includes(q) ||
      ps.project?.teamName?.toLowerCase().includes(q) ||
      ps.project?.competitionCategory?.toLowerCase().includes(q)
    )
  }, [projectStates, projectSearch])

  // Existing assignments for the selected juror (to grey out already-assigned projects)
  const jurorExistingProjectIds = useMemo(() => {
    if (!selectedJurorId || !assignments) return new Set<string>()
    return new Set(
      assignments
        .filter((a: any) => a.userId === selectedJurorId)
        .map((a: any) => a.projectId)
    )
  }, [selectedJurorId, assignments])

  const toggleProject = useCallback((projectId: string) => {
    setSelectedProjectIds(prev => {
      const next = new Set(prev)
      if (next.has(projectId)) {
        next.delete(projectId)
      } else {
        next.add(projectId)
      }
      return next
    })
  }, [])

  const selectAllUnassigned = useCallback(() => {
    const unassigned = filteredProjects
      .filter((ps: any) => !jurorExistingProjectIds.has(ps.project?.id))
      .map((ps: any) => ps.project?.id)
      .filter(Boolean)
    setSelectedProjectIds(new Set(unassigned))
  }, [filteredProjects, jurorExistingProjectIds])

  const handleCreate = useCallback(() => {
    if (!selectedJurorId || selectedProjectIds.size === 0) return

    const projectIds = Array.from(selectedProjectIds)
    if (projectIds.length === 1) {
      createMutation.mutate({
        userId: selectedJurorId,
        projectId: projectIds[0],
        roundId,
      })
    } else {
      bulkCreateMutation.mutate({
        roundId,
        assignments: projectIds.map(projectId => ({
          userId: selectedJurorId,
          projectId,
        })),
      })
    }
  }, [selectedJurorId, selectedProjectIds, roundId, createMutation, bulkCreateMutation])

  const isMutating = createMutation.isPending || bulkCreateMutation.isPending

  // ── By Project mode helpers ──

  // Existing assignments for the selected project (to grey out already-assigned jurors)
  const projectExistingJurorIds = useMemo(() => {
    if (!selectedProjectId || !assignments) return new Set<string>()
    return new Set(
      assignments
        .filter((a: any) => a.projectId === selectedProjectId)
        .map((a: any) => a.userId)
    )
  }, [selectedProjectId, assignments])

  // Count assignments per juror in this round (for display)
  const jurorAssignmentCounts = useMemo(() => {
    if (!assignments) return new Map<string, number>()
    const counts = new Map<string, number>()
    for (const a of assignments) {
      counts.set(a.userId, (counts.get(a.userId) || 0) + 1)
    }
    return counts
  }, [assignments])

  // Filter jurors by search term
  const filteredJurors = useMemo(() => {
    const items = juryMembers ?? []
    if (!jurorSearch) return items
    const q = jurorSearch.toLowerCase()
    return items.filter((j: any) =>
      j.name?.toLowerCase().includes(q) ||
      j.email?.toLowerCase().includes(q)
    )
  }, [juryMembers, jurorSearch])

  const toggleJuror = useCallback((jurorId: string) => {
    setSelectedJurorIds(prev => {
      const next = new Set(prev)
      if (next.has(jurorId)) next.delete(jurorId)
      else next.add(jurorId)
      return next
    })
  }, [])

  const handleCreateByProject = useCallback(() => {
    if (!selectedProjectId || selectedJurorIds.size === 0) return

    const jurorIds = Array.from(selectedJurorIds)
    if (jurorIds.length === 1) {
      createMutation.mutate({
        userId: jurorIds[0],
        projectId: selectedProjectId,
        roundId,
      })
    } else {
      bulkCreateMutation.mutate({
        roundId,
        assignments: jurorIds.map(userId => ({
          userId,
          projectId: selectedProjectId,
        })),
      })
    }
  }, [selectedProjectId, selectedJurorIds, roundId, createMutation, bulkCreateMutation])

  return (
    <div className="space-y-4">
      <div className="flex items-center justify-between">
        <div>
          <p className="text-sm font-medium">{assignments?.length ?? 0} individual assignments</p>
        </div>
        <Button size="sm" variant="outline" onClick={() => setAddDialogOpen(true)}>
          <Plus className="h-4 w-4 mr-1.5" />
          Add
        </Button>
      </div>
      <div>
        {isLoading ? (
          <div className="space-y-2">
            {[1, 2, 3, 4, 5].map((i) => <Skeleton key={i} className="h-12 w-full" />)}
          </div>
        ) : !assignments || assignments.length === 0 ? (
          <p className="text-sm text-muted-foreground text-center py-6">
            No assignments yet. Generate assignments or add one manually.
          </p>
        ) : (
          <div className="space-y-1 max-h-[500px] overflow-y-auto">
            <div className="grid grid-cols-[1fr_1fr_100px_70px] gap-2 text-xs text-muted-foreground font-medium px-3 py-2 sticky top-0 bg-background border-b">
              <span>Juror</span>
              <span>Project</span>
              <span>Status</span>
              <span>Actions</span>
            </div>
            {assignments.map((a: any, idx: number) => (
              <div
                key={a.id}
                className={cn(
                  'grid grid-cols-[1fr_1fr_100px_70px] gap-2 items-center px-3 py-2 rounded-md text-sm transition-colors',
                  idx % 2 === 1 ? 'bg-muted/20' : 'hover:bg-muted/20',
                )}
              >
                <span className="truncate">{a.user?.name || a.user?.email || 'Unknown'}</span>
                <span className="truncate text-muted-foreground">{a.project?.title || 'Unknown'}</span>
                <div className="flex items-center gap-1">
                  {a.conflictOfInterest?.hasConflict ? (
                    <Badge variant="outline" className="text-[10px] justify-center bg-red-50 text-red-700 border-red-200">
                      COI
                    </Badge>
                  ) : (
                    <Badge
                      variant="outline"
                      className={cn(
                        'text-[10px] justify-center',
                        a.evaluation?.status === 'SUBMITTED'
                          ? 'bg-emerald-50 text-emerald-700 border-emerald-200'
                          : a.evaluation?.status === 'DRAFT'
                            ? 'bg-blue-50 text-blue-700 border-blue-200'
                            : 'bg-gray-50 text-gray-600 border-gray-200',
                      )}
                    >
                      {a.evaluation?.status || 'PENDING'}
                    </Badge>
                  )}
                </div>
                <DropdownMenu>
                  <DropdownMenuTrigger asChild>
                    <Button variant="ghost" size="icon" className="h-7 w-7">
                      <MoreHorizontal className="h-3.5 w-3.5 text-muted-foreground" />
                    </Button>
                  </DropdownMenuTrigger>
                  <DropdownMenuContent align="end">
                    {a.conflictOfInterest?.hasConflict && (
                      <>
                        <DropdownMenuItem
                          onClick={() => reassignCOIMutation.mutate({ assignmentId: a.id })}
                          disabled={reassignCOIMutation.isPending}
                        >
                          <UserPlus className="h-3.5 w-3.5 mr-2 text-blue-600" />
                          Reassign (COI)
                        </DropdownMenuItem>
                        <DropdownMenuSeparator />
                      </>
                    )}
                    {a.evaluation && (
                      <>
                        <DropdownMenuItem
                          onClick={() => setConfirmAction({ type: 'reset', assignment: a })}
                          disabled={resetEvalMutation.isPending}
                        >
                          <RotateCcw className="h-3.5 w-3.5 mr-2" />
                          Reset Evaluation
                        </DropdownMenuItem>
                        <DropdownMenuSeparator />
                      </>
                    )}
                    <DropdownMenuItem
                      className="text-destructive focus:text-destructive"
                      onClick={() => setConfirmAction({ type: 'delete', assignment: a })}
                      disabled={deleteMutation.isPending}
                    >
                      <Trash2 className="h-3.5 w-3.5 mr-2" />
                      Delete Assignment
                    </DropdownMenuItem>
                  </DropdownMenuContent>
                </DropdownMenu>
              </div>
            ))}
          </div>
        )}
      </div>

      {/* Add Assignment Dialog */}
      <Dialog open={addDialogOpen} onOpenChange={(open) => {
        if (!open) resetDialog()
        else setAddDialogOpen(true)
      }}>
        <DialogContent className="max-w-3xl">
          <DialogHeader>
            <DialogTitle>Add Assignment</DialogTitle>
            <DialogDescription>
              {assignMode === 'byJuror'
                ? 'Select a juror, then choose projects to assign'
                : 'Select a project, then choose jurors to assign'
              }
            </DialogDescription>
          </DialogHeader>

          {/* Mode Toggle */}
          <Tabs value={assignMode} onValueChange={(v) => {
            setAssignMode(v as 'byJuror' | 'byProject')
            // Reset selections when switching
            setSelectedJurorId('')
            setSelectedProjectIds(new Set())
            setProjectSearch('')
            setSelectedProjectId('')
            setSelectedJurorIds(new Set())
            setJurorSearch('')
          }}>
            <TabsList className="grid w-full grid-cols-2">
              <TabsTrigger value="byJuror">By Juror</TabsTrigger>
              <TabsTrigger value="byProject">By Project</TabsTrigger>
            </TabsList>

            {/* ── By Juror Tab ── */}
            <TabsContent value="byJuror" className="space-y-4 mt-4">
              {/* Juror Selector */}
              <div className="space-y-2">
                <Label className="text-sm font-medium">Juror</Label>
                <Popover open={jurorPopoverOpen} onOpenChange={setJurorPopoverOpen}>
                  <PopoverTrigger asChild>
                    <Button
                      variant="outline"
                      role="combobox"
                      aria-expanded={jurorPopoverOpen}
                      className="w-full justify-between font-normal"
                    >
                      {selectedJuror
                        ? (
                          <span className="flex items-center gap-2 truncate">
                            <span className="truncate">{selectedJuror.name || selectedJuror.email}</span>
                            <Badge variant="secondary" className="text-[10px] shrink-0">
                              {selectedJuror.currentAssignments}/{selectedJuror.maxAssignments ?? '\u221E'}
                            </Badge>
                          </span>
                        )
                        : <span className="text-muted-foreground">Select a jury member...</span>
                      }
                      <ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
                    </Button>
                  </PopoverTrigger>
                  <PopoverContent className="w-[var(--radix-popover-trigger-width)] p-0" align="start">
                    <Command>
                      <CommandInput placeholder="Search by name or email..." />
                      <CommandList>
                        <CommandEmpty>No jury members found.</CommandEmpty>
                        <CommandGroup>
                          {juryMembers?.map((juror: any) => {
                            const atCapacity = juror.maxAssignments !== null && juror.availableSlots === 0
                            return (
                              <CommandItem
                                key={juror.id}
                                value={`${juror.name ?? ''} ${juror.email}`}
                                disabled={atCapacity}
                                onSelect={() => {
                                  setSelectedJurorId(juror.id === selectedJurorId ? '' : juror.id)
                                  setSelectedProjectIds(new Set())
                                  setJurorPopoverOpen(false)
                                }}
                              >
                                <Check
                                  className={cn(
                                    'mr-2 h-4 w-4',
                                    selectedJurorId === juror.id ? 'opacity-100' : 'opacity-0',
                                  )}
                                />
                                <div className="flex flex-1 items-center justify-between min-w-0">
                                  <div className="min-w-0">
                                    <p className="text-sm font-medium truncate">
                                      {juror.name || 'Unnamed'}
                                    </p>
                                    <p className="text-xs text-muted-foreground truncate">
                                      {juror.email}
                                    </p>
                                  </div>
                                  <Badge
                                    variant={atCapacity ? 'destructive' : 'secondary'}
                                    className="text-[10px] ml-2 shrink-0"
                                  >
                                    {juror.currentAssignments}/{juror.maxAssignments ?? '\u221E'}
                                    {atCapacity ? ' full' : ''}
                                  </Badge>
                                </div>
                              </CommandItem>
                            )
                          })}
                        </CommandGroup>
                      </CommandList>
                    </Command>
                  </PopoverContent>
                </Popover>
              </div>

              {/* Project Multi-Select */}
              <div className="space-y-2">
                <div className="flex items-center justify-between">
                  <Label className="text-sm font-medium">
                    Projects
                    {selectedProjectIds.size > 0 && (
                      <span className="ml-1.5 text-muted-foreground font-normal">
                        ({selectedProjectIds.size} selected)
                      </span>
                    )}
                  </Label>
                  {selectedJurorId && (
                    <div className="flex items-center gap-2">
                      <Button
                        type="button"
                        variant="ghost"
                        size="sm"
                        className="h-7 text-xs"
                        onClick={selectAllUnassigned}
                      >
                        Select all
                      </Button>
                      {selectedProjectIds.size > 0 && (
                        <Button
                          type="button"
                          variant="ghost"
                          size="sm"
                          className="h-7 text-xs"
                          onClick={() => setSelectedProjectIds(new Set())}
                        >
                          Clear
                        </Button>
                      )}
                    </div>
                  )}
                </div>

                {/* Search input */}
                <div className="relative">
                  <Search className="absolute left-2.5 top-2.5 h-4 w-4 text-muted-foreground" />
                  <Input
                    placeholder="Filter projects..."
                    value={projectSearch}
                    onChange={(e) => setProjectSearch(e.target.value)}
                    className="pl-9 h-9"
                  />
                </div>

                {/* Project checklist */}
                <ScrollArea className="h-[320px] rounded-md border">
                  <div className="p-2 space-y-0.5">
                    {!selectedJurorId ? (
                      <p className="text-sm text-muted-foreground text-center py-8">
                        Select a juror first
                      </p>
                    ) : filteredProjects.length === 0 ? (
                      <p className="text-sm text-muted-foreground text-center py-8">
                        No projects found
                      </p>
                    ) : (
                      filteredProjects.map((ps: any) => {
                        const project = ps.project
                        if (!project) return null
                        const alreadyAssigned = jurorExistingProjectIds.has(project.id)
                        const isSelected = selectedProjectIds.has(project.id)

                        return (
                          <label
                            key={project.id}
                            className={cn(
                              'flex items-center gap-3 rounded-md px-2.5 py-2 text-sm cursor-pointer transition-colors',
                              alreadyAssigned
                                ? 'opacity-50 cursor-not-allowed'
                                : isSelected
                                  ? 'bg-accent'
                                  : 'hover:bg-muted/50',
                            )}
                          >
                            <Checkbox
                              checked={isSelected}
                              disabled={alreadyAssigned}
                              onCheckedChange={() => toggleProject(project.id)}
                            />
                            <div className="flex flex-1 items-center justify-between min-w-0">
                              <span className="truncate">{project.title}</span>
                              <div className="flex items-center gap-1.5 shrink-0 ml-2">
                                {project.competitionCategory && (
                                  <Badge variant="outline" className="text-[10px]">
                                    {project.competitionCategory === 'STARTUP'
                                      ? 'Startup'
                                      : project.competitionCategory === 'BUSINESS_CONCEPT'
                                        ? 'Concept'
                                        : project.competitionCategory}
                                  </Badge>
                                )}
                                {alreadyAssigned && (
                                  <Badge variant="secondary" className="text-[10px]">
                                    Assigned
                                  </Badge>
                                )}
                              </div>
                            </div>
                          </label>
                        )
                      })
                    )}
                  </div>
                </ScrollArea>
              </div>

              <DialogFooter>
                <Button variant="outline" onClick={resetDialog}>
                  Cancel
                </Button>
                <Button
                  onClick={handleCreate}
                  disabled={!selectedJurorId || selectedProjectIds.size === 0 || isMutating}
                >
                  {isMutating && <Loader2 className="h-4 w-4 mr-1.5 animate-spin" />}
                  {selectedProjectIds.size <= 1
                    ? 'Create Assignment'
                    : `Create ${selectedProjectIds.size} Assignments`
                  }
                </Button>
              </DialogFooter>
            </TabsContent>

            {/* ── By Project Tab ── */}
            <TabsContent value="byProject" className="space-y-4 mt-4">
              {/* Project Selector */}
              <div className="space-y-2">
                <Label className="text-sm font-medium">Project</Label>
                <Popover open={projectPopoverOpen} onOpenChange={setProjectPopoverOpen}>
                  <PopoverTrigger asChild>
                    <Button
                      variant="outline"
                      role="combobox"
                      aria-expanded={projectPopoverOpen}
                      className="w-full justify-between font-normal"
                    >
                      {selectedProjectId
                        ? (
                          <span className="truncate">
                            {(projectStates ?? []).find((ps: any) => ps.project?.id === selectedProjectId)?.project?.title || 'Unknown'}
                          </span>
                        )
                        : <span className="text-muted-foreground">Select a project...</span>
                      }
                      <ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
                    </Button>
                  </PopoverTrigger>
                  <PopoverContent className="w-[var(--radix-popover-trigger-width)] p-0" align="start">
                    <Command>
                      <CommandInput placeholder="Search by project title..." />
                      <CommandList>
                        <CommandEmpty>No projects found.</CommandEmpty>
                        <CommandGroup>
                          {(projectStates ?? []).map((ps: any) => {
                            const project = ps.project
                            if (!project) return null
                            return (
                              <CommandItem
                                key={project.id}
                                value={`${project.title ?? ''} ${project.teamName ?? ''}`}
                                onSelect={() => {
                                  setSelectedProjectId(project.id === selectedProjectId ? '' : project.id)
                                  setSelectedJurorIds(new Set())
                                  setProjectPopoverOpen(false)
                                }}
                              >
                                <Check
                                  className={cn(
                                    'mr-2 h-4 w-4',
                                    selectedProjectId === project.id ? 'opacity-100' : 'opacity-0',
                                  )}
                                />
                                <div className="flex flex-1 items-center justify-between min-w-0">
                                  <div className="min-w-0">
                                    <p className="text-sm font-medium truncate">{project.title}</p>
                                    <p className="text-xs text-muted-foreground truncate">{project.teamName}</p>
                                  </div>
                                  {project.competitionCategory && (
                                    <Badge variant="outline" className="text-[10px] ml-2 shrink-0">
                                      {project.competitionCategory === 'STARTUP' ? 'Startup' : 'Concept'}
                                    </Badge>
                                  )}
                                </div>
                              </CommandItem>
                            )
                          })}
                        </CommandGroup>
                      </CommandList>
                    </Command>
                  </PopoverContent>
                </Popover>
              </div>

              {/* Juror Multi-Select */}
              <div className="space-y-2">
                <div className="flex items-center justify-between">
                  <Label className="text-sm font-medium">
                    Jurors
                    {selectedJurorIds.size > 0 && (
                      <span className="ml-1.5 text-muted-foreground font-normal">
                        ({selectedJurorIds.size} selected)
                      </span>
                    )}
                  </Label>
                  {selectedProjectId && selectedJurorIds.size > 0 && (
                    <Button
                      type="button"
                      variant="ghost"
                      size="sm"
                      className="h-7 text-xs"
                      onClick={() => setSelectedJurorIds(new Set())}
                    >
                      Clear
                    </Button>
                  )}
                </div>

                {/* Search input */}
                <div className="relative">
                  <Search className="absolute left-2.5 top-2.5 h-4 w-4 text-muted-foreground" />
                  <Input
                    placeholder="Filter jurors..."
                    value={jurorSearch}
                    onChange={(e) => setJurorSearch(e.target.value)}
                    className="pl-9 h-9"
                  />
                </div>

                {/* Juror checklist */}
                <ScrollArea className="h-[320px] rounded-md border">
                  <div className="p-2 space-y-0.5">
                    {!selectedProjectId ? (
                      <p className="text-sm text-muted-foreground text-center py-8">
                        Select a project first
                      </p>
                    ) : filteredJurors.length === 0 ? (
                      <p className="text-sm text-muted-foreground text-center py-8">
                        No jurors found
                      </p>
                    ) : (
                      filteredJurors.map((juror: any) => {
                        const alreadyAssigned = projectExistingJurorIds.has(juror.id)
                        const isSelected = selectedJurorIds.has(juror.id)
                        const assignCount = jurorAssignmentCounts.get(juror.id) ?? 0

                        return (
                          <label
                            key={juror.id}
                            className={cn(
                              'flex items-center gap-3 rounded-md px-2.5 py-2 text-sm cursor-pointer transition-colors',
                              alreadyAssigned
                                ? 'opacity-50 cursor-not-allowed'
                                : isSelected
                                  ? 'bg-accent'
                                  : 'hover:bg-muted/50',
                            )}
                          >
                            <Checkbox
                              checked={isSelected}
                              disabled={alreadyAssigned}
                              onCheckedChange={() => toggleJuror(juror.id)}
                            />
                            <div className="flex flex-1 items-center justify-between min-w-0">
                              <div className="min-w-0">
                                <span className="font-medium truncate block">{juror.name || 'Unnamed'}</span>
                                <span className="text-xs text-muted-foreground truncate block">{juror.email}</span>
                              </div>
                              <div className="flex items-center gap-1.5 shrink-0 ml-2">
                                <Badge variant="secondary" className="text-[10px]">
                                  {assignCount} assigned
                                </Badge>
                                {alreadyAssigned && (
                                  <Badge variant="outline" className="text-[10px] bg-amber-50 text-amber-700 border-amber-200">
                                    Already on project
                                  </Badge>
                                )}
                              </div>
                            </div>
                          </label>
                        )
                      })
                    )}
                  </div>
                </ScrollArea>
              </div>

              <DialogFooter>
                <Button variant="outline" onClick={resetDialog}>
                  Cancel
                </Button>
                <Button
                  onClick={handleCreateByProject}
                  disabled={!selectedProjectId || selectedJurorIds.size === 0 || isMutating}
                >
                  {isMutating && <Loader2 className="h-4 w-4 mr-1.5 animate-spin" />}
                  {selectedJurorIds.size <= 1
                    ? 'Create Assignment'
                    : `Create ${selectedJurorIds.size} Assignments`
                  }
                </Button>
              </DialogFooter>
            </TabsContent>
          </Tabs>
        </DialogContent>
      </Dialog>

      {/* 4.2 Confirmation AlertDialog for reset/delete (replaces native confirm) */}
      <AlertDialog open={!!confirmAction} onOpenChange={(open) => { if (!open) setConfirmAction(null) }}>
        <AlertDialogContent>
          <AlertDialogHeader>
            <AlertDialogTitle>
              {confirmAction?.type === 'reset' ? 'Reset evaluation?' : 'Delete assignment?'}
            </AlertDialogTitle>
            <AlertDialogDescription>
              {confirmAction?.type === 'reset'
                ? `Reset evaluation by ${confirmAction.assignment?.user?.name || confirmAction.assignment?.user?.email} for "${confirmAction.assignment?.project?.title}"? This will erase all scores and feedback so they can start over.`
                : `Remove assignment for ${confirmAction?.assignment?.user?.name || confirmAction?.assignment?.user?.email} on "${confirmAction?.assignment?.project?.title}"?`
              }
            </AlertDialogDescription>
          </AlertDialogHeader>
          <AlertDialogFooter>
            <AlertDialogCancel>Cancel</AlertDialogCancel>
            <AlertDialogAction
              className={confirmAction?.type === 'delete' ? 'bg-destructive text-destructive-foreground hover:bg-destructive/90' : ''}
              onClick={() => {
                if (confirmAction?.type === 'reset') {
                  resetEvalMutation.mutate({ assignmentId: confirmAction.assignment.id })
                } else if (confirmAction?.type === 'delete') {
                  deleteMutation.mutate({ id: confirmAction.assignment.id })
                }
                setConfirmAction(null)
              }}
            >
              {confirmAction?.type === 'reset' ? 'Reset' : 'Delete'}
            </AlertDialogAction>
          </AlertDialogFooter>
        </AlertDialogContent>
      </AlertDialog>
    </div>
  )
}

// ── Evaluation Criteria Editor ───────────────────────────────────────────

// ── Advance Projects Dialog ─────────────────────────────────────────────

function AdvanceProjectsDialog({
  open,
  onOpenChange,
  roundId,
  roundType,
  projectStates,
  config,
  advanceMutation,
  competitionRounds,
  currentSortOrder,
}: {
  open: boolean
  onOpenChange: (open: boolean) => void
  roundId: string
  roundType?: string
  projectStates: any[] | undefined
  config: Record<string, unknown>
  advanceMutation: { mutate: (input: { roundId: string; projectIds?: string[]; targetRoundId?: string; autoPassPending?: boolean }) => void; isPending: boolean }
  competitionRounds?: Array<{ id: string; name: string; sortOrder: number; roundType: string }>
  currentSortOrder?: number
}) {
  // For non-jury rounds (INTAKE, SUBMISSION, MENTORING), offer a simpler "advance all" flow
  const isSimpleAdvance = ['INTAKE', 'SUBMISSION', 'MENTORING'].includes(roundType ?? '')
  // Target round selector
  const availableTargets = useMemo(() =>
    (competitionRounds ?? [])
      .filter((r) => r.sortOrder > (currentSortOrder ?? -1) && r.id !== roundId)
      .sort((a, b) => a.sortOrder - b.sortOrder),
  [competitionRounds, currentSortOrder, roundId])

  const [targetRoundId, setTargetRoundId] = useState<string>('')

  // Default to first available target when dialog opens
  if (open && !targetRoundId && availableTargets.length > 0) {
    setTargetRoundId(availableTargets[0].id)
  }
  const allProjects = projectStates ?? []
  const pendingCount = allProjects.filter((ps: any) => ps.state === 'PENDING').length
  const passedProjects = useMemo(() =>
    allProjects.filter((ps: any) => ps.state === 'PASSED'),
  [allProjects])

  const startups = useMemo(() =>
    passedProjects.filter((ps: any) => ps.project?.competitionCategory === 'STARTUP'),
  [passedProjects])

  const concepts = useMemo(() =>
    passedProjects.filter((ps: any) => ps.project?.competitionCategory === 'BUSINESS_CONCEPT'),
  [passedProjects])

  const other = useMemo(() =>
    passedProjects.filter((ps: any) =>
      ps.project?.competitionCategory !== 'STARTUP' && ps.project?.competitionCategory !== 'BUSINESS_CONCEPT',
    ),
  [passedProjects])

  const startupCap = (config.startupAdvanceCount as number) || 0
  const conceptCap = (config.conceptAdvanceCount as number) || 0

  const [selected, setSelected] = useState<Set<string>>(new Set())

  // Reset selection when dialog opens
  if (open && selected.size === 0 && passedProjects.length > 0) {
    const initial = new Set<string>()
    // Auto-select all (or up to cap if configured)
    const startupSlice = startupCap > 0 ? startups.slice(0, startupCap) : startups
    const conceptSlice = conceptCap > 0 ? concepts.slice(0, conceptCap) : concepts
    for (const ps of startupSlice) initial.add(ps.project?.id)
    for (const ps of conceptSlice) initial.add(ps.project?.id)
    for (const ps of other) initial.add(ps.project?.id)
    setSelected(initial)
  }

  const toggleProject = (projectId: string) => {
    setSelected((prev) => {
      const next = new Set(prev)
      if (next.has(projectId)) next.delete(projectId)
      else next.add(projectId)
      return next
    })
  }

  const toggleAll = (projects: any[], on: boolean) => {
    setSelected((prev) => {
      const next = new Set(prev)
      for (const ps of projects) {
        if (on) next.add(ps.project?.id)
        else next.delete(ps.project?.id)
      }
      return next
    })
  }

  const handleAdvance = (autoPass?: boolean) => {
    if (autoPass) {
      // Auto-pass all pending then advance all
      advanceMutation.mutate({
        roundId,
        autoPassPending: true,
        ...(targetRoundId ? { targetRoundId } : {}),
      })
    } else {
      const ids = Array.from(selected)
      if (ids.length === 0) return
      advanceMutation.mutate({
        roundId,
        projectIds: ids,
        ...(targetRoundId ? { targetRoundId } : {}),
      })
    }
    onOpenChange(false)
    setSelected(new Set())
    setTargetRoundId('')
  }

  const handleClose = () => {
    onOpenChange(false)
    setSelected(new Set())
    setTargetRoundId('')
  }

  const renderCategorySection = (
    label: string,
    projects: any[],
    cap: number,
    badgeColor: string,
  ) => {
    const selectedInCategory = projects.filter((ps: any) => selected.has(ps.project?.id)).length
    const overCap = cap > 0 && selectedInCategory > cap

    return (
      <div className="space-y-2">
        <div className="flex items-center justify-between">
          <div className="flex items-center gap-2">
            <Checkbox
              checked={projects.length > 0 && projects.every((ps: any) => selected.has(ps.project?.id))}
              onCheckedChange={(checked) => toggleAll(projects, !!checked)}
            />
            <span className="text-sm font-medium">{label}</span>
            <Badge variant="secondary" className={cn('text-[10px]', badgeColor)}>
              {selectedInCategory}/{projects.length}
            </Badge>
            {cap > 0 && (
              <span className={cn('text-[10px]', overCap ? 'text-red-500 font-medium' : 'text-muted-foreground')}>
                (target: {cap})
              </span>
            )}
          </div>
        </div>
        {projects.length === 0 ? (
          <p className="text-xs text-muted-foreground pl-7">No passed projects in this category</p>
        ) : (
          <div className="space-y-1 pl-7">
            {projects.map((ps: any) => (
              <label
                key={ps.project?.id}
                className="flex items-center gap-2 p-2 rounded hover:bg-muted/30 cursor-pointer"
              >
                <Checkbox
                  checked={selected.has(ps.project?.id)}
                  onCheckedChange={() => toggleProject(ps.project?.id)}
                />
                <span className="text-sm truncate flex-1">{ps.project?.title || 'Untitled'}</span>
                {ps.project?.teamName && (
                  <span className="text-xs text-muted-foreground shrink-0">{ps.project.teamName}</span>
                )}
              </label>
            ))}
          </div>
        )}
      </div>
    )
  }

  const totalProjectCount = allProjects.length

  return (
    <Dialog open={open} onOpenChange={handleClose}>
      <DialogContent className="max-w-lg max-h-[85vh] flex flex-col">
        <DialogHeader>
          <DialogTitle>Advance Projects</DialogTitle>
          <DialogDescription>
            {isSimpleAdvance
              ? `Move all ${totalProjectCount} projects to the next round.`
              : `Select which passed projects to advance. ${selected.size} of ${passedProjects.length} selected.`
            }
          </DialogDescription>
        </DialogHeader>

        {/* Target round selector */}
        {availableTargets.length > 0 && (
          <div className="space-y-2 pb-2 border-b">
            <Label className="text-sm">Advance to</Label>
            <Select value={targetRoundId} onValueChange={setTargetRoundId}>
              <SelectTrigger>
                <SelectValue placeholder="Select target round" />
              </SelectTrigger>
              <SelectContent>
                {availableTargets.map((r) => (
                  <SelectItem key={r.id} value={r.id}>
                    {r.name} ({r.roundType.replace('_', ' ').toLowerCase()})
                  </SelectItem>
                ))}
              </SelectContent>
            </Select>
          </div>
        )}
        {availableTargets.length === 0 && (
          <div className="text-sm text-amber-600 bg-amber-50 rounded-md p-3">
            No subsequent rounds found. Projects will advance to the next round by sort order.
          </div>
        )}

        {isSimpleAdvance ? (
          /* Simple mode for INTAKE/SUBMISSION/MENTORING — no per-project selection needed */
          <div className="py-4 space-y-3">
            <div className="rounded-lg border bg-muted/30 p-4 text-center space-y-1">
              <p className="text-3xl font-bold">{totalProjectCount}</p>
              <p className="text-sm text-muted-foreground">projects will be advanced</p>
            </div>
            {pendingCount > 0 && (
              <div className="rounded-md border border-blue-200 bg-blue-50 px-3 py-2">
                <p className="text-xs text-blue-700">
                  {pendingCount} pending project{pendingCount !== 1 ? 's' : ''} will be automatically marked as passed and advanced.
                  {passedProjects.length > 0 && ` ${passedProjects.length} already passed.`}
                </p>
              </div>
            )}
          </div>
        ) : (
          /* Detailed mode for jury/evaluation rounds — per-project selection */
          <div className="flex-1 overflow-y-auto space-y-4 py-2">
            {renderCategorySection('Startup', startups, startupCap, 'bg-blue-100 text-blue-700')}
            {renderCategorySection('Business Concept', concepts, conceptCap, 'bg-purple-100 text-purple-700')}
            {other.length > 0 && renderCategorySection('Other / Uncategorized', other, 0, 'bg-gray-100 text-gray-700')}
          </div>
        )}

        <DialogFooter>
          <Button variant="outline" onClick={handleClose}>Cancel</Button>
          {isSimpleAdvance ? (
            <Button
              onClick={() => handleAdvance(true)}
              disabled={totalProjectCount === 0 || advanceMutation.isPending || availableTargets.length === 0}
            >
              {advanceMutation.isPending && <Loader2 className="h-4 w-4 mr-1.5 animate-spin" />}
              Advance All {totalProjectCount} Project{totalProjectCount !== 1 ? 's' : ''}
            </Button>
          ) : (
            <Button
              onClick={() => handleAdvance()}
              disabled={selected.size === 0 || advanceMutation.isPending || availableTargets.length === 0}
            >
              {advanceMutation.isPending && <Loader2 className="h-4 w-4 mr-1.5 animate-spin" />}
              Advance {selected.size} Project{selected.size !== 1 ? 's' : ''}
            </Button>
          )}
        </DialogFooter>
      </DialogContent>
    </Dialog>
  )
}

// ── AI Recommendations Display ──────────────────────────────────────────

type RecommendationItem = {
  projectId: string
  rank: number
  score: number
  category: string
  strengths: string[]
  concerns: string[]
  recommendation: string
}

function AIRecommendationsDisplay({
  recommendations,
  projectStates,
  roundId,
  onClear,
  onApplied,
}: {
  recommendations: { STARTUP: RecommendationItem[]; BUSINESS_CONCEPT: RecommendationItem[] }
  projectStates: any[] | undefined
  roundId: string
  onClear: () => void
  onApplied: () => void
}) {
  const [expandedId, setExpandedId] = useState<string | null>(null)
  const [applying, setApplying] = useState(false)

  // Initialize selected with all recommended project IDs
  const allRecommendedIds = useMemo(() => {
    const ids = new Set<string>()
    for (const item of recommendations.STARTUP) ids.add(item.projectId)
    for (const item of recommendations.BUSINESS_CONCEPT) ids.add(item.projectId)
    return ids
  }, [recommendations])

  const [selectedIds, setSelectedIds] = useState<Set<string>>(() => new Set(allRecommendedIds))

  // Build projectId → title map from projectStates
  const projectTitleMap = useMemo(() => {
    const map = new Map<string, string>()
    if (projectStates) {
      for (const ps of projectStates) {
        if (ps.project?.id && ps.project?.title) {
          map.set(ps.project.id, ps.project.title)
        }
      }
    }
    return map
  }, [projectStates])

  const transitionMutation = trpc.roundEngine.transitionProject.useMutation()

  const toggleProject = (projectId: string) => {
    setSelectedIds((prev) => {
      const next = new Set(prev)
      if (next.has(projectId)) next.delete(projectId)
      else next.add(projectId)
      return next
    })
  }

  const selectedStartups = recommendations.STARTUP.filter((item) => selectedIds.has(item.projectId)).length
  const selectedConcepts = recommendations.BUSINESS_CONCEPT.filter((item) => selectedIds.has(item.projectId)).length

  const handleApply = async () => {
    setApplying(true)
    try {
      // Transition all selected projects to PASSED
      const promises = Array.from(selectedIds).map((projectId) =>
        transitionMutation.mutateAsync({ projectId, roundId, newState: 'PASSED' }).catch(() => {
          // Project might already be PASSED — that's OK
        })
      )
      await Promise.all(promises)
      toast.success(`Marked ${selectedIds.size} project(s) as passed`)
      onApplied()
    } catch (error) {
      toast.error('Failed to apply recommendations')
    } finally {
      setApplying(false)
    }
  }

  const renderCategory = (label: string, items: RecommendationItem[], colorClass: string) => {
    if (items.length === 0) return (
      <div className="text-center py-4 text-muted-foreground text-sm">
        No {label.toLowerCase()} projects evaluated
      </div>
    )

    return (
      <div className="space-y-2">
        {items.map((item) => {
          const isExpanded = expandedId === `${item.category}-${item.projectId}`
          const isSelected = selectedIds.has(item.projectId)
          const projectTitle = projectTitleMap.get(item.projectId) || item.projectId

          return (
            <div
              key={item.projectId}
              className={cn(
                'border rounded-lg overflow-hidden transition-colors',
                !isSelected && 'opacity-50',
              )}
            >
              <div className="flex items-center gap-2 p-3">
                <Checkbox
                  checked={isSelected}
                  onCheckedChange={() => toggleProject(item.projectId)}
                  className="shrink-0"
                />
                <button
                  onClick={() => setExpandedId(isExpanded ? null : `${item.category}-${item.projectId}`)}
                  className="flex-1 flex items-center gap-3 text-left hover:bg-muted/30 rounded transition-colors min-w-0"
                >
                  <span className={cn(
                    'h-7 w-7 rounded-full flex items-center justify-center text-xs font-bold text-white shrink-0 shadow-sm',
                    colorClass === 'bg-blue-500' ? 'bg-gradient-to-br from-blue-400 to-blue-600' : 'bg-gradient-to-br from-purple-400 to-purple-600',
                  )}>
                    {item.rank}
                  </span>
                  <div className="flex-1 min-w-0">
                    <p className="text-sm font-medium truncate">{projectTitle}</p>
                    <p className="text-xs text-muted-foreground truncate">{item.recommendation}</p>
                  </div>
                  <Badge variant="outline" className="shrink-0 text-xs font-mono">
                    {item.score}/100
                  </Badge>
                  <ChevronDown className={cn(
                    'h-4 w-4 text-muted-foreground transition-transform shrink-0',
                    isExpanded && 'rotate-180',
                  )} />
                </button>
              </div>
              {isExpanded && (
                <div className="px-3 pb-3 pt-0 space-y-2 border-t bg-muted/10">
                  <div className="pt-2">
                    <p className="text-xs font-medium text-emerald-700 mb-1">Strengths</p>
                    <ul className="text-xs text-muted-foreground space-y-0.5 pl-4 list-disc">
                      {item.strengths.map((s, i) => <li key={i}>{s}</li>)}
                    </ul>
                  </div>
                  {item.concerns.length > 0 && (
                    <div>
                      <p className="text-xs font-medium text-amber-700 mb-1">Concerns</p>
                      <ul className="text-xs text-muted-foreground space-y-0.5 pl-4 list-disc">
                        {item.concerns.map((c, i) => <li key={i}>{c}</li>)}
                      </ul>
                    </div>
                  )}
                  <div>
                    <p className="text-xs font-medium text-blue-700 mb-1">Recommendation</p>
                    <p className="text-xs text-muted-foreground">{item.recommendation}</p>
                  </div>
                </div>
              )}
            </div>
          )
        })}
      </div>
    )
  }

  return (
    <Card>
      <CardHeader>
        <div className="flex items-center justify-between">
          <div>
            <CardTitle className="text-base">AI Shortlist Recommendations</CardTitle>
            <CardDescription>
              Ranked independently per category — {selectedStartups} of {recommendations.STARTUP.length} startups, {selectedConcepts} of {recommendations.BUSINESS_CONCEPT.length} concepts selected
            </CardDescription>
          </div>
          <Button variant="ghost" size="sm" onClick={onClear}>
            <X className="h-4 w-4 mr-1" />
            Dismiss
          </Button>
        </div>
      </CardHeader>
      <CardContent className="space-y-6">
        <div className="grid gap-6 lg:grid-cols-2">
          <div>
            <h4 className="text-sm font-semibold mb-3 flex items-center gap-2">
              <div className="h-2 w-2 rounded-full bg-blue-500" />
              Startup ({recommendations.STARTUP.length})
            </h4>
            {renderCategory('Startup', recommendations.STARTUP, 'bg-blue-500')}
          </div>
          <div>
            <h4 className="text-sm font-semibold mb-3 flex items-center gap-2">
              <div className="h-2 w-2 rounded-full bg-purple-500" />
              Business Concept ({recommendations.BUSINESS_CONCEPT.length})
            </h4>
            {renderCategory('Business Concept', recommendations.BUSINESS_CONCEPT, 'bg-purple-500')}
          </div>
        </div>

        {/* Apply button */}
        <div className="flex items-center justify-between pt-4 border-t">
          <p className="text-sm text-muted-foreground">
            {selectedIds.size} project{selectedIds.size !== 1 ? 's' : ''} will be marked as <strong>Passed</strong>
          </p>
          <Button
            onClick={handleApply}
            disabled={selectedIds.size === 0 || applying}
            className="bg-[#053d57] hover:bg-[#053d57]/90 text-white"
          >
            {applying ? (
              <><Loader2 className="h-4 w-4 mr-1.5 animate-spin" />Applying...</>
            ) : (
              <><CheckCircle2 className="h-4 w-4 mr-1.5" />Apply &amp; Mark as Passed</>
            )}
          </Button>
        </div>
      </CardContent>
    </Card>
  )
}

// ── Evaluation Criteria Editor ───────────────────────────────────────────

function EvaluationCriteriaEditor({ roundId }: { roundId: string }) {
  const [pendingCriteria, setPendingCriteria] = useState<Criterion[] | null>(null)
  const utils = trpc.useUtils()

  const { data: form, isLoading } = trpc.evaluation.getForm.useQuery(
    { roundId },
    { refetchInterval: 30_000 },
  )

  const upsertMutation = trpc.evaluation.upsertForm.useMutation({
    onSuccess: () => {
      utils.evaluation.getForm.invalidate({ roundId })
      toast.success('Evaluation criteria saved')
      setPendingCriteria(null)
    },
    onError: (err) => toast.error(err.message),
  })

  // Convert server criteriaJson to Criterion[] format
  const serverCriteria: Criterion[] = useMemo(() => {
    if (!form?.criteriaJson) return []
    return (form.criteriaJson as Criterion[]).map((c) => {
      // Handle legacy numeric-only format: convert "scale" string like "1-10" back to minScore/maxScore
      const type = c.type || 'numeric'
      if (type === 'numeric' && typeof c.scale === 'string') {
        const parts = (c.scale as string).split('-').map(Number)
        if (parts.length === 2 && !isNaN(parts[0]) && !isNaN(parts[1])) {
          return { ...c, type: 'numeric' as const, scale: parts[1], minScore: parts[0], maxScore: parts[1] } as unknown as Criterion
        }
      }
      return { ...c, type } as Criterion
    })
  }, [form?.criteriaJson])

  const handleChange = useCallback((criteria: Criterion[]) => {
    setPendingCriteria(criteria)
  }, [])

  const handleSave = () => {
    const criteria = pendingCriteria ?? serverCriteria
    const validCriteria = criteria.filter((c) => c.label.trim())
    if (validCriteria.length === 0) {
      toast.error('Add at least one criterion')
      return
    }
    // Map to upsertForm format
    upsertMutation.mutate({
      roundId,
      criteria: validCriteria.map((c) => ({
        id: c.id,
        label: c.label,
        description: c.description,
        type: c.type || 'numeric',
        weight: c.weight,
        scale: typeof c.scale === 'number' ? c.scale : undefined,
        minScore: (c as any).minScore,
        maxScore: (c as any).maxScore,
        required: c.required,
        maxLength: c.maxLength,
        placeholder: c.placeholder,
        trueLabel: c.trueLabel,
        falseLabel: c.falseLabel,
        condition: c.condition,
        sectionId: c.sectionId,
      })),
    })
  }

  return (
    <Card>
      <CardHeader>
        <div className="flex items-center justify-between">
          <div>
            <CardTitle className="text-base">Evaluation Criteria</CardTitle>
            <CardDescription>
              {form
                ? `Version ${form.version} \u2014 ${(form.criteriaJson as Criterion[]).filter((c) => (c.type || 'numeric') !== 'section_header').length} criteria`
                : 'No criteria defined yet. Add numeric scores, yes/no questions, and text fields.'}
            </CardDescription>
          </div>
          {pendingCriteria && (
            <div className="flex items-center gap-2">
              <Button size="sm" variant="outline" onClick={() => setPendingCriteria(null)}>
                Cancel
              </Button>
              <Button size="sm" onClick={handleSave} disabled={upsertMutation.isPending}>
                {upsertMutation.isPending && <Loader2 className="h-4 w-4 mr-1.5 animate-spin" />}
                Save Criteria
              </Button>
            </div>
          )}
        </div>
      </CardHeader>
      <CardContent>
        {isLoading ? (
          <div className="space-y-3">
            {[1, 2, 3].map((i) => <Skeleton key={i} className="h-16 w-full" />)}
          </div>
        ) : (
          <EvaluationFormBuilder
            initialCriteria={serverCriteria}
            onChange={handleChange}
          />
        )}
      </CardContent>
    </Card>
  )
}

// ── COI Review Section ────────────────────────────────────────────────────

function COIReviewSection({ roundId }: { roundId: string }) {
  const utils = trpc.useUtils()
  const { data: declarations, isLoading } = trpc.evaluation.listCOIByStage.useQuery(
    { roundId },
    { refetchInterval: 15_000 },
  )

  const reviewMutation = trpc.evaluation.reviewCOI.useMutation({
    onSuccess: (data) => {
      utils.evaluation.listCOIByStage.invalidate({ roundId })
      utils.assignment.listByStage.invalidate({ roundId })
      utils.analytics.getJurorWorkload.invalidate({ roundId })
      if (data.reassignment) {
        toast.success(`Reassigned to ${data.reassignment.newJurorName}`)
      } else {
        toast.success('COI review updated')
      }
    },
    onError: (err) => toast.error(err.message),
  })

  // Show placeholder when no declarations
  if (!isLoading && (!declarations || declarations.length === 0)) {
    return (
      <div className="rounded-lg border border-dashed p-4 text-center">
        <p className="text-sm text-muted-foreground">No conflict of interest declarations yet.</p>
      </div>
    )
  }

  const conflictCount = declarations?.filter((d) => d.hasConflict).length ?? 0
  const unreviewedCount = declarations?.filter((d) => d.hasConflict && !d.reviewedAt).length ?? 0

  return (
    <div className="space-y-3">
      <div className="flex items-center justify-between">
        <div>
          <p className="text-sm font-medium flex items-center gap-2">
            <ShieldAlert className="h-4 w-4" />
            Conflict of Interest Declarations
          </p>
          <p className="text-xs text-muted-foreground">
            {declarations?.length ?? 0} declaration{(declarations?.length ?? 0) !== 1 ? 's' : ''}
            {conflictCount > 0 && (
              <> &mdash; <span className="text-amber-600 font-medium">{conflictCount} conflict{conflictCount !== 1 ? 's' : ''}</span></>
            )}
            {unreviewedCount > 0 && (
              <> ({unreviewedCount} pending review)</>
            )}
          </p>
        </div>
      </div>
      <div>
        {isLoading ? (
          <div className="space-y-2">
            {[1, 2, 3].map((i) => <Skeleton key={i} className="h-14 w-full" />)}
          </div>
        ) : (
          <div className="space-y-1 max-h-[400px] overflow-y-auto">
            <div className="grid grid-cols-[1fr_1fr_80px_100px_100px] gap-2 text-xs text-muted-foreground font-medium px-3 py-2 sticky top-0 bg-background border-b">
              <span>Juror</span>
              <span>Project</span>
              <span>Conflict</span>
              <span>Type</span>
              <span>Action</span>
            </div>
            {declarations?.map((coi: any, idx: number) => (
              <div
                key={coi.id}
                className={cn(
                  'grid grid-cols-[1fr_1fr_80px_100px_100px] gap-2 items-center px-3 py-2 rounded-md text-sm transition-colors',
                  idx % 2 === 1 ? 'bg-muted/20' : 'hover:bg-muted/20',
                  coi.hasConflict && !coi.reviewedAt && 'border-l-4 border-l-amber-500',
                )}
              >
                <span className="truncate">{coi.user?.name || coi.user?.email || 'Unknown'}</span>
                <span className="truncate text-muted-foreground">{coi.assignment?.project?.title || 'Unknown'}</span>
                <Badge
                  variant="outline"
                  className={cn(
                    'text-[10px] justify-center',
                    coi.hasConflict
                      ? 'bg-red-50 text-red-700 border-red-200'
                      : 'bg-emerald-50 text-emerald-700 border-emerald-200',
                  )}
                >
                  {coi.hasConflict ? 'Yes' : 'No'}
                </Badge>
                <span className="text-xs text-muted-foreground truncate">
                  {coi.hasConflict ? (coi.conflictType || 'Unspecified') : '\u2014'}
                </span>
                {coi.hasConflict ? (
                  coi.reviewedAt ? (
                    <Badge
                      variant="outline"
                      className={cn(
                        'text-[10px] justify-center',
                        coi.reviewAction === 'cleared'
                          ? 'bg-emerald-50 text-emerald-700 border-emerald-200'
                          : coi.reviewAction === 'reassigned'
                            ? 'bg-blue-50 text-blue-700 border-blue-200'
                            : 'bg-gray-50 text-gray-600 border-gray-200',
                      )}
                    >
                      {coi.reviewAction === 'cleared' ? 'Cleared' : coi.reviewAction === 'reassigned' ? 'Reassigned' : 'Noted'}
                    </Badge>
                  ) : (
                    <DropdownMenu>
                      <DropdownMenuTrigger asChild>
                        <Button variant="outline" size="sm" className="h-7 text-xs">
                          <Eye className="h-3 w-3 mr-1" />
                          Review
                        </Button>
                      </DropdownMenuTrigger>
                      <DropdownMenuContent align="end">
                        <DropdownMenuItem
                          onClick={() => reviewMutation.mutate({ id: coi.id, reviewAction: 'cleared' })}
                          disabled={reviewMutation.isPending}
                        >
                          <CheckCircle2 className="h-3.5 w-3.5 mr-2 text-emerald-600" />
                          Clear — no real conflict
                        </DropdownMenuItem>
                        <DropdownMenuItem
                          onClick={() => reviewMutation.mutate({ id: coi.id, reviewAction: 'reassigned' })}
                          disabled={reviewMutation.isPending}
                        >
                          <UserPlus className="h-3.5 w-3.5 mr-2 text-blue-600" />
                          Reassign to another juror
                        </DropdownMenuItem>
                        <DropdownMenuItem
                          onClick={() => reviewMutation.mutate({ id: coi.id, reviewAction: 'noted' })}
                          disabled={reviewMutation.isPending}
                        >
                          <FileText className="h-3.5 w-3.5 mr-2 text-gray-600" />
                          Note — keep as is
                        </DropdownMenuItem>
                      </DropdownMenuContent>
                    </DropdownMenu>
                  )
                ) : (
                  <span className="text-xs text-muted-foreground">&mdash;</span>
                )}
              </div>
            ))}
          </div>
        )}
      </div>
    </div>
  )
}
