"use client"

import { useState, useRef, useEffect, useCallback, useMemo } from "react"
import { useFormStatus } from "react-dom"
import { toast } from "sonner"
import { useRouter } from "next/navigation"
import { useTranslations } from "next-intl"
import { CalendarDays, Search, CheckCircle2, XCircle, Clock, LogOut, FileText, School } from "lucide-react"

import { Card, CardContent, CardFooter, 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 {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "@/shared/components/ui/table"
import {
  AlertDialog,
  AlertDialogAction,
  AlertDialogCancel,
  AlertDialogContent,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogHeader,
  AlertDialogTitle,
} from "@/shared/components/ui/alert-dialog"
import { cn } from "@/shared/lib/utils"
import { resolveActionError } from "@/shared/lib/resolve-action-error"

import { batchRecordAttendanceAction } from "../actions"
import {
  ATTENDANCE_STATUS_OPTIONS,
  ATTENDANCE_STATUS_SHORTCUTS,
  ATTENDANCE_STATUS_LABEL_KEYS,
  createInitialStatusCounts,
  type AttendanceStatus,
} from "../constants"
import type { AttendancePeriod } from "../types"

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

/** L-6：节次选项（顺序即选择器中的展示顺序）。 */
const ATTENDANCE_PERIOD_OPTIONS: AttendancePeriod[] = [
  "full_day",
  "morning_reading",
  "morning",
  "afternoon",
  "evening",
]

/** L-6：节次对应的 i18n key 后缀。 */
const ATTENDANCE_PERIOD_LABEL_KEYS: Record<AttendancePeriod, string> = {
  full_day: "period.full_day",
  morning_reading: "period.morning_reading",
  morning: "period.morning",
  afternoon: "period.afternoon",
  evening: "period.evening",
}

const STATUS_STYLES: Record<AttendanceStatus, { active: string; icon: typeof CheckCircle2 }> = {
  present: { active: "bg-emerald-500 text-white border-emerald-500 hover:bg-emerald-600", icon: CheckCircle2 },
  absent: { active: "bg-red-500 text-white border-red-500 hover:bg-red-600", icon: XCircle },
  late: { active: "bg-amber-500 text-white border-amber-500 hover:bg-amber-600", icon: Clock },
  early_leave: { active: "bg-blue-500 text-white border-blue-500 hover:bg-blue-600", icon: LogOut },
  excused: { active: "bg-purple-500 text-white border-purple-500 hover:bg-purple-600", icon: FileText },
  school_activity: { active: "bg-cyan-500 text-white border-cyan-500 hover:bg-cyan-600", icon: School },
}

/** 需要填写原因的状态（缺勤/迟到/早退/请假/校内活动）。 */
const STATUSES_REQUIRING_REASON: ReadonlySet<AttendanceStatus> = new Set([
  "absent",
  "late",
  "early_leave",
  "excused",
  "school_activity",
])

function SubmitButton() {
  const { pending } = useFormStatus()
  const t = useTranslations("attendance")
  return (
    <Button type="submit" disabled={pending}>
      {pending ? t("actions.save") + "..." : t("actions.save")}
    </Button>
  )
}

export function AttendanceSheet({
  classes,
  students,
  defaultClassId,
  defaultDate,
}: {
  classes: Option[]
  students: Student[]
  defaultClassId?: string
  defaultDate?: string
}) {
  const router = useRouter()
  const t = useTranslations("attendance")
  const today = new Date().toISOString().slice(0, 10)
  const [classId, setClassId] = useState(defaultClassId ?? classes[0]?.id ?? "")
  const [date, setDate] = useState(defaultDate ?? today)
  // L-6：节次默认 full_day（向后兼容已有数据）
  const [period, setPeriod] = useState<AttendancePeriod>("full_day")
  const [statuses, setStatuses] = useState<Record<string, AttendanceStatus>>({})
  const [reasons, setReasons] = useState<Record<string, string>>({})
  const [searchQuery, setSearchQuery] = useState("")
  const [focusedStudentIndex, setFocusedStudentIndex] = useState(0)
  const [isSubmitting, setIsSubmitting] = useState(false)
  const [showSwitchConfirm, setShowSwitchConfirm] = useState(false)
  const [pendingClassId, setPendingClassId] = useState<string | null>(null)
  const studentRefs = useRef<(HTMLTableRowElement | null)[]>([])
  const containerRef = useRef<HTMLDivElement>(null)

  const handleStatusChange = useCallback((studentId: string, status: AttendanceStatus) => {
    setStatuses((prev) => ({ ...prev, [studentId]: status }))
    // 切回 present 时清除原因（present 不需要原因）
    if (status === "present") {
      setReasons((prev) => {
        if (!prev[studentId]) return prev
        const next = { ...prev }
        delete next[studentId]
        return next
      })
    }
  }, [])

  const handleReasonChange = useCallback((studentId: string, reason: string) => {
    setReasons((prev) => ({ ...prev, [studentId]: reason }))
  }, [])

  const markAllPresent = useCallback(() => {
    const all: Record<string, AttendanceStatus> = {}
    for (const s of students) all[s.id] = "present"
    setStatuses(all)
    setReasons({})
    toast.success(t("actions.markAllPresent"))
  }, [students, t])

  const handleClassChange = (newClassId: string) => {
    const hasUnsaved = Object.keys(statuses).length > 0
    if (hasUnsaved && newClassId !== classId) {
      setPendingClassId(newClassId)
      setShowSwitchConfirm(true)
      return
    }
    confirmClassSwitch(newClassId)
  }

  const confirmClassSwitch = (newClassId: string) => {
    setClassId(newClassId)
    setStatuses({})
    setReasons({})
    const newUrl = newClassId ? `/teacher/attendance/sheet?classId=${encodeURIComponent(newClassId)}` : "/teacher/attendance/sheet"
    router.push(newUrl)
  }

  const filteredStudents = students.filter(
    (s) => !searchQuery || s.name.toLowerCase().includes(searchQuery.toLowerCase())
  )

  const statusCounts = useMemo(
    () =>
      ATTENDANCE_STATUS_OPTIONS.reduce(
        (acc, st) => {
          acc[st] = students.filter((s) => (statuses[s.id] ?? "present") === st).length
          return acc
        },
        createInitialStatusCounts()
      ),
    [students, statuses]
  )

  // 派生值：当筛选结果变少时，焦点索引自动夹紧到有效范围，避免 useEffect 重置导致的级联渲染
  const effectiveFocusedIndex = filteredStudents.length === 0
    ? 0
    : Math.min(focusedStudentIndex, filteredStudents.length - 1)

  useEffect(() => {
    const container = containerRef.current
    if (!container) return
    const handleKeyDown = (e: KeyboardEvent) => {
      // P2-7 修复：限制监听范围到容器内，并排除所有可交互元素
      const target = e.target
      if (
        target instanceof HTMLInputElement ||
        target instanceof HTMLTextAreaElement ||
        target instanceof HTMLSelectElement ||
        (target instanceof HTMLElement && target.isContentEditable)
      ) {
        return
      }
      const key = e.key.toLowerCase()
      if (ATTENDANCE_STATUS_SHORTCUTS[key] && filteredStudents[effectiveFocusedIndex]) {
        e.preventDefault()
        handleStatusChange(filteredStudents[effectiveFocusedIndex].id, ATTENDANCE_STATUS_SHORTCUTS[key])
        if (effectiveFocusedIndex < filteredStudents.length - 1) {
          setFocusedStudentIndex((prev) => prev + 1)
        }
      }
      if (e.key === "ArrowDown" && effectiveFocusedIndex < filteredStudents.length - 1) {
        e.preventDefault()
        setFocusedStudentIndex((prev) => prev + 1)
      }
      if (e.key === "ArrowUp" && effectiveFocusedIndex > 0) {
        e.preventDefault()
        setFocusedStudentIndex((prev) => prev - 1)
      }
    }
    container.addEventListener("keydown", handleKeyDown)
    return () => container.removeEventListener("keydown", handleKeyDown)
  }, [filteredStudents, effectiveFocusedIndex, handleStatusChange])

  useEffect(() => {
    studentRefs.current[effectiveFocusedIndex]?.scrollIntoView({ block: "nearest" })
  }, [effectiveFocusedIndex])

  const handleSubmit = async (formData: FormData) => {
    if (!classId || !date) {
      toast.error(t("errors.invalidForm"))
      return
    }

    const records = students.map((s) => {
      const status = statuses[s.id] ?? "present"
      return {
        studentId: s.id,
        classId,
        date,
        status,
        // L-6：节次考勤，提交时携带当前选中的节次
        period,
        // 仅当状态需要原因且原因非空时携带（present 不需要原因）
        reason:
          STATUSES_REQUIRING_REASON.has(status) && reasons[s.id]
            ? reasons[s.id].slice(0, 255)
            : undefined,
      }
    })

    if (records.length === 0) {
      toast.error(t("sheet.noStudents"))
      return
    }

    setIsSubmitting(true)
    formData.set("recordsJson", JSON.stringify(records))

    try {
      const result = await batchRecordAttendanceAction(null, formData)
      if (result.success) {
        toast.success(result.message || t("sheet.saved"))
        router.push("/teacher/attendance")
        router.refresh()
      } else {
        toast.error(resolveActionError(result, t, t("errors.unexpected")))
      }
    } catch {
      toast.error(t("errors.unexpected"))
    } finally {
      setIsSubmitting(false)
    }
  }

  return (
    <Card className="relative">
      {isSubmitting && (
        <div className="absolute inset-0 z-10 flex items-center justify-center rounded-lg bg-background/60 backdrop-blur-sm">
          <div className="flex items-center gap-2 text-sm font-medium">
            <div className="h-4 w-4 animate-spin rounded-full border-2 border-primary border-t-transparent" />
            {t("sheet.saving")}
          </div>
        </div>
      )}
      <CardHeader>
        <CardTitle>{t("title.sheet")}</CardTitle>
        <p className="text-sm text-muted-foreground">
          {t("description.teacherRecords")}
        </p>
      </CardHeader>
      <CardContent>
        <form action={handleSubmit} className="space-y-6">
          <div className="grid grid-cols-1 gap-4 md:grid-cols-3">
            <div className="grid gap-2">
              <Label htmlFor="class-select">{t("filters.class")}</Label>
              <Select value={classId} onValueChange={handleClassChange}>
                <SelectTrigger id="class-select">
                  <SelectValue placeholder={t("sheet.selectClass")} />
                </SelectTrigger>
                <SelectContent>
                  {classes.map((c) => (
                    <SelectItem key={c.id} value={c.id}>
                      {c.name}
                    </SelectItem>
                  ))}
                </SelectContent>
              </Select>
            </div>

            <div className="grid gap-2">
              <Label htmlFor="date">{t("filters.date")}</Label>
              <div className="relative">
                <CalendarDays className="pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" />
                <Input
                  id="date"
                  type="date"
                  value={date}
                  onChange={(e) => setDate(e.target.value)}
                  className="pl-9"
                  required
                  aria-label={t("filters.date")}
                />
              </div>
            </div>

            {/* L-6：节次选择器，允许按节次记录考勤 */}
            <div className="grid gap-2">
              <Label htmlFor="period-select">{t("period.label")}</Label>
              <Select value={period} onValueChange={(v) => setPeriod(v as AttendancePeriod)}>
                <SelectTrigger id="period-select">
                  <SelectValue placeholder={t("period.label")} />
                </SelectTrigger>
                <SelectContent>
                  {ATTENDANCE_PERIOD_OPTIONS.map((p) => (
                    <SelectItem key={p} value={p}>
                      {t(ATTENDANCE_PERIOD_LABEL_KEYS[p])}
                    </SelectItem>
                  ))}
                </SelectContent>
              </Select>
            </div>
          </div>

          {students.length === 0 ? (
            <p className="text-sm text-muted-foreground">
              {t("sheet.noStudents")}
            </p>
          ) : (
            <>
              <div className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
                <div className="flex flex-wrap items-center gap-2">
                  {ATTENDANCE_STATUS_OPTIONS.map((st) => {
                    const Icon = STATUS_STYLES[st].icon
                    return (
                      <span key={st} className="inline-flex items-center gap-1 rounded-md border bg-muted/50 px-2 py-1 text-xs">
                        <Icon className="h-3 w-3" aria-hidden="true" />
                        {t(ATTENDANCE_STATUS_LABEL_KEYS[st])}
                        <span className="font-semibold tabular-nums">{statusCounts[st]}</span>
                      </span>
                    )
                  })}
                </div>
                <div className="flex items-center gap-2">
                  <div className="relative">
                    <Search className="pointer-events-none absolute left-2.5 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-muted-foreground" />
                    <Input
                      type="search"
                      placeholder={t("list.columns.student")}
                      value={searchQuery}
                      onChange={(e) => setSearchQuery(e.target.value)}
                      className="h-8 w-40 pl-8 text-sm"
                      aria-label={t("list.columns.student")}
                    />
                  </div>
                  <Button type="button" variant="outline" size="sm" onClick={markAllPresent}>
                    {t("actions.markAllPresent")}
                  </Button>
                </div>
              </div>
              <div ref={containerRef} className="rounded-md border" tabIndex={-1}>
                <Table>
                  <TableHeader>
                    <TableRow>
                      <TableHead className="w-12">#</TableHead>
                      <TableHead>{t("list.columns.student")}</TableHead>
                      <TableHead className="hidden md:table-cell">{t("list.columns.reason")}</TableHead>
                      <TableHead>{t("list.columns.status")}</TableHead>
                    </TableRow>
                  </TableHeader>
                  <TableBody>
                    {filteredStudents.map((s, idx) => {
                      const currentStatus = statuses[s.id] ?? "present"
                      const isFocused = idx === effectiveFocusedIndex
                      const needsReason = STATUSES_REQUIRING_REASON.has(currentStatus)
                      return (
                        <TableRow
                          key={s.id}
                          ref={(el) => { studentRefs.current[idx] = el }}
                          className={cn("cursor-pointer", isFocused && "bg-primary/5")}
                          onClick={() => setFocusedStudentIndex(idx)}
                          role="button"
                          tabIndex={isFocused ? 0 : -1}
                          aria-label={s.name}
                        >
                          <TableCell className="text-muted-foreground tabular-nums">{idx + 1}</TableCell>
                          <TableCell className="font-medium">
                            <div className="flex flex-col">
                              <span>{s.name}</span>
                              <span className="text-xs text-muted-foreground md:hidden">{s.email}</span>
                            </div>
                          </TableCell>
                          <TableCell className="hidden md:table-cell">
                            <Input
                              type="text"
                              value={reasons[s.id] ?? ""}
                              onChange={(e) => handleReasonChange(s.id, e.target.value)}
                              onClick={(e) => e.stopPropagation()}
                              disabled={!needsReason}
                              placeholder={needsReason ? t("sheet.reasonPlaceholder") : ""}
                              maxLength={255}
                              className="h-8 text-sm"
                              aria-label={t("list.columns.reason")}
                            />
                          </TableCell>
                          <TableCell>
                            <div className="flex flex-wrap gap-1">
                              {ATTENDANCE_STATUS_OPTIONS.map((st) => {
                                const Icon = STATUS_STYLES[st].icon
                                const isActive = currentStatus === st
                                return (
                                  <button
                                    key={st}
                                    type="button"
                                    onClick={(e) => {
                                      e.stopPropagation()
                                      handleStatusChange(s.id, st)
                                    }}
                                    className={cn(
                                      "inline-flex items-center gap-1 rounded-md border px-2 py-1 text-xs font-medium transition-colors",
                                      isActive
                                        ? STATUS_STYLES[st].active
                                        : "border-border bg-background text-muted-foreground hover:bg-muted"
                                    )}
                                    aria-pressed={isActive}
                                    aria-label={`${t(ATTENDANCE_STATUS_LABEL_KEYS[st])} (${st[0].toUpperCase()})`}
                                  >
                                    <Icon className="h-3 w-3" aria-hidden="true" />
                                    <span className="hidden sm:inline">{t(ATTENDANCE_STATUS_LABEL_KEYS[st])}</span>
                                    <span className="sm:hidden">{st[0].toUpperCase()}</span>
                                  </button>
                                )
                              })}
                            </div>
                          </TableCell>
                        </TableRow>
                      )
                    })}
                  </TableBody>
                </Table>
              </div>
            </>
          )}

          <CardFooter className="justify-end gap-2 px-0">
            <Button type="button" variant="outline" onClick={() => router.back()}>
              {t("actions.cancel")}
            </Button>
            <SubmitButton />
          </CardFooter>
        </form>
      </CardContent>

      <AlertDialog open={showSwitchConfirm} onOpenChange={setShowSwitchConfirm}>
        <AlertDialogContent>
          <AlertDialogHeader>
            <AlertDialogTitle>{t("sheet.confirmClassSwitch")}</AlertDialogTitle>
            <AlertDialogDescription>
              {t("sheet.confirmClassSwitch")}
            </AlertDialogDescription>
          </AlertDialogHeader>
          <AlertDialogFooter>
            <AlertDialogCancel>{t("actions.cancel")}</AlertDialogCancel>
            <AlertDialogAction
              onClick={() => {
                if (pendingClassId) {
                  confirmClassSwitch(pendingClassId)
                  setPendingClassId(null)
                }
                setShowSwitchConfirm(false)
              }}
            >
              {t("sheet.confirmClassSwitchAction")}
            </AlertDialogAction>
          </AlertDialogFooter>
        </AlertDialogContent>
      </AlertDialog>
    </Card>
  )
}
