"use client";

/**
 * MyAttendance — 我的考勤（ai14）
 *
 * 数据源：useMyAttendance GraphQL hook
 * 视图：
 *   - 顶部摘要：总天数 / 出勤 / 缺勤 / 迟到 / 出勤率
 *   - 日历网格：按月分组，每格显示当日状态颜色（present/absent/late）
 *   - 最近异常列表：缺勤与迟到记录明细
 *
 * 设计依据：01-understanding.md §7（my-attendance 视口）
 *          02-architecture-design.md §14.4（CSR）
 */

import { useMemo } from "react";
import { useMyAttendance } from "@/lib/graphql/hooks";
import type { AttendanceRecord, AttendanceStatus } from "@/lib/graphql/types";

const WEEKDAY_LABELS = ["日", "一", "二", "三", "四", "五", "六"];
const MONTH_NAMES = [
  "一月",
  "二月",
  "三月",
  "四月",
  "五月",
  "六月",
  "七月",
  "八月",
  "九月",
  "十月",
  "十一月",
  "十二月",
];

export default function MyAttendancePage(): JSX.Element {
  const { data, fetching, error } = useMyAttendance();
  const attendance = data ?? [];

  // 摘要统计
  const summary = useMemo(() => computeSummary(attendance), [attendance]);

  // 按月分组用于日历视图
  const monthlyGroups = useMemo(() => groupByMonth(attendance), [attendance]);

  return (
    <div className="px-6 lg:px-10 py-8 lg:py-10 max-w-7xl mx-auto">
      <header className="mb-6">
        <p
          className="text-xs uppercase tracking-wider"
          style={{ color: "var(--color-ink-muted)" }}
        >
          考勤档案
        </p>
        <h1
          className="mt-2 text-3xl lg:text-4xl font-serif"
          style={{ color: "var(--color-ink)" }}
        >
          我的考勤
        </h1>
        <p className="mt-2 text-sm" style={{ color: "var(--color-ink-muted)" }}>
          查看每日出勤情况，下方日历按状态着色，可追踪缺勤与迟到明细。
        </p>
      </header>

      <div className="rule-thin mb-8" />

      {fetching ? (
        <LoadingSkeleton />
      ) : error ? (
        <ErrorState message={error.message} />
      ) : attendance.length === 0 ? (
        <EmptyState />
      ) : (
        <>
          <SummaryStats summary={summary} />
          <div className="mt-8">
            <CalendarView monthlyGroups={monthlyGroups} />
          </div>
          <div className="mt-8">
            <AbnormalList attendance={attendance} />
          </div>
        </>
      )}
    </div>
  );
}

// === 顶部统计 ===
interface AttendanceSummary {
  total: number;
  present: number;
  absent: number;
  late: number;
  rate: number;
}

function computeSummary(items: AttendanceRecord[]): AttendanceSummary {
  let present = 0;
  let absent = 0;
  let late = 0;
  for (const it of items) {
    if (it.status === "present") present++;
    else if (it.status === "absent") absent++;
    else if (it.status === "late") late++;
  }
  const total = items.length;
  const rate = total === 0 ? 0 : present / total;
  return { total, present, absent, late, rate };
}

function SummaryStats({
  summary,
}: {
  summary: AttendanceSummary;
}): JSX.Element {
  return (
    <section
      aria-label="考勤摘要"
      className="grid grid-cols-2 lg:grid-cols-5 gap-4"
    >
      <StatTile label="总记录" value={String(summary.total)} suffix="天" />
      <StatTile
        label="出勤"
        value={String(summary.present)}
        suffix="天"
        tone="success"
      />
      <StatTile
        label="缺勤"
        value={String(summary.absent)}
        suffix="天"
        tone="danger"
      />
      <StatTile
        label="迟到"
        value={String(summary.late)}
        suffix="天"
        tone="warning"
      />
      <StatTile
        label="出勤率"
        value={`${(summary.rate * 100).toFixed(1)}%`}
        tone="accent"
      />
    </section>
  );
}

