"use client";

import { useEffect, useMemo, useState } from "react";
import { useLang } from "@/context/LanguageContext";
import {
  Alert,
  Button,
  Card,
  EmptyState,
  Modal,
  PageHeader,
  LoadingArea,
  Select,
  StatusBadge,
} from "@/components/ui";
import { api, useApi } from "@/lib/client";
import { formatDate } from "@/lib/utils";
import { IconClipboard, IconInfo } from "@/components/icons";

interface PaperMark {
  studentId: number;
  cq: number | null;
  mcq: number | null;
  applied: number | null;
  total: number | null;
}

interface Paper {
  id: number;
  date: string;
  startTime: string | null;
  fullMarks: number;
  cqMarks: number | null;
  mcqMarks: number | null;
  appliedMarks: number | null;
  subjectItem: { name: string; nameBn: string | null } | null;
  exam: {
    id: number;
    name: string;
    nameBn: string | null;
    status: string;
    startDate: string;
    endDate: string | null;
    resultPublished: boolean;
    classItemId: number | null;
    classItem: { name: string; nameBn: string | null } | null;
    sectionItem: { name: string; nameBn: string | null } | null;
  };
  marks: PaperMark[];
}

interface RosterStudent {
  id: number;
  roll: string;
  name: string;
  nameBn: string | null;
  classItemId: number | null;
  sectionItemId: number | null;
}

interface MarksData {
  exams: {
    id: number;
    name: string;
    nameBn: string | null;
    className: string | null;
    classNameBn: string | null;
    sectionName: string | null;
    sectionItemId: number | null;
    status: string;
    startDate: string;
    endDate: string | null;
    resultPublished: boolean;
    papers: Paper[];
  }[];
  roster: RosterStudent[];
}

type Entry = { cq: string; mcq: string; applied: string; total: string };
type MarkMode = "subject" | "student";

const EMPTY_ENTRY: Entry = { cq: "", mcq: "", applied: "", total: "" };

/** Teacher marks entry with the full admin feature set — subject-wise AND
    student-wise modes, live auto-total with clamping, per-column max hints,
    progress counter and a lock notice for published results — scoped to the
    papers the teacher actually teaches (their class-routine subjects). */
