"use client"

import { useState, useRef, useMemo, type JSX, type KeyboardEvent, type ClipboardEvent } from "react"
import { toast } from "sonner"
import { useRouter } from "next/navigation"
import { useTranslations } from "next-intl"
import { Search, Info, AlertCircle } from "lucide-react"

import { Card, CardContent, CardHeader, CardTitle } from "@/shared/components/ui/card"
import { Button } from "@/shared/components/ui/button"
import { Input } from "@/shared/components/ui/input"
import { Label } from "@/shared/components/ui/label"
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/shared/components/ui/select"
import { Badge } from "@/shared/components/ui/badge"
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "@/shared/components/ui/table"
import { cn } from "@/shared/lib/utils"
import { safeActionCall } from "@/shared/lib/action-utils"

import { batchCreateGradeRecordsByExamAction, undoBatchCreateGradeRecordsAction } from "../actions"
import type { ExamOptionForEntry, ExamForGradeEntry } from "@/modules/exams/types"

type Student = { id: string; name: string; email: string }
type ClassOption = { id: string; name: string }

interface Props {
  exams: ExamOptionForEntry[]
  classes: ClassOption[]
  classGradeMap: Record<string, string>
  exam: ExamForGradeEntry | null
  students: Student[]
  defaultExamId?: string
  defaultClassId?: string
}

/** 序列化撤销数据 */
function serializeUndoData(ids: string[]): string {
  return JSON.stringify({ ids, timestamp: Date.now() })
}

