"use client"

import { ChevronLeft, ChevronRight } from "lucide-react"
import { useState, useRef, type KeyboardEvent } from "react"
import { useTranslations } from "next-intl"

import { Card, CardContent, CardHeader, CardTitle } from "@/shared/components/ui/card"
import { cn } from "@/shared/lib/utils"
import {
  ATTENDANCE_STATUS_DOT_COLORS,
  ATTENDANCE_STATUS_LABEL_KEYS,
} from "@/modules/attendance/constants"
import type {
  ParentAttendanceListItem,
  ParentAttendanceStatus,
  ParentStudentAttendanceSummary,
} from "@/modules/parent/types"

const WEEKDAY_KEYS = [
  "parent.weekday.sun",
  "parent.weekday.mon",
  "parent.weekday.tue",
  "parent.weekday.wed",
  "parent.weekday.thu",
  "parent.weekday.fri",
  "parent.weekday.sat",
] as const

/**
 * 格式化日期为 `YYYY-MM-DD`（纯函数，便于测试）。
 */
export function formatDateKey(d: Date): string {
  const y = d.getFullYear()
  const m = String(d.getMonth() + 1).padStart(2, "0")
  const day = String(d.getDate()).padStart(2, "0")
  return `${y}-${m}-${day}`
}

/**
 * 解析 `YYYY-MM-DD` 为 Date（纯函数，便于测试）。
 */
export function parseDateKey(key: string): Date | null {
  const parts = key.split("-")
  if (parts.length !== 3) return null
  const [y, m, d] = parts.map(Number)
  if (!y || !m || !d) return null
  return new Date(y, m - 1, d)
}

/**
 * 构建日历单元格（纯函数，便于测试）。
 */
export function buildCalendarDays(year: number, month: number): Array<Date | null> {
  const firstDay = new Date(year, month, 1)
  const lastDay = new Date(year, month + 1, 0)
  const startWeekday = firstDay.getDay()
  const totalDays = lastDay.getDate()
  const cells: Array<Date | null> = []
  for (let i = 0; i < startWeekday; i += 1) cells.push(null)
  for (let day = 1; day <= totalDays; day += 1) {
    cells.push(new Date(year, month, day))
  }
  while (cells.length % 7 !== 0) cells.push(null)
  return cells
}

/**
 * 判断两个日期是否为同一天（纯函数，便于测试）。
 */
export function isSameDay(a: Date, b: Date): boolean {
  return (
    a.getFullYear() === b.getFullYear() &&
    a.getMonth() === b.getMonth() &&
    a.getDate() === b.getDate()
  )
}

/**
 * 家长视角的考勤月历视图。
 * 基于子女的近期考勤记录，在月历上按状态着色，让家长直观看到出勤分布。
 * 支持键盘方向键导航（a11y）：← → ↑ ↓ 在日期格子间移动，Home/End 跳至行首/尾。
 */
