'use client'

import { useState, useMemo } from 'react'
import { trpc } from '@/lib/trpc/client'
import { toast } from 'sonner'
import { cn } from '@/lib/utils'
import { Button } from '@/components/ui/button'
import { Badge } from '@/components/ui/badge'
import { Checkbox } from '@/components/ui/checkbox'
import { Skeleton } from '@/components/ui/skeleton'
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from '@/components/ui/dialog'
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from '@/components/ui/select'
import { Loader2, Sparkles } from 'lucide-react'

export type TransferAssignmentsDialogProps = {
  roundId: string
  sourceJuror: { id: string; name: string }
  open: boolean
  onClose: () => void
}

export function TransferAssignmentsDialog({
  roundId,
  sourceJuror,
  open,
  onClose,
}: TransferAssignmentsDialogProps) {
  const utils = trpc.useUtils()
  const [step, setStep] = useState<1 | 2>(1)
  const [selectedIds, setSelectedIds] = useState<Set<string>>(new Set())

  // Fetch source juror's assignments
  const { data: sourceAssignments, isLoading: loadingAssignments } = trpc.assignment.listByStage.useQuery(
    { roundId },
    { enabled: open },
  )

  const jurorAssignments = useMemo(() =>
    (sourceAssignments ?? []).filter((a: any) => a.userId === sourceJuror.id),
    [sourceAssignments, sourceJuror.id],
  )

  // Fetch transfer candidates when in step 2
  const { data: candidateData, isLoading: loadingCandidates } = trpc.assignment.getTransferCandidates.useQuery(
    { roundId, sourceJurorId: sourceJuror.id, assignmentIds: [...selectedIds] },
    { enabled: step === 2 && selectedIds.size > 0 },
  )

  // Per-assignment destination overrides
  const [destOverrides, setDestOverrides] = useState<Record<string, string>>({})
  const [forceOverCap, setForceOverCap] = useState(false)

  // Auto-assign: distribute assignments across eligible candidates balanced by load
  const handleAutoAssign = () => {
    if (!candidateData) return
    const movable = candidateData.assignments.filter((a) => a.movable)
    if (movable.length === 0) return

    // Simulate load starting from each candidate's current load
    const simLoad = new Map<string, number>()
    for (const c of candidateData.candidates) {
      simLoad.set(c.userId, c.currentLoad)
    }

    const overrides: Record<string, string> = {}

    for (const assignment of movable) {
      const eligible = candidateData.candidates
        .filter((c) => c.eligibleProjectIds.includes(assignment.projectId))

      if (eligible.length === 0) continue

      // Sort: prefer not-all-completed, then under cap, then lowest simulated load
      const sorted = [...eligible].sort((a, b) => {
        // Prefer jurors who haven't completed all evaluations
        if (a.allCompleted !== b.allCompleted) return a.allCompleted ? 1 : -1
        const loadA = simLoad.get(a.userId) ?? 0
        const loadB = simLoad.get(b.userId) ?? 0
        // Prefer jurors under their cap
        const overCapA = loadA >= a.cap ? 1 : 0
        const overCapB = loadB >= b.cap ? 1 : 0
        if (overCapA !== overCapB) return overCapA - overCapB
        // Then pick the least loaded
        return loadA - loadB
      })

      const best = sorted[0]
      overrides[assignment.id] = best.userId
      simLoad.set(best.userId, (simLoad.get(best.userId) ?? 0) + 1)
    }

    setDestOverrides(overrides)
  }

  const transferMutation = trpc.assignment.transferAssignments.useMutation({
    onSuccess: (data) => {
      utils.assignment.listByStage.invalidate({ roundId })
      utils.analytics.getJurorWorkload.invalidate({ roundId })
      utils.roundAssignment.unassignedQueue.invalidate({ roundId })
      utils.assignment.getReassignmentHistory.invalidate({ roundId })

      const successCount = data.succeeded.length
      const failCount = data.failed.length
      if (failCount > 0) {
        toast.warning(`Transferred ${successCount} project(s). ${failCount} failed.`)
      } else {
        toast.success(`Transferred ${successCount} project(s) successfully.`)
      }
      onClose()
    },
    onError: (err) => toast.error(err.message),
  })

  // Build the transfer plan: for each selected assignment, determine destination
  const transferPlan = useMemo(() => {
    if (!candidateData) return []
    const movable = candidateData.assignments.filter((a) => a.movable)
    return movable.map((assignment) => {
      const override = destOverrides[assignment.id]
      // Default: first eligible candidate
      const defaultDest = candidateData.candidates.find((c) =>
        c.eligibleProjectIds.includes(assignment.projectId)
      )
      const destId = override || defaultDest?.userId || ''
      const destName = candidateData.candidates.find((c) => c.userId === destId)?.name || ''
      return { assignmentId: assignment.id, projectTitle: assignment.projectTitle, destinationJurorId: destId, destName }
    }).filter((t) => t.destinationJurorId)
  }, [candidateData, destOverrides])

  // Check if any destination is at or over cap
  const anyOverCap = useMemo(() => {
    if (!candidateData) return false
    const destCounts = new Map<string, number>()
    for (const t of transferPlan) {
      destCounts.set(t.destinationJurorId, (destCounts.get(t.destinationJurorId) ?? 0) + 1)
    }
    return candidateData.candidates.some((c) => {
      const extraLoad = destCounts.get(c.userId) ?? 0
      return c.currentLoad + extraLoad > c.cap
    })
  }, [candidateData, transferPlan])

  const handleTransfer = () => {
    transferMutation.mutate({
      roundId,
      sourceJurorId: sourceJuror.id,
      transfers: transferPlan.map((t) => ({ assignmentId: t.assignmentId, destinationJurorId: t.destinationJurorId })),
      forceOverCap,
    })
  }

  const isMovable = (a: any) => {
    const status = a.evaluation?.status
    return !status || status === 'NOT_STARTED' || status === 'DRAFT'
  }

  const movableAssignments = jurorAssignments.filter(isMovable)
  const allMovableSelected = movableAssignments.length > 0 && movableAssignments.every((a: any) => selectedIds.has(a.id))

  return (
    <Dialog open={open} onOpenChange={(v) => { if (!v) onClose() }}>
      <DialogContent className="max-w-2xl max-h-[80vh] overflow-y-auto">
        <DialogHeader>
          <DialogTitle>Transfer Assignments from {sourceJuror.name}</DialogTitle>
          <DialogDescription>
            {step === 1 ? 'Select projects to transfer to other jurors.' : 'Choose destination jurors for each project.'}
          </DialogDescription>
        </DialogHeader>

        {step === 1 && (
          <div className="space-y-3">
            {loadingAssignments ? (
              <div className="space-y-2">
                {[1, 2, 3].map((i) => <Skeleton key={i} className="h-10 w-full" />)}
              </div>
            ) : jurorAssignments.length === 0 ? (
              <p className="text-sm text-muted-foreground text-center py-6">No assignments found.</p>
            ) : (
              <>
                <div className="flex items-center gap-2 pb-2 border-b">
                  <Checkbox
                    checked={allMovableSelected}
                    onCheckedChange={(checked) => {
                      if (checked) {
                        setSelectedIds(new Set(movableAssignments.map((a: any) => a.id)))
                      } else {
                        setSelectedIds(new Set())
                      }
                    }}
                  />
                  <span className="text-xs text-muted-foreground">Select all movable ({movableAssignments.length})</span>
                </div>
                <div className="space-y-1 max-h-[400px] overflow-y-auto">
                  {jurorAssignments.map((a: any) => {
                    const movable = isMovable(a)
                    const status = a.evaluation?.status || 'No evaluation'
                    return (
                      <div key={a.id} className={cn('flex items-center gap-3 py-2 px-2 rounded-md', !movable && 'opacity-50')}>
                        <Checkbox
                          checked={selectedIds.has(a.id)}
                          disabled={!movable}
                          onCheckedChange={(checked) => {
                            const next = new Set(selectedIds)
                            if (checked) next.add(a.id)
                            else next.delete(a.id)
                            setSelectedIds(next)
                          }}
                        />
                        <div className="flex-1 min-w-0">
                          <p className="text-sm truncate">{a.project?.title || 'Unknown'}</p>
                        </div>
                        <Badge variant="outline" className="text-xs shrink-0">
                          {status}
                        </Badge>
                      </div>
                    )
                  })}
                </div>
              </>
            )}
            <DialogFooter>
              <Button variant="outline" onClick={onClose}>Cancel</Button>
              <Button
                disabled={selectedIds.size === 0}
                onClick={() => { setStep(2); setDestOverrides({}) }}
              >
                Next ({selectedIds.size} selected)
              </Button>
            </DialogFooter>
          </div>
        )}

        {step === 2 && (
          <div className="space-y-3">
            {loadingCandidates ? (
              <div className="space-y-2">
                {[1, 2, 3].map((i) => <Skeleton key={i} className="h-10 w-full" />)}
              </div>
            ) : !candidateData || candidateData.candidates.length === 0 ? (
              <p className="text-sm text-muted-foreground text-center py-6">No eligible candidates found.</p>
            ) : (
              <>
                <div className="flex items-center justify-end">
                  <Button variant="outline" size="sm" onClick={handleAutoAssign}>
                    <Sparkles className="mr-1.5 h-3.5 w-3.5" />
                    Auto-assign
                  </Button>
                </div>
                <div className="space-y-2 max-h-[350px] overflow-y-auto">
                  {candidateData.assignments.filter((a) => a.movable).map((assignment) => {
                    const currentDest = destOverrides[assignment.id] ||
                      candidateData.candidates.find((c) => c.eligibleProjectIds.includes(assignment.projectId))?.userId || ''
                    return (
                      <div key={assignment.id} className="flex items-center gap-3 py-2 px-2 border rounded-md">
                        <div className="flex-1 min-w-0">
                          <p className="text-sm truncate">{assignment.projectTitle}</p>
                          <p className="text-xs text-muted-foreground">{assignment.evalStatus || 'No evaluation'}</p>
                        </div>
                        <Select
                          value={currentDest}
                          onValueChange={(v) => setDestOverrides((prev) => ({ ...prev, [assignment.id]: v }))}
                        >
                          <SelectTrigger className="w-[220px] h-8 text-xs">
                            <SelectValue placeholder="Select juror" />
                          </SelectTrigger>
                          <SelectContent>
                            {candidateData.candidates.map((c) => {
                              const isEligible = c.eligibleProjectIds.includes(assignment.projectId)
                              const alreadyHas = c.alreadyAssignedProjectIds?.includes(assignment.projectId)
                              return (
                                <SelectItem
                                  key={c.userId}
                                  value={c.userId}
                                  disabled={!isEligible}
                                  className={cn(!isEligible && 'opacity-50')}
                                >
                                  <span>{c.name}</span>
                                  <span className="text-muted-foreground ml-1">({c.currentLoad}/{c.cap})</span>
                                  {c.allCompleted && <span className="text-emerald-600 ml-1">Done</span>}
                                  {alreadyHas && <span className="text-amber-600 ml-1">Already assigned</span>}
                                  {!isEligible && !alreadyHas && c.currentLoad >= c.cap && <span className="text-red-500 ml-1">At cap</span>}
                                </SelectItem>
                              )
                            })}
                          </SelectContent>
                        </Select>
                      </div>
                    )
                  })}
                </div>

                {transferPlan.length > 0 && (
                  <p className="text-xs text-muted-foreground">
                    Transfer {transferPlan.length} project(s) from {sourceJuror.name}
                  </p>
                )}

                {anyOverCap && (
                  <div className="flex items-center gap-2 p-2 border border-amber-200 bg-amber-50 rounded-md">
                    <Checkbox
                      checked={forceOverCap}
                      onCheckedChange={(checked) => setForceOverCap(!!checked)}
                    />
                    <span className="text-xs text-amber-800">Force over-cap: some destinations will exceed their assignment limit</span>
                  </div>
                )}
              </>
            )}
            <DialogFooter>
              <Button variant="outline" onClick={() => setStep(1)}>Back</Button>
              <Button
                disabled={transferPlan.length === 0 || transferMutation.isPending || (anyOverCap && !forceOverCap)}
                onClick={handleTransfer}
              >
                {transferMutation.isPending ? <Loader2 className="h-4 w-4 animate-spin mr-1.5" /> : null}
                Transfer {transferPlan.length} project(s)
              </Button>
            </DialogFooter>
          </div>
        )}
      </DialogContent>
    </Dialog>
  )
}
