"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 { Info } from "lucide-react"

import { Card, CardContent, CardHeader, CardTitle } from "@/shared/components/ui/card"
import { Button } from "@/shared/components/ui/button"
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 { safeActionCall } from "@/shared/lib/action-utils"

import { batchCreateGradeRecordsByExamAction } from "../actions"
import { useBatchGradeEntryUndo } from "../hooks/use-batch-grade-entry-undo"
import { BatchGradeEntryStats } from "./batch-grade-entry-stats"
import { BatchGradeEntryDialog, type PendingSwitch } from "./batch-grade-entry-dialog"
import { BatchGradeEntryTable } from "./batch-grade-entry-table"
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
}

/**
 * 按试卷批量录入成绩主组件。
 *
 * P1-6 重构：将表格、统计栏、确认对话框拆分为独立子组件。
 * - useBatchGradeEntryUndo Hook 封装撤销逻辑 + 类型守卫（P1-7 修复 `as` 断言）
 * - BatchGradeEntryTable / BatchGradeEntryStats / BatchGradeEntryDialog 为组合子组件
 */
export function BatchGradeEntryByExam({
  exams,
  classes,
  classGradeMap,
  exam,
  students,
  defaultExamId,
  defaultClassId,
}: Props): JSX.Element {
  const router = useRouter()
  const t = useTranslations("grades")
  const { saveUndoToken, handleUndo } = useBatchGradeEntryUndo()
  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>>({})
  const [pendingSwitch, setPendingSwitch] = useState<PendingSwitch>(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) {
      setPendingSwitch({
        kind: "exam",
        examId,
        message: t("batchByExam.confirmSwitchExam"),
      })
      return
    }
    setScores({})
    router.push(`/teacher/grades/entry?examId=${examId}`)
  }

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

  const confirmPendingSwitch = (): void => {
    if (!pendingSwitch) return
    setScores({})
    if (pendingSwitch.kind === "exam") {
      router.push(`/teacher/grades/entry?examId=${pendingSwitch.examId}`)
    } else {
      router.push(`/teacher/grades/entry?examId=${defaultExamId}&classId=${pendingSwitch.classId}`)
    }
    setPendingSwitch(null)
  }

  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) {
        saveUndoToken(createdIds)
        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"))
    }
  }

  // 未选试卷
  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>
      ) : (
        <>
          {/* 统计栏 */}
          <BatchGradeEntryStats
            stats={stats}
            hasInvalidScores={hasInvalidScores}
            searchQuery={searchQuery}
            onSearchChange={setSearchQuery}
          />

          {/* Excel 式表格 */}
          <BatchGradeEntryTable
            exam={exam}
            students={filteredStudents}
            scores={scores}
            inputRefs={inputRefs}
            onScoreChange={handleScoreChange}
            onKeyDown={handleKeyDown}
            onPaste={handlePaste}
            computeTotal={computeTotal}
            isScoreInvalid={isScoreInvalid}
          />

          {/* 提交按钮 */}
          <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>
        </>
      )}

      {/* 确认对话框 */}
      <BatchGradeEntryDialog
        pendingSwitch={pendingSwitch}
        onConfirm={confirmPendingSwitch}
        onCancel={() => setPendingSwitch(null)}
      />
    </div>
  )
}