function StatTile({
  label,
  value,
  suffix,
  tone = "default",
}: {
  label: string;
  value: string;
  suffix?: string;
  tone?: "default" | "success" | "danger" | "warning" | "accent";
}): JSX.Element {
  const toneColor = (() => {
    switch (tone) {
      case "success":
        return "var(--color-success)";
      case "danger":
        return "var(--color-danger)";
      case "warning":
        return "var(--color-warning)";
      case "accent":
        return "var(--color-accent)";
      default:
        return "var(--color-ink)";
    }
  })();

  return (
    <div className="card-paper p-5">
      <p
        className="text-xs uppercase tracking-wider"
        style={{ color: "var(--color-ink-muted)" }}
      >
        {label}
      </p>
      <p
        className="mt-3 text-2xl lg:text-3xl font-serif"
        style={{ color: toneColor }}
      >
        {value}
        {suffix && (
          <span
            className="ml-1 text-xs font-sans"
            style={{ color: "var(--color-ink-muted)" }}
          >
            {suffix}
          </span>
        )}
      </p>
    </div>
  );
}

// === 日历网格视图 ===

interface MonthlyGroup {
  year: number;
  month: number; // 0-11
  items: AttendanceRecord[];
}

function groupByMonth(items: AttendanceRecord[]): MonthlyGroup[] {
  const map = new Map<string, MonthlyGroup>();
  for (const it of items) {
    const d = new Date(it.date);
    const key = `${d.getFullYear()}-${d.getMonth()}`;
    if (!map.has(key)) {
      map.set(key, {
        year: d.getFullYear(),
        month: d.getMonth(),
        items: [],
      });
    }
    map.get(key)!.items.push(it);
  }
  return Array.from(map.values()).sort(
    (a, b) => b.year - a.year || b.month - a.month,
  );
}

function CalendarView({
  monthlyGroups,
}: {
  monthlyGroups: MonthlyGroup[];
}): JSX.Element {
  return (
    <section aria-label="日历视图">
      <div className="space-y-8">
        {monthlyGroups.map((group) => (
          <MonthGrid key={`${group.year}-${group.month}`} group={group} />
        ))}
      </div>
    </section>
  );
}

function MonthGrid({ group }: { group: MonthlyGroup }): JSX.Element {
  // 构建当月日历：按 date 索引
  const byDate = new Map<string, AttendanceRecord>();
  for (const it of group.items) {
    byDate.set(it.date, it);
  }

  // 当月天数
  const daysInMonth = new Date(group.year, group.month + 1, 0).getDate();
  // 当月 1 号是周几
  const firstWeekday = new Date(group.year, group.month, 1).getDay();

  const cells: Array<{
    day: number | null;
    dateStr: string | null;
    item?: AttendanceRecord;
  }> = [];
  // 前置空格
  for (let i = 0; i < firstWeekday; i++) {
    cells.push({ day: null, dateStr: null });
  }
  for (let day = 1; day <= daysInMonth; day++) {
    const dateStr = `${group.year}-${String(group.month + 1).padStart(2, "0")}-${String(day).padStart(2, "0")}`;
    cells.push({
      day,
      dateStr,
      item: byDate.get(dateStr),
    });
  }

  return (
    <div className="card-paper p-5 lg:p-6">
      <div className="flex items-baseline justify-between mb-4">
        <h2
          className="text-lg font-serif"
          style={{ color: "var(--color-ink)" }}
        >
          {group.year} 年 {MONTH_NAMES[group.month]}
        </h2>
        <Legend />
      </div>
      <div className="rule-thin mb-4" />

      <div
        className="grid grid-cols-7 gap-1"
        role="grid"
        aria-label={`${group.year}年${group.month + 1}月考勤日历`}
      >
        {WEEKDAY_LABELS.map((wd) => (
          <div
            key={wd}
            role="columnheader"
            className="text-center text-xs py-1"
            style={{ color: "var(--color-ink-muted)" }}
          >
            {wd}
          </div>
        ))}
        {cells.map((cell, idx) => (
          <DayCell key={idx} cell={cell} />
        ))}
      </div>
    </div>
  );
}

