"use client";

import { useMemo, useState } from "react";
import { useRouter } from "next/navigation";
import { ChevronLeft, ChevronRight } from "lucide-react";
import type { AttendanceStatus } from "@prisma/client";
import { cn } from "@/lib/utils";
import { saveAttendance } from "./actions";

type Assignment = { id: string; crewName: string; rank: string; location: string; marks: Record<string, AttendanceStatus> };

const INPUT = "rounded-lg border border-neutral-300 px-3 py-2 text-sm focus:border-primary-500 focus:outline-none focus:ring-2 focus:ring-primary-500/20";

// Tap cycle (§8.10): Unmarked → Present → Absent → Leave → Half day → Unmarked.
const CYCLE: (AttendanceStatus | null)[] = [null, "PRESENT", "ABSENT", "ON_LEAVE", "HALF_DAY"];
const next = (s: AttendanceStatus | null) => CYCLE[(CYCLE.indexOf(s ?? null) + 1) % CYCLE.length];

const CELL: Record<AttendanceStatus, string> = {
  PRESENT: "bg-success-100 text-success-700 border-success-200",
  ABSENT: "bg-danger-100 text-danger-700 border-danger-200",
  ON_LEAVE: "bg-warning-100 text-warning-700 border-warning-200",
  HALF_DAY: "bg-primary-100 text-primary-700 border-primary-200",
  SIGN_OFF: "bg-neutral-200 text-neutral-600 border-neutral-300",
};
const ABBR: Record<AttendanceStatus, string> = { PRESENT: "P", ABSENT: "A", ON_LEAVE: "L", HALF_DAY: "½", SIGN_OFF: "S" };
const MONTHS = ["January","February","March","April","May","June","July","August","September","October","November","December"];
const iso = (y: number, m: number, d: number) => `${y}-${String(m + 1).padStart(2, "0")}-${String(d).padStart(2, "0")}`;