export function ParentAttendanceCalendar({
  summary,
}: {
  summary: ParentStudentAttendanceSummary
}) {
  const t = useTranslations("attendance")
  const now = new Date()
  const [viewYear, setViewYear] = useState(now.getFullYear())
  const [viewMonth, setViewMonth] = useState(now.getMonth())
  const [focusedIdx, setFocusedIdx] = useState<number>(-1)
  const gridRef = useRef<HTMLDivElement>(null)

  const recordMap = new Map<string, ParentAttendanceListItem>()
  for (const r of summary.recentRecords) {
    const d = parseDateKey(r.date)
    if (d) recordMap.set(formatDateKey(d), r)
  }

  const days = buildCalendarDays(viewYear, viewMonth)
  const monthLabel = new Date(viewYear, viewMonth, 1).toLocaleDateString("en-US", {
    year: "numeric",
    month: "long",
  })

  const goPrev = () => {
    if (viewMonth === 0) {
      setViewMonth(11)
      setViewYear((y) => y - 1)
    } else {
      setViewMonth((m) => m - 1)
    }
    setFocusedIdx(-1)
  }
  const goNext = () => {
    if (viewMonth === 11) {
      setViewMonth(0)
      setViewYear((y) => y + 1)
    } else {
      setViewMonth((m) => m + 1)
    }
    setFocusedIdx(-1)
  }

  /**
   * 键盘导航：方向键在日期格子间移动，Home/End 跳至行首/尾。
   * 仅在非空格子（有 Date 的格子）间移动，跳过 null 占位。
   */
  const handleKeyDown = (e: KeyboardEvent<HTMLDivElement>) => {
    if (focusedIdx < 0) return
    const nonNullIndices = days
      .map((d, i) => (d ? i : -1))
      .filter((i) => i >= 0)
    const currentPos = nonNullIndices.indexOf(focusedIdx)
    if (currentPos < 0) return

    const cols = 7
    const currentRow = Math.floor(currentPos / cols)
    const currentCol = currentPos % cols
    let nextPos = currentPos

    switch (e.key) {
      case "ArrowRight":
        nextPos = Math.min(currentPos + 1, nonNullIndices.length - 1)
        break
      case "ArrowLeft":
        nextPos = Math.max(currentPos - 1, 0)
        break
      case "ArrowDown": {
        const target = (currentRow + 1) * cols + currentCol
        nextPos = target < nonNullIndices.length ? target : currentPos
        break
      }
      case "ArrowUp": {
        const target = (currentRow - 1) * cols + currentCol
        nextPos = target >= 0 ? target : currentPos
        break
      }
      case "Home":
        nextPos = currentRow * cols
        break
      case "End":
        nextPos = Math.min((currentRow + 1) * cols - 1, nonNullIndices.length - 1)
        break
      default:
        return
    }

    e.preventDefault()
    const nextIdx = nonNullIndices[nextPos]
    if (nextIdx !== undefined && nextIdx !== focusedIdx) {
      setFocusedIdx(nextIdx)
      const cell = gridRef.current?.querySelector<HTMLElement>(`[data-day-idx="${nextIdx}"]`)
      cell?.focus()
    }
  }

  const usedStatuses = new Set<ParentAttendanceStatus>()
  for (const r of recordMap.values()) usedStatuses.add(r.status)

  return (
    <Card aria-label={t("parent.calendarTitle", { name: summary.studentName })}>
      <CardHeader className="pb-2">
        <CardTitle className="flex items-center justify-between text-base">
          <span>{t("parent.calendarFor", { name: summary.studentName })}</span>
          <div className="flex items-center gap-1">
            <button
              type="button"
              onClick={goPrev}
              aria-label={t("parent.prevMonth")}
              className="inline-flex h-8 w-8 items-center justify-center rounded-md hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
            >
              <ChevronLeft className="h-4 w-4" />
            </button>
            <span className="min-w-[120px] text-center text-sm font-medium">{monthLabel}</span>
            <button
              type="button"
              onClick={goNext}
              aria-label={t("parent.nextMonth")}
              className="inline-flex h-8 w-8 items-center justify-center rounded-md hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
            >
              <ChevronRight className="h-4 w-4" />
            </button>
          </div>
        </CardTitle>
      </CardHeader>
      <CardContent className="space-y-3">
        <div className="grid grid-cols-7 gap-1 text-center text-xs font-medium text-muted-foreground">
          {WEEKDAY_KEYS.map((key) => (
            <div key={key} className="py-1">
              {t(key)}
            </div>
          ))}
        </div>
        <div
          ref={gridRef}
          className="grid grid-cols-7 gap-1"
          onKeyDown={handleKeyDown}
          role="grid"
          aria-label={monthLabel}
        >
          {days.map((d, idx) => {
            if (!d) return <div key={`empty-${idx}`} className="aspect-square" />
            const key = formatDateKey(d)
            const record = recordMap.get(key)
            const isToday = isSameDay(d, now)
            const isFocused = focusedIdx === idx
            return (
              <div
                key={key}
                data-day-idx={idx}
                tabIndex={isFocused || (focusedIdx < 0 && isToday) ? 0 : -1}
                onFocus={() => setFocusedIdx(idx)}
                className={cn(
                  "relative flex aspect-square flex-col items-center justify-center rounded-md border text-xs",
                  "min-h-[36px] cursor-default",
                  record ? "border-border bg-muted/30" : "border-transparent",
                  isToday && "ring-2 ring-primary ring-offset-1",
                  "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
                )}
                role="gridcell"
                aria-label={
                  record
                    ? `${formatDateKey(d)}: ${t(ATTENDANCE_STATUS_LABEL_KEYS[record.status])}`
                    : formatDateKey(d)
                }
                aria-selected={isFocused}
              >
                <span className="tabular-nums">{d.getDate()}</span>
                {record ? (
                  <span
                    className={cn(
                      "mt-0.5 h-1.5 w-1.5 rounded-full",
                      ATTENDANCE_STATUS_DOT_COLORS[record.status],
                    )}
                    aria-hidden
                  />
                ) : null}
              </div>
            )
          })}
        </div>
        {usedStatuses.size > 0 ? (
          <div className="flex flex-wrap items-center gap-3 pt-1 text-xs text-muted-foreground">
            {Array.from(usedStatuses).map((status) => (
              <span key={status} className="inline-flex items-center gap-1.5">
                <span
                  className={cn("h-2 w-2 rounded-full", ATTENDANCE_STATUS_DOT_COLORS[status])}
                  aria-hidden
                />
                {t(ATTENDANCE_STATUS_LABEL_KEYS[status])}
              </span>
            ))}
          </div>
        ) : null}
      </CardContent>
    </Card>
  )
}