export default function MeMarksPage() {
  const { t, locale } = useLang();
  const { data, loading, reload } = useApi<MarksData>("/api/me/marks");

  const [mode, setMode] = useState<MarkMode>("subject");
  const [examId, setExamId] = useState("");
  const [paperId, setPaperId] = useState<number | null>(null);
  const [studentId, setStudentId] = useState<number | null>(null);
  const [entries, setEntries] = useState<Record<number, Entry>>({});
  const [saving, setSaving] = useState(false);
  const [message, setMessage] = useState<{ type: "success" | "error"; text: string } | null>(null);
  const [lockNotice, setLockNotice] = useState(false);

  const exams = data?.exams ?? [];
  const exam = exams.find((e) => String(e.id) === examId) ?? null;
  const paper = exam?.papers.find((p) => p.id === paperId) ?? null;

  // roster of the selected exam's class, narrowed to the exam's section
  const roster = useMemo(
    () =>
      (data?.roster ?? []).filter(
        (s) =>
          s.classItemId != null &&
          exam?.papers[0]?.exam.classItemId != null &&
          s.classItemId === exam.papers[0].exam.classItemId &&
          (exam.sectionItemId == null || s.sectionItemId == null || s.sectionItemId === exam.sectionItemId)
      ),
    [data, exam]
  );
  const selectedStudent = roster.find((s) => s.id === studentId) ?? null;

  // prefill the grid from saved marks whenever the viewed paper set changes
  const viewPapers: Paper[] = mode === "subject" ? (paper ? [paper] : []) : exam?.papers ?? [];
  useEffect(() => {
    const students = mode === "subject" ? roster : selectedStudent ? [selectedStudent] : [];
    if (viewPapers.length === 0 || students.length === 0) {
      setEntries({});
      return;
    }
    const next: Record<number, Entry> = {};
    for (const p of viewPapers) {
      const byStudent = new Map(p.marks.map((m) => [m.studentId, m]));
      for (const s of students) {
        const m = byStudent.get(s.id);
        next[p.id * 100000 + s.id] = {
          cq: m?.cq != null ? String(m.cq) : "",
          mcq: m?.mcq != null ? String(m.mcq) : "",
          applied: m?.applied != null ? String(m.applied) : "",
          total: m?.total != null ? String(m.total) : "",
        };
      }
    }
    setEntries(next);
    setMessage(null);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [paperId, studentId, mode, roster.length, exam?.id, viewPapers.length]);

  const hasSplit = !!(paper && (paper.cqMarks != null || paper.mcqMarks != null || paper.appliedMarks != null));
  const locked = !!exam?.resultPublished;

  /** clamp to the part max and keep the total as the live CQ+MCQ+Applied sum */
  function setPart(key: "cq" | "mcq" | "applied", rowKey: number, raw: string, max: number | null) {
    setEntries((prev) => {
      const e = prev[rowKey] ?? EMPTY_ENTRY;
      let v = raw.replace(/[^0-9]/g, "");
      if (max != null && v !== "" && Number(v) > max) v = String(max);
      const next = { ...e, [key]: v };
      if (hasSplit) {
        const sum = (Number(next.cq) || 0) + (Number(next.mcq) || 0) + (Number(next.applied) || 0);
        next.total = sum > 0 ? String(sum) : "";
      }
      return { ...prev, [rowKey]: next };
    });
  }

  function setTotal(rowKey: number, raw: string, max: number) {
    setEntries((prev) => {
      const e = prev[rowKey] ?? EMPTY_ENTRY;
      let v = raw.replace(/[^0-9]/g, "");
      if (v !== "" && Number(v) > max) v = String(max);
      return { ...prev, [rowKey]: { ...e, total: v } };
    });
  }

  /** rows with any entered value — only these are posted (like the admin grid) */
  const filledRows = Object.entries(entries).filter(([, e]) => e.cq !== "" || e.mcq !== "" || e.applied !== "" || e.total !== "");

  // progress: subject mode counts students, student mode counts papers
  const enteredCount = useMemo(() => {
    if (mode === "subject") {
      return roster.filter((s) => {
        const e = entries[s.id];
        return e && (e.cq !== "" || e.mcq !== "" || e.applied !== "" || e.total !== "");
      }).length;
    }
    return (exam?.papers ?? []).filter((p) => {
      const e = entries[p.id * 100000 + (studentId ?? 0)];
      return e && (e.cq !== "" || e.mcq !== "" || e.applied !== "" || e.total !== "");
    }).length;
  }, [entries, roster, mode, exam, studentId]);

  async function save() {
    if (!exam || filledRows.length === 0) return;
    setSaving(true);
    setMessage(null);
    const rows = filledRows.map(([rowKey, e]) => {
      const rowKeyNum = Number(rowKey);
      const pid = Math.floor(rowKeyNum / 100000);
      const sid = rowKeyNum % 100000;
      const p = exam.papers.find((x) => x.id === pid);
      const split = !!(p && (p.cqMarks != null || p.mcqMarks != null || p.appliedMarks != null));
      const total =
        split && !e.total
          ? (["cq", "mcq", "applied"] as const).reduce((sum, k) => sum + (Number(e[k]) || 0), 0) || null
          : e.total === ""
            ? null
            : Number(e.total);
      return {
        examScheduleId: pid,
        studentId: sid,
        cq: e.cq === "" ? null : Number(e.cq),
        mcq: e.mcq === "" ? null : Number(e.mcq),
        applied: e.applied === "" ? null : Number(e.applied),
        total,
      };
    });
    try {
      const res = await api<{ saved?: number }>("/api/me/marks", {
        method: "POST",
        body: JSON.stringify({ examId: exam.id, rows }),
      });
      setMessage({
        type: "success",
        text: (t.me.marksSavedCount || t.me.marksSaved).replace("{n}", String(res.saved ?? rows.length)),
      });
      reload();
    } catch (err) {
      const code = err instanceof Error ? err.message : "";
      setMessage({
        type: "error",
        text:
          code === "MARKS_EXCEED"
            ? t.me.marksExceed
            : code === "RESULT_PUBLISHED"
              ? t.me.marksLocked
              : code === "NOT_YOUR_PAPER"
                ? t.me.notYourPaper
                : t.common.tryAgain,
      });
    } finally {
      setSaving(false);
    }
  }

  if (loading) {
    return (
      <div>
        <PageHeader title={t.me.marksTitle} subtitle={t.me.marksSubtitle} />
        <LoadingArea label={t.common.loading} />
      </div>
    );
  }

  const subjName = (p: Paper) => (locale === "bn" && p.subjectItem?.nameBn ? p.subjectItem.nameBn : p.subjectItem?.name) ?? "—";
  // the grid's rows: subject mode → students of the paper; student mode → papers of the student
  const gridRows: { rowKey: number; paper: Paper; student: RosterStudent | null }[] =
    mode === "subject"
      ? roster.map((s) => ({ rowKey: s.id, paper: paper as Paper, student: s }))
      : (exam?.papers ?? [])
          .filter(() => selectedStudent != null)
          .map((p) => ({ rowKey: p.id * 100000 + (studentId as number), paper: p, student: selectedStudent }));

  return (
    <div>
      <PageHeader title={t.me.marksTitle} subtitle={t.me.marksSubtitle} />

      {message && (
        <div className="mb-4">
          <Alert type={message.type} onClose={() => setMessage(null)}>{message.text}</Alert>
        </div>
      )}

      {exams.length === 0 ? (
        <div className="card">
          <EmptyState icon={<IconClipboard />} title={t.me.noPapers} />
        </div>
      ) : (
        <Card title={t.me.marksTitle} icon={<IconClipboard className="svg-20" />}>
          <div className="row g-3 mb-3">
            <div className="col-md-6">
              <Select
                label={t.me.examCol}
                value={examId}
                onChange={(e) => {
                  setExamId(e.target.value);
                  const ex = exams.find((x) => String(x.id) === e.target.value);
                  setPaperId(ex?.papers[0]?.id ?? null);
                  setStudentId(null);
                }}
              >
                <option value="">— {t.common.select} —</option>
                {exams.map((e) => (
                  <option key={e.id} value={e.id}>
                    {(locale === "bn" && e.nameBn ? e.nameBn : e.name) +
                      (e.className ? ` · ${locale === "bn" && e.classNameBn ? e.classNameBn : e.className}` : "")}
                  </option>
                ))}
              </Select>
            </div>
            <div className="col-md-3 d-flex align-items-end">
              {exam && (
                <div className="d-flex align-items-center gap-2 flex-wrap pb-2">
                  <StatusBadge status={exam.status} label={t.status[exam.status as keyof typeof t.status]} />
                  {locked && <span className="badge badge-secondary">{t.me.marksLockedBadge}</span>}
                </div>
              )}
            </div>
            <div className="col-md-3 d-flex align-items-end">
              <div className="btn-group btn-group-sm w-100 pb-2" role="group" aria-label={t.me.marksMode}>
                <button
                  type="button"
                  className={`btn f-w-700 ${mode === "subject" ? "btn-primary" : "btn-outline-secondary"}`}
                  onClick={() => setMode("subject")}
                >
                  {t.portal.examsPage.subjectWise}
                </button>
                <button
                  type="button"
                  className={`btn f-w-700 ${mode === "student" ? "btn-primary" : "btn-outline-secondary"}`}
                  onClick={() => setMode("student")}
                >
                  {t.portal.examsPage.studentWise}
                </button>
              </div>
            </div>
          </div>

          {!exam ? (
            <EmptyState icon={<IconClipboard />} title={t.me.pickExamFirst} />
          ) : (
            <>
              {/* picker: subject mode → paper pills (with date); student mode → student select */}
              {mode === "subject" ? (
                <div className="d-flex flex-wrap gap-2 mb-3">
                  {exam.papers.map((p) => (
                    <button
                      key={p.id}
                      type="button"
                      className={`btn btn-sm f-w-600 ${p.id === paperId ? "btn-primary" : "btn-outline-secondary"}`}
                      onClick={() => setPaperId(p.id)}
                    >
                      {subjName(p)}
                      <span className="ms-1 opacity-75">({p.fullMarks})</span>
                      <span className="ms-1 opacity-75 ems-fs-11">{formatDate(p.date, locale)}</span>
                    </button>
                  ))}
                </div>
              ) : (
                <div className="row g-3 mb-3">
                  <div className="col-md-6">
                    <Select
                      label={t.common.name}
                      value={studentId != null ? String(studentId) : ""}
                      onChange={(e) => setStudentId(e.target.value ? Number(e.target.value) : null)}
                    >
                      <option value="">— {t.common.select} —</option>
                      {roster.map((s) => (
                        <option key={s.id} value={s.id}>
                          {s.roll} — {s.name}
                        </option>
                      ))}
                    </Select>
                  </div>
                </div>
              )}

              {mode === "subject" && paper && (
                <p className="ems-fs-12 text-muted mb-3">
                  {t.me.subjectCol}: <b>{subjName(paper)}</b>
                  {" · "}{formatDate(paper.date, locale)}
                  {" · "}{t.me.fullMarksCol}: <b>{paper.fullMarks}</b>
                  {paper.cqMarks != null && ` · CQ ${paper.cqMarks}`}
                  {paper.mcqMarks != null && ` · MCQ ${paper.mcqMarks}`}
                  {paper.appliedMarks != null && ` · ${t.me.appliedCol} ${paper.appliedMarks}`}
                  {locked && ` · ${t.me.marksLocked}`}
                </p>
              )}

              {mode === "student" && !selectedStudent ? (
                <EmptyState icon={<IconClipboard />} title={t.me.pickStudentFirst} />
              ) : gridRows.length === 0 ? (
                <EmptyState icon={<IconClipboard />} title={t.me.noStudentsInClass} />
              ) : (
                <>
                  <div className="position-relative">
                    <div className="table-responsive">
                      <table className="table table-hover align-middle mb-0">
                        <thead className="ems-table-head">
                          <tr>
                            {mode === "subject" ? (
                              <>
                                <th style={{ width: 90 }}>{t.me.rollCol}</th>
                                <th>{t.common.name}</th>
                              </>
                            ) : (
                              <>
                                <th>{t.me.subjectCol}</th>
                                <th>{t.common.date}</th>
                              </>
                            )}
                            {hasSplit ? (
                              <>
                                {paper?.cqMarks != null && <th className="text-center">CQ {partHint(paper.cqMarks)}</th>}
                                {paper?.mcqMarks != null && <th className="text-center">MCQ {partHint(paper.mcqMarks)}</th>}
                                {paper?.appliedMarks != null && <th className="text-center">{t.me.appliedCol} {partHint(paper.appliedMarks)}</th>}
                                <th className="text-center">{t.me.totalCol}</th>
                              </>
                            ) : (
                              <th className="text-center">{t.me.totalCol} ({t.me.fullMarksCol}: {gridRows[0]?.paper.fullMarks})</th>
                            )}
                          </tr>
                        </thead>
                        <tbody>
                          {gridRows.map(({ rowKey, paper: rp, student: s }) => {
                            const e = entries[rowKey] ?? EMPTY_ENTRY;
                            const split = !!(rp.cqMarks != null || rp.mcqMarks != null || rp.appliedMarks != null);
                            const cell = (key: "cq" | "mcq" | "applied", max: number | null) => (
                              <td className="text-center" style={{ width: 110 }}>
                                <input
                                  className="form-control form-control-sm text-center"
                                  type="number"
                                  min={0}
                                  max={max ?? undefined}
                                  disabled={locked}
                                  value={e[key]}
                                  onChange={(ev) => setPart(key, rowKey, ev.target.value, max)}
                                />
                              </td>
                            );
                            const sum = (Number(e.cq) || 0) + (Number(e.mcq) || 0) + (Number(e.applied) || 0);
                            return (
                              <tr key={rowKey}>
                                {mode === "subject" ? (
                                  <>
                                    <td>
                                      <span className="ems-roll-badge">{s?.roll}</span>
                                    </td>
                                    <td className="f-w-600 ems-fs-13">
                                      {s?.name}
                                      {s?.nameBn && locale === "bn" && (
                                        <span className="text-muted"> ({s.nameBn})</span>
                                      )}
                                    </td>
                                  </>
                                ) : (
                                  <>
                                    <td className="f-w-600 ems-fs-13">{subjName(rp)}</td>
                                    <td className="ems-fs-12 text-muted">{formatDate(rp.date, locale)}</td>
                                  </>
                                )}
                                {split ? (
                                  <>
                                    {rp.cqMarks != null && cell("cq", rp.cqMarks)}
                                    {rp.mcqMarks != null && cell("mcq", rp.mcqMarks)}
                                    {rp.appliedMarks != null && cell("applied", rp.appliedMarks)}
                                    <td className="text-center">
                                      <input
                                        className="form-control form-control-sm text-center f-w-700"
                                        style={{ background: "rgba(36,105,92,.06)" }}
                                        type="number"
                                        min={0}
                                        max={rp.fullMarks}
                                        disabled={locked}
                                        readOnly={split}
                                        value={e.total || sum || ""}
                                        onChange={(ev) => setTotal(rowKey, ev.target.value, rp.fullMarks)}
                                      />
                                    </td>
                                  </>
                                ) : (
                                  <td className="text-center" style={{ width: 110 }}>
                                    <input
                                      className="form-control form-control-sm text-center"
                                      type="number"
                                      min={0}
                                      max={rp.fullMarks}
                                      disabled={locked}
                                      value={e.total}
                                      onChange={(ev) => setTotal(rowKey, ev.target.value, rp.fullMarks)}
                                    />
                                  </td>
                                )}
                              </tr>
                            );
                          })}
                        </tbody>
                      </table>
                    </div>
                    {/* click-capture overlay + notice, like the admin grid lock */}
                    {locked && (
                      <div
                        className="position-absolute d-flex align-items-center justify-content-center"
                        style={{ inset: 0, background: "rgba(255,255,255,.55)", cursor: "pointer", zIndex: 5 }}
                        onClick={() => setLockNotice(true)}
                        title={t.me.marksLocked}
                      />
                    )}
                  </div>

                  {/* progress + save */}
                  <div className="d-flex flex-wrap justify-content-between align-items-center gap-2 pt-3">
                    <span className="ems-fs-12 text-muted">
                      {t.me.marksEntered.replace("{x}", String(enteredCount)).replace("{y}", String(mode === "subject" ? roster.length : exam?.papers.length ?? 0))}
                      {enteredCount < (mode === "subject" ? roster.length : exam?.papers.length ?? 0) && ` · ${t.me.marksNotGraded}`}
                    </span>
                    {!locked && (
                      <Button onClick={save} loading={saving} disabled={filledRows.length === 0}>
                        {t.common.save}
                      </Button>
                    )}
                  </div>
                </>
              )}
            </>
          )}
        </Card>
      )}

      {/* published-result lock notice */}
      <Modal open={lockNotice} onClose={() => setLockNotice(false)} title={t.me.marksLockedBadge}>
        <div className="d-flex gap-3 align-items-start">
          <IconInfo className="svg-24 text-warning flex-shrink-0" />
          <p className="mb-0 ems-fs-13">{t.me.marksLockedNotice}</p>
        </div>
        <div className="d-flex justify-content-end pt-3">
          <Button onClick={() => setLockNotice(false)}>{t.common.close}</Button>
        </div>
      </Modal>
    </div>
  );
}

function partHint(max: number): string {
  return `(≤ ${max})`;
}