export function AttendanceCalendar({ assignments, canEdit }: { assignments: Assignment[]; canEdit: boolean }) {
  const router = useRouter();
  const today = new Date();
  const [selectedId, setSelectedId] = useState(assignments[0]?.id ?? "");
  const [y, setY] = useState(today.getFullYear());
  const [m, setM] = useState(today.getMonth());
  const [edits, setEdits] = useState<Record<string, Record<string, AttendanceStatus | null>>>({});
  const [pending, setPending] = useState(false);

  const selected = assignments.find((a) => a.id === selectedId) ?? null;
  const myEdits = edits[selectedId] ?? {};

  const statusOf = (date: string): AttendanceStatus | null => {
    if (date in myEdits) return myEdits[date];
    return selected?.marks[date] ?? null;
  };

  const daysInMonth = new Date(y, m + 1, 0).getDate();
  const firstWeekday = new Date(y, m, 1).getDay();
  const days = useMemo(() => Array.from({ length: daysInMonth }, (_, i) => i + 1), [daysInMonth]);

  const summary = useMemo(() => {
    let present = 0, absent = 0, leave = 0;
    for (const d of days) {
      const s = (date => (date in myEdits ? myEdits[date] : selected?.marks[date] ?? null))(iso(y, m, d));
      if (s === "PRESENT") present++; else if (s === "ABSENT") absent++; else if (s === "ON_LEAVE") leave++;
    }
    return { present, absent, leave };
  }, [days, myEdits, selected, y, m]);

  const unmarkedToDate = useMemo(() => {
    const isCurrentOrPast = y < today.getFullYear() || (y === today.getFullYear() && m <= today.getMonth());
    if (!isCurrentOrPast) return 0;
    const lastDay = (y === today.getFullYear() && m === today.getMonth()) ? today.getDate() : daysInMonth;
    let n = 0;
    for (let d = 1; d <= lastDay; d++) if (statusOf(iso(y, m, d)) === null) n++;
    return n;
  }, [y, m, daysInMonth, myEdits, selected]); // eslint-disable-line react-hooks/exhaustive-deps

  const dirty = Object.keys(myEdits).length > 0;

  function cycleDay(date: string) {
    if (!canEdit) return;
    setEdits((e) => ({ ...e, [selectedId]: { ...(e[selectedId] ?? {}), [date]: next(statusOf(date)) } }));
  }

  function shiftMonth(delta: number) {
    const nm = m + delta;
    if (nm < 0) { setM(11); setY(y - 1); } else if (nm > 11) { setM(0); setY(y + 1); } else setM(nm);
  }

  async function save() {
    setPending(true);
    // Null edits (cleared cells) are skipped — clearing a saved mark isn't supported here.
    const marks = Object.entries(myEdits).filter(([, s]) => s !== null).map(([date, status]) => ({ date, status: status as AttendanceStatus }));
    const res = await saveAttendance(selectedId, marks);
    setPending(false);
    if ("ok" in res) { setEdits((e) => ({ ...e, [selectedId]: {} })); router.refresh(); }
  }

  if (assignments.length === 0) {
    return (
      <div>
        <h1 className="text-2xl font-semibold text-neutral-900 mb-2">Attendance</h1>
        <p className="text-neutral-400">No active crew to mark attendance for.</p>
      </div>
    );
  }

  return (
    <div className="max-w-3xl">
      <div className="mb-5 flex items-center justify-between">
        <h1 className="text-2xl font-semibold text-neutral-900">Attendance</h1>
        {canEdit && (
          <button onClick={save} disabled={!dirty || pending} className={cn("rounded-lg px-4 py-2 text-sm font-semibold text-white", dirty ? "bg-primary-600 hover:bg-primary-700" : "bg-neutral-300", "disabled:opacity-60")}>
            {pending ? "Saving…" : "Save"}
          </button>
        )}
      </div>

      <div className="mb-4 flex flex-wrap items-center gap-3">
        <select className={INPUT} value={selectedId} onChange={(e) => setSelectedId(e.target.value)}>
          {assignments.map((a) => <option key={a.id} value={a.id}>{a.crewName} · {a.rank} · {a.location}</option>)}
        </select>
        <div className="flex items-center gap-2">
          <button onClick={() => shiftMonth(-1)} className="rounded-md border border-neutral-300 p-1.5 hover:bg-neutral-50"><ChevronLeft className="h-4 w-4" /></button>
          <span className="text-sm font-medium text-neutral-800 w-36 text-center">{MONTHS[m]} {y}</span>
          <button onClick={() => shiftMonth(1)} className="rounded-md border border-neutral-300 p-1.5 hover:bg-neutral-50"><ChevronRight className="h-4 w-4" /></button>
        </div>
      </div>

      {unmarkedToDate > 0 && (
        <div className="mb-4 rounded-lg border border-warning-200 bg-warning-50 px-4 py-2 text-sm text-warning-800">{unmarkedToDate} day{unmarkedToDate === 1 ? "" : "s"} still need marking.</div>
      )}

      <div className="mb-4 grid grid-cols-3 gap-3">
        {([["Present", summary.present], ["Absent", summary.absent], ["On leave", summary.leave]] as const).map(([k, v]) => (
          <div key={k} className="rounded-lg border border-neutral-200 bg-white p-3 text-center">
            <p className="text-2xl font-semibold text-neutral-900">{v}</p>
            <p className="text-xs text-neutral-500">{k}</p>
          </div>
        ))}
      </div>

      <div className="rounded-lg border border-neutral-200 bg-white p-4">
        <div className="grid grid-cols-7 gap-1 mb-1 text-center text-xs font-medium text-neutral-400">
          {["Sun","Mon","Tue","Wed","Thu","Fri","Sat"].map((d) => <div key={d}>{d}</div>)}
        </div>
        <div className="grid grid-cols-7 gap-1">
          {Array.from({ length: firstWeekday }).map((_, i) => <div key={`pad${i}`} />)}
          {days.map((d) => {
            const date = iso(y, m, d);
            const s = statusOf(date);
            return (
              <button
                key={d}
                onClick={() => cycleDay(date)}
                disabled={!canEdit}
                className={cn(
                  "aspect-square rounded-md border text-sm flex flex-col items-center justify-center",
                  s ? CELL[s] : "border-dashed border-neutral-200 text-neutral-400",
                  canEdit ? "hover:ring-2 hover:ring-primary-200 cursor-pointer" : "cursor-default"
                )}
              >
                <span className="text-[11px] leading-none">{d}</span>
                {s && <span className="text-xs font-semibold leading-none mt-0.5">{ABBR[s]}</span>}
              </button>
            );
          })}
        </div>
        <div className="mt-3 flex flex-wrap gap-3 text-xs text-neutral-500">
          <span><span className="inline-block w-3 h-3 rounded bg-success-100 border border-success-200 align-middle" /> Present</span>
          <span><span className="inline-block w-3 h-3 rounded bg-danger-100 border border-danger-200 align-middle" /> Absent</span>
          <span><span className="inline-block w-3 h-3 rounded bg-warning-100 border border-warning-200 align-middle" /> Leave</span>
          <span><span className="inline-block w-3 h-3 rounded bg-primary-100 border border-primary-200 align-middle" /> Half day</span>
        </div>
      </div>
      {!canEdit && <p className="mt-3 text-xs text-neutral-400">View only — attendance is marked by site staff.</p>}
    </div>
  );
}