function DayCell({
  cell,
}: {
  cell: {
    day: number | null;
    dateStr: string | null;
    item?: AttendanceRecord;
  };
}): JSX.Element {
  if (cell.day === null) {
    return <div role="gridcell" className="aspect-square" aria-hidden="true" />;
  }

  const status = cell.item?.status;
  const bg = getBackgroundColorForStatus(status);
  const fg = getForegroundColorForStatus(status);
  const label = getStatusLabel(status);

  return (
    <div
      role="gridcell"
      className="aspect-square rounded-sm flex flex-col items-center justify-center text-xs"
      style={{ background: bg, color: fg }}
      aria-label={
        cell.item
          ? `${cell.dateStr} ${label}${cell.item.subject ? ` · ${cell.item.subject.name}` : ""}`
          : `${cell.dateStr} 无记录`
      }
      title={
        cell.item
          ? `${cell.dateStr} · ${label}${cell.item.subject ? ` · ${cell.item.subject.name}` : ""}${cell.item.reason ? ` · ${cell.item.reason}` : ""}${cell.item.lateMinutes ? ` · 迟到 ${cell.item.lateMinutes} 分钟` : ""}`
          : (cell.dateStr ?? "")
      }
    >
      <span className="font-mono">{cell.day}</span>
      {status && (
        <span className="text-[10px] mt-0.5 leading-none">
          {label.slice(0, 1)}
        </span>
      )}
    </div>
  );
}

function Legend(): JSX.Element {
  return (
    <ul className="flex flex-wrap gap-3 text-xs" aria-label="图例">
      <LegendItem color="var(--color-success)" label="出勤" />
      <LegendItem color="var(--color-warning)" label="迟到" />
      <LegendItem color="var(--color-danger)" label="缺勤" />
      <LegendItem color="var(--color-rule)" label="无记录" />
    </ul>
  );
}

function LegendItem({
  color,
  label,
}: {
  color: string;
  label: string;
}): JSX.Element {
  return (
    <li className="flex items-center gap-1">
      <span
        className="inline-block w-3 h-3 rounded-sm"
        style={{ background: color }}
        aria-hidden="true"
      />
      <span style={{ color: "var(--color-ink-muted)" }}>{label}</span>
    </li>
  );
}

// === 异常列表（缺勤 + 迟到）===
function AbnormalList({
  attendance,
}: {
  attendance: AttendanceRecord[];
}): JSX.Element {
  const abnormal = attendance
    .filter((a) => a.status === "absent" || a.status === "late")
    .sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime());

  if (abnormal.length === 0) {
    return (
      <section aria-label="异常记录" className="card-paper p-6">
        <h2
          className="text-lg font-serif mb-2"
          style={{ color: "var(--color-ink)" }}
        >
          异常记录
        </h2>
        <div className="rule-thin mb-4" />
        <p
          className="text-sm text-center py-6"
          style={{ color: "var(--color-ink-muted)" }}
        >
          全勤！近期没有缺勤或迟到记录。
        </p>
      </section>
    );
  }

  return (
    <section aria-label="异常记录" className="card-paper p-6">
      <div className="flex items-baseline justify-between mb-4">
        <h2
          className="text-lg font-serif"
          style={{ color: "var(--color-ink)" }}
        >
          异常记录
        </h2>
        <span className="text-xs" style={{ color: "var(--color-ink-muted)" }}>
          共 {abnormal.length} 条
        </span>
      </div>
      <div className="rule-thin mb-4" />
      <ul className="divide-y" style={{ borderColor: "var(--color-rule)" }}>
        {abnormal.map((it) => (
          <li
            key={it.id}
            className="py-3 flex items-start justify-between gap-4"
          >
            <div className="min-w-0 flex-1">
              <p
                className="text-sm font-medium"
                style={{ color: "var(--color-ink)" }}
              >
                {it.subject.name}
              </p>
              <p
                className="mt-1 text-xs"
                style={{ color: "var(--color-ink-muted)" }}
              >
                {new Intl.DateTimeFormat("zh-CN", {
                  year: "numeric",
                  month: "2-digit",
                  day: "2-digit",
                }).format(new Date(it.date))}
                {it.reason ? ` · ${it.reason}` : ""}
                {it.lateMinutes ? ` · 迟到 ${it.lateMinutes} 分钟` : ""}
              </p>
            </div>
            <span
              className={`badge ${
                it.status === "absent" ? "badge-danger" : "badge-warning"
              } flex-shrink-0`}
            >
              {getStatusLabel(it.status)}
            </span>
          </li>
        ))}
      </ul>
    </section>
  );
}