export function BatchGradeEntryByExam({
  exams,
  classes,
  classGradeMap,
  exam,
  students,
  defaultExamId,
  defaultClassId,
}: Props): JSX.Element {
  const router = useRouter()
  const t = useTranslations("grades")
  const [scores, setScores] = useState<Record<string, Record<string, string>>>({})
  const [searchQuery, setSearchQuery] = useState("")
  const [isSubmitting, setIsSubmitting] = useState(false)
  const inputRefs = useRef<Record<string, HTMLInputElement | null>>({})

  // 按试卷 gradeId 过滤班级
  const filteredClasses = useMemo(() => {
    if (!exam?.gradeId) return classes
    return classes.filter((c) => classGradeMap[c.id] === exam.gradeId)
  }, [classes, classGradeMap, exam])

  // 过滤学生
  const filteredStudents = useMemo(() => {
    if (!searchQuery) return students
    const q = searchQuery.toLowerCase()
    return students.filter(
      (s) => s.name.toLowerCase().includes(q) || s.email.toLowerCase().includes(q)
    )
  }, [students, searchQuery])

  const handleExamChange = (examId: string): void => {
    if (Object.keys(scores).length > 0) {
      if (!window.confirm(t("batchByExam.confirmSwitchExam"))) return
    }
    setScores({})
    router.push(`/teacher/grades/entry?examId=${examId}`)
  }

  const handleClassChange = (classId: string): void => {
    if (Object.keys(scores).length > 0) {
      if (!window.confirm(t("batchByExam.confirmSwitchClass"))) return
    }
    setScores({})
    router.push(`/teacher/grades/entry?examId=${defaultExamId}&classId=${classId}`)
  }

  const handleScoreChange = (studentId: string, questionId: string, value: string): void => {
    setScores((prev) => ({
      ...prev,
      [studentId]: {
        ...(prev[studentId] ?? {}),
        [questionId]: value,
      },
    }))
  }

  // 计算学生总分
  const computeTotal = (studentId: string): number => {
    const studentScores = scores[studentId]
    if (!studentScores || !exam) return 0
    return exam.questions.reduce((sum, q) => {
      const raw = studentScores[q.id]
      if (raw === undefined || raw === "") return sum
      const n = parseFloat(raw)
      return sum + (isNaN(n) ? 0 : n)
    }, 0)
  }

  // 检查分数是否超出满分
  const isScoreInvalid = (studentId: string, questionId: string): boolean => {
    if (!exam) return false
    const question = exam.questions.find((q) => q.id === questionId)
    if (!question) return false
    const raw = scores[studentId]?.[questionId]
    if (raw === undefined || raw === "") return false
    const n = parseFloat(raw)
    if (isNaN(n)) return true
    return n < 0 || n > question.score
  }

  // 统计
  const stats = useMemo(() => {
    const entered = students.filter((s) => {
      if (!exam) return false
      const ss = scores[s.id]
      if (!ss) return false
      return exam.questions.every((q) => ss[q.id] !== undefined && ss[q.id] !== "")
    }).length
    const totals = students
      .map((s) => computeTotal(s.id))
      .filter((n) => n > 0)
    const avg = totals.length > 0 ? totals.reduce((a, b) => a + b, 0) / totals.length : 0
    const max = totals.length > 0 ? Math.max(...totals) : 0
    const min = totals.length > 0 ? Math.min(...totals) : 0
    return { entered, total: students.length, avg, max, min }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [scores, students, exam])

  // Excel 粘贴：支持多行多列
  const handlePaste = (e: ClipboardEvent, startStudentId: string, startQuestionId: string): void => {
    if (!exam) return
    const text = e.clipboardData.getData("text")
    const lines = text.split(/\r?\n/).filter((l) => l.trim())
    if (lines.length === 0) return

    const startStudentIdx = students.findIndex((s) => s.id === startStudentId)
    const startQuestionIdx = exam.questions.findIndex((q) => q.id === startQuestionId)
    if (startStudentIdx === -1 || startQuestionIdx === -1) return

    const newScores: Record<string, Record<string, string>> = {}
    let pastedCount = 0

    lines.forEach((line, lineIdx) => {
      const student = students[startStudentIdx + lineIdx]
      if (!student) return
      const cells = line.split(/\t/).filter((c) => c.trim() || c === "0")
      if (cells.length === 1) {
        // 单列：按行填充当前题目
        newScores[student.id] = {
          ...(newScores[student.id] ?? {}),
          [exam.questions[startQuestionIdx].id]: cells[0].trim(),
        }
        pastedCount++
      } else {
        // 多列：按行×列填充
        cells.forEach((cell, colIdx) => {
          const question = exam.questions[startQuestionIdx + colIdx]
          if (question) {
            newScores[student.id] = {
              ...(newScores[student.id] ?? {}),
              [question.id]: cell.trim(),
            }
          }
        })
        pastedCount++
      }
    })

    if (pastedCount > 0) {
      setScores((prev) => {
        const merged = { ...prev }
        for (const [sid, qs] of Object.entries(newScores)) {
          merged[sid] = { ...(merged[sid] ?? {}), ...qs }
        }
        return merged
      })
      e.preventDefault()
      toast.success(t("batchByExam.pasteApplied", { count: pastedCount }))
    }
  }

  // Enter 跳下一行同一列
  const handleKeyDown = (e: KeyboardEvent, studentId: string, questionId: string): void => {
    if (e.key === "Enter") {
      e.preventDefault()
      const studentIdx = students.findIndex((s) => s.id === studentId)
      const nextStudent = students[studentIdx + 1]
      if (nextStudent) {
        const ref = inputRefs.current[`${nextStudent.id}-${questionId}`]
        ref?.focus()
        ref?.select()
      }
    }
  }

  const hasInvalidScores = useMemo(() => {
    if (!exam) return false
    return students.some((s) =>
      exam.questions.some((q) => isScoreInvalid(s.id, q.id))
    )
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [scores, students, exam])

  const handleSubmit = async (): Promise<void> => {
    if (!exam || !defaultClassId || !defaultExamId) return
    if (hasInvalidScores) {
      toast.error(t("batchByExam.invalidScoresError"))
      return
    }

    const records = students
      .map((s) => {
        const studentScores = scores[s.id]
        if (!studentScores) return null
        const hasAny = exam.questions.some(
          (q) => studentScores[q.id] !== undefined && studentScores[q.id] !== ""
        )
        if (!hasAny) return null
        return {
          studentId: s.id,
          answers: exam.questions.map((q) => ({
            questionId: q.id,
            score: parseFloat(studentScores[q.id] ?? "0") || 0,
          })),
        }
      })
      .filter((r): r is NonNullable<typeof r> => r !== null)

    if (records.length === 0) {
      toast.error(t("batchByExam.enterAtLeastOne"))
      return
    }

    const formData = new FormData()
    formData.set("examId", defaultExamId)
    formData.set("classId", defaultClassId)
    formData.set("recordsJson", JSON.stringify(records))

    setIsSubmitting(true)
    const result = await safeActionCall(
      () => batchCreateGradeRecordsByExamAction(null, formData),
      {
        onError: () => toast.error(t("error.saveFailed")),
        onFinally: () => setIsSubmitting(false),
      }
    )

    if (result?.success) {
      setScores({})
      const createdIds = result.data ?? []
      if (createdIds.length > 0) {
        try {
          sessionStorage.setItem(
            "lastBatchGradeRecordIds",
            serializeUndoData(createdIds)
          )
        } catch {
          // sessionStorage 不可用时静默失败
        }
        toast.success(result.message, {
          duration: 10000,
          action: {
            label: t("batchByExam.undo"),
            onClick: () => handleUndo(),
          },
        })
      } else {
        toast.success(result.message)
      }
      router.push("/teacher/grades")
      router.refresh()
    } else if (result) {
      toast.error(result.message || t("error.saveFailed"))
    }
  }

  const handleUndo = async (): Promise<void> => {
    try {
      const raw = sessionStorage.getItem("lastBatchGradeRecordIds")
      if (!raw) {
        toast.error(t("batchByExam.undoNoRecord"))
        return
      }
      const data = JSON.parse(raw) as { ids: string[]; timestamp: number }
      if (Date.now() - data.timestamp > 5 * 60 * 1000) {
        toast.error(t("batchByExam.undoExpired"))
        return
      }
      const result = await undoBatchCreateGradeRecordsAction(data.ids)
      if (result.success) {
        sessionStorage.removeItem("lastBatchGradeRecordIds")
        toast.success(result.message)
        router.refresh()
      } else {
        toast.error(result.message || t("batchByExam.undoFailed"))
      }
    } catch {
      toast.error(t("batchByExam.undoFailed"))
    }
  }

  // 未选试卷
  if (!exam) {
    return (
      <Card className="shadow-none">
        <CardHeader>
          <CardTitle className="text-base">{t("batchByExam.selectExam")}</CardTitle>
        </CardHeader>
        <CardContent className="space-y-4">
          <div className="space-y-2">
            <Label>{t("batchByExam.selectExam")}</Label>
            <Select onValueChange={handleExamChange}>
              <SelectTrigger>
                <SelectValue placeholder={t("batchByExam.selectExamPlaceholder")} />
              </SelectTrigger>
              <SelectContent>
                {exams.map((e) => (
                  <SelectItem key={e.id} value={e.id}>
                    {e.title}（{e.subjectName} · {e.questionCount}题 · {e.totalScore}分）
                  </SelectItem>
                ))}
              </SelectContent>
            </Select>
          </div>
          <div className="flex items-start gap-2 rounded-md bg-muted/50 p-3 text-sm text-muted-foreground">
            <Info className="mt-0.5 h-4 w-4 shrink-0" />
            <span>{t("batchByExam.guideSelectExam")}</span>
          </div>
        </CardContent>
      </Card>
    )
  }

  return (
    <div className="space-y-6">
      {/* 试卷 + 班级选择器 */}
      <Card className="shadow-none">
        <CardHeader>
          <CardTitle className="text-base">{t("batchByExam.title")}</CardTitle>
        </CardHeader>
        <CardContent className="grid gap-4 md:grid-cols-2">
          <div className="space-y-2">
            <Label>{t("batchByExam.selectExam")}</Label>
            <Select value={defaultExamId} onValueChange={handleExamChange}>
              <SelectTrigger>
                <SelectValue placeholder={t("batchByExam.selectExamPlaceholder")} />
              </SelectTrigger>
              <SelectContent>
                {exams.map((e) => (
                  <SelectItem key={e.id} value={e.id}>
                    {e.title}（{e.subjectName} · {e.questionCount}题）
                  </SelectItem>
                ))}
              </SelectContent>
            </Select>
          </div>
          <div className="space-y-2">
            <Label>{t("batchByExam.selectClass")}</Label>
            <Select value={defaultClassId} onValueChange={handleClassChange}>
              <SelectTrigger>
                <SelectValue placeholder={t("batchByExam.selectClassPlaceholder")} />
              </SelectTrigger>
              <SelectContent>
                {filteredClasses.map((c) => (
                  <SelectItem key={c.id} value={c.id}>
                    {c.name}
                  </SelectItem>
                ))}
              </SelectContent>
            </Select>
          </div>
          {/* 试卷信息 */}
          <div className="md:col-span-2 flex flex-wrap gap-2 text-sm">
            <Badge variant="secondary">
              {t("batchByExam.questionCount", { count: exam.questions.length })}
            </Badge>
            <Badge variant="secondary">
              {t("batchByExam.fullScore", { score: exam.totalScore })}
            </Badge>
          </div>
        </CardContent>
      </Card>

      {/* 未选班级 */}
      {!defaultClassId ? (
        <Card className="shadow-none">
          <CardContent className="py-8 text-center text-muted-foreground">
            {t("batchByExam.selectClassFirst")}
          </CardContent>
        </Card>
      ) : students.length === 0 ? (
        <Card className="shadow-none">
          <CardContent className="py-8 text-center text-muted-foreground">
            {t("batchByExam.noStudents")}
          </CardContent>
        </Card>
      ) : (
        <>
          {/* 统计栏 */}
          <div className="flex flex-wrap items-center gap-4">
            <Badge variant="outline" className="tabular-nums">
              {t("batchByExam.entered")}: {stats.entered}/{stats.total}
            </Badge>
            {stats.entered > 0 && (
              <>
                <Badge variant="outline" className="tabular-nums">
                  {t("batchByExam.average")}: {Math.round(stats.avg * 10) / 10}
                </Badge>
                <Badge variant="outline" className="tabular-nums">
                  {t("batchByExam.max")}: {stats.max}
                </Badge>
                <Badge variant="outline" className="tabular-nums">
                  {t("batchByExam.min")}: {stats.min}
                </Badge>
              </>
            )}
            {hasInvalidScores && (
              <Badge variant="destructive">
                <AlertCircle className="mr-1 h-3 w-3" />
                {t("batchByExam.invalidScoresBadge")}
              </Badge>
            )}
            <div className="relative ml-auto">
              <Search className="absolute left-2 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" />
              <Input
                placeholder={t("batchByExam.searchStudent")}
                value={searchQuery}
                onChange={(e) => setSearchQuery(e.target.value)}
                className="h-8 w-48 pl-8"
              />
            </div>
          </div>

          {/* Excel 式表格 */}
          <Card className="shadow-none">
            <CardContent className="p-0">
              <div className="overflow-x-auto">
                <Table>
                  <TableHeader>
                    <TableRow className="bg-muted/50">
                      <TableHead className="w-12 text-center">#</TableHead>
                      <TableHead className="min-w-[120px]">{t("batchByExam.studentName")}</TableHead>
                      {exam.questions.map((q, idx) => (
                        <TableHead key={q.id} className="text-center min-w-[80px]">
                          <div className="font-medium">{t("batchByExam.question", { n: idx + 1 })}</div>
                          <div className="text-xs text-muted-foreground tabular-nums">({q.score}{t("batchByExam.points")})</div>
                        </TableHead>
                      ))}
                      <TableHead className="text-center min-w-[80px]">{t("batchByExam.totalScore")}</TableHead>
                    </TableRow>
                  </TableHeader>
                  <TableBody>
                    {filteredStudents.map((s, sIdx) => {
                      const total = computeTotal(s.id)
                      return (
                        <TableRow key={s.id}>
                          <TableCell className="text-center text-muted-foreground tabular-nums">{sIdx + 1}</TableCell>
                          <TableCell className="font-medium">{s.name}</TableCell>
                          {exam.questions.map((q) => {
                            const invalid = isScoreInvalid(s.id, q.id)
                            const key = `${s.id}-${q.id}`
                            return (
                              <TableCell key={q.id} className="p-1">
                                <Input
                                  ref={(el) => { inputRefs.current[key] = el }}
                                  type="number"
                                  step="0.5"
                                  min="0"
                                  max={q.score}
                                  value={scores[s.id]?.[q.id] ?? ""}
                                  onChange={(e) => handleScoreChange(s.id, q.id, e.target.value)}
                                  onKeyDown={(e) => handleKeyDown(e, s.id, q.id)}
                                  onPaste={(e) => handlePaste(e, s.id, q.id)}
                                  onFocus={(e) => e.target.select()}
                                  className={cn(
                                    "h-8 text-center tabular-nums",
                                    invalid && "border-destructive focus-visible:ring-destructive"
                                  )}
                                  aria-label={`${s.name} - ${t("batchByExam.question", { n: exam.questions.findIndex(qq => qq.id === q.id) + 1 })}`}
                                />
                              </TableCell>
                            )
                          })}
                          <TableCell className="text-center font-medium tabular-nums">
                            {Math.round(total * 10) / 10}
                          </TableCell>
                        </TableRow>
                      )
                    })}
                  </TableBody>
                </Table>
              </div>
            </CardContent>
          </Card>

          {/* 提交按钮 */}
          <div className="flex items-center justify-end gap-3">
            <Button
              type="button"
              variant="outline"
              onClick={() => setScores({})}
              disabled={isSubmitting}
            >
              {t("batchByExam.clear")}
            </Button>
            <Button
              type="button"
              onClick={handleSubmit}
              disabled={isSubmitting || hasInvalidScores}
            >
              {isSubmitting ? t("batchByExam.saving") : t("batchByExam.saveAll")}
            </Button>
          </div>

          {/* 提示 */}
          <div className="flex items-start gap-2 rounded-md bg-muted/50 p-3 text-sm text-muted-foreground">
            <Info className="mt-0.5 h-4 w-4 shrink-0" />
            <span>{t("batchByExam.pasteHint")}</span>
          </div>
        </>
      )}
    </div>
  )
}