// === 状态工具 ===
function getBackgroundColorForStatus(
  status: AttendanceStatus | undefined,
): string {
  if (!status) return "var(--color-paper)";
  switch (status) {
    case "present":
      return "hsl(var(--hue-success), var(--sat-success), 92%)";
    case "late":
      return "hsl(var(--hue-warning), var(--sat-warning), 92%)";
    case "absent":
      return "hsl(var(--hue-danger), var(--sat-danger), 92%)";
    default:
      return "var(--color-paper)";
  }
}

function getForegroundColorForStatus(
  status: AttendanceStatus | undefined,
): string {
  if (!status) return "var(--color-ink-subtle)";
  switch (status) {
    case "present":
      return "var(--color-success)";
    case "late":
      return "var(--color-warning)";
    case "absent":
      return "var(--color-danger)";
    default:
      return "var(--color-ink-muted)";
  }
}

function getStatusLabel(status: AttendanceStatus | undefined): string {
  if (!status) return "无记录";
  const map: Record<AttendanceStatus, string> = {
    present: "出勤",
    late: "迟到",
    absent: "缺勤",
  };
  return map[status] ?? "无记录";
}

function LoadingSkeleton(): JSX.Element {
  return (
    <div aria-busy="true" aria-live="polite">
      <div className="grid grid-cols-2 lg:grid-cols-5 gap-4" aria-hidden="true">
        {[0, 1, 2, 3, 4].map((i) => (
          <div key={i} className="card-paper p-5">
            <div
              className="h-3 w-12 rounded-sm animate-pulse"
              style={{ background: "var(--color-rule)" }}
            />
            <div
              className="mt-3 h-7 w-20 rounded-sm animate-pulse"
              style={{ background: "var(--color-rule)" }}
            />
          </div>
        ))}
      </div>
      <div className="mt-8 card-paper p-6" aria-hidden="true">
        <div
          className="h-4 w-32 rounded-sm animate-pulse mb-4"
          style={{ background: "var(--color-rule)" }}
        />
        <div className="rule-thin mb-4" />
        <div className="grid grid-cols-7 gap-1">
          {Array.from({ length: 35 }).map((_, i) => (
            <div
              key={i}
              className="aspect-square rounded-sm animate-pulse"
              style={{
                background: "var(--color-rule)",
                opacity: 0.4,
              }}
            />
          ))}
        </div>
      </div>
      <span className="sr-only">正在加载考勤数据...</span>
    </div>
  );
}

function ErrorState({ message }: { message: string }): JSX.Element {
  return (
    <div
      role="alert"
      className="card-paper p-8 text-center"
      style={{ borderColor: "var(--color-danger)" }}
    >
      <p
        className="text-base font-serif"
        style={{ color: "var(--color-danger)" }}
      >
        考勤数据加载失败
      </p>
      <p className="mt-2 text-sm" style={{ color: "var(--color-ink-muted)" }}>
        {message}
      </p>
      <button
        type="button"
        onClick={() => window.location.reload()}
        className="mt-4 btn-secondary text-xs"
      >
        重新加载
      </button>
    </div>
  );
}

function EmptyState(): JSX.Element {
  return (
    <div className="card-paper p-8 text-center">
      <p
        className="text-4xl font-serif"
        style={{ color: "var(--color-ink-subtle)" }}
        aria-hidden="true"
      >
        ◯
      </p>
      <p
        className="mt-4 text-base font-serif"
        style={{ color: "var(--color-ink)" }}
      >
        暂无考勤记录
      </p>
      <p className="mt-2 text-sm" style={{ color: "var(--color-ink-muted)" }}>
        当学校记录考勤后，这里会显示你的出勤日历与统计。
      </p>
    </div>
  );
}
