import { useCallback, useEffect, useMemo, useState } from "react";
import { apiGet, apiPost } from "../../lib/api";

export interface QuestionMeta {
  number: number;
  text: string;
  options: string[];
}

export interface StudentRow {
  name: string;
  answers: (string | null)[];
}

export interface AnswerGrid {
  total_questions: number;
  official_answers: (string | null)[];
  students: StudentRow[];
  questions: QuestionMeta[];
}

interface AnswerGridResponse {
  grid: AnswerGrid;
  is_confirmed: boolean;
}

interface AnswerGridEditorProps {
  sessionId: number;
  onConfirmedChange: (grid: AnswerGrid | null) => void;
}

const CORRECT_MARKER = "=";
const DASH_MARKERS = new Set(["-", "–", "—"]);

function normalizeCell(raw: string): string | null {
  const trimmed = raw.trim();
  if (!trimmed) return null;
  if (trimmed === CORRECT_MARKER || DASH_MARKERS.has(trimmed)) {
    return CORRECT_MARKER;
  }
  const first = trimmed.charAt(0).toUpperCase();
  return /^[A-Z]$/.test(first) ? first : null;
}

function resizeRow(row: (string | null)[], n: number): (string | null)[] {
  if (row.length === n) return row;
  if (row.length > n) return row.slice(0, n);
  return [...row, ...Array<string | null>(n - row.length).fill(null)];
}

function resizeQuestions(qs: QuestionMeta[], n: number): QuestionMeta[] {
  if (qs.length === n) return qs;
  if (qs.length > n) return qs.slice(0, n);
  const pad: QuestionMeta[] = [];
  for (let i = qs.length; i < n; i++) {
    pad.push({ number: i + 1, text: "", options: [] });
  }
  return [...qs, ...pad];
}

export function AnswerGridEditor({
  sessionId,
  onConfirmedChange,
}: AnswerGridEditorProps) {
  const [grid, setGrid] = useState<AnswerGrid | null>(null);
  const [loading, setLoading] = useState(true);
  const [saving, setSaving] = useState(false);
  const [saved, setSaved] = useState(false);
  const [error, setError] = useState("");

  useEffect(() => {
    setLoading(true);
    apiGet<AnswerGridResponse>(`/api/sessions/${sessionId}/answer-grid`)
      .then((res) => {
        setGrid(res.grid);
        setSaved(res.is_confirmed);
        if (res.is_confirmed) {
          onConfirmedChange(res.grid);
        }
      })
      .catch((e) => setError(e instanceof Error ? e.message : "Failed to load grid"))
      .finally(() => setLoading(false));
  }, [sessionId]);

  const qNums = useMemo(() => {
    if (!grid) return [];
    return Array.from({ length: grid.total_questions }, (_, i) => i + 1);
  }, [grid]);

  const markDirty = useCallback(() => {
    setSaved(false);
    onConfirmedChange(null);
  }, [onConfirmedChange]);

  const updateN = useCallback(
    (n: number) => {
      if (!grid || n < 1) return;
      setGrid({
        ...grid,
        total_questions: n,
        official_answers: resizeRow(grid.official_answers, n),
        students: grid.students.map((s) => ({
          ...s,
          answers: resizeRow(s.answers, n),
        })),
        questions: resizeQuestions(grid.questions, n),
      });
      markDirty();
    },
    [grid, markDirty]
  );

  const updateStudentCell = useCallback(
    (studentIdx: number, qIdx: number, raw: string) => {
      if (!grid) return;
      const value = normalizeCell(raw);
      const nextStudents = grid.students.map((s, i) => {
        if (i !== studentIdx) return s;
        const nextAnswers = [...s.answers];
        nextAnswers[qIdx] = value;
        return { ...s, answers: nextAnswers };
      });
      setGrid({ ...grid, students: nextStudents });
      markDirty();
    },
    [grid, markDirty]
  );

  const updateOfficialCell = useCallback(
    (qIdx: number, raw: string) => {
      if (!grid) return;
      const value = normalizeCell(raw);
      const next = [...grid.official_answers];
      next[qIdx] = value;
      setGrid({ ...grid, official_answers: next });
      markDirty();
    },
    [grid, markDirty]
  );

  const handleSave = useCallback(async () => {
    if (!grid) return;
    setSaving(true);
    setError("");
    try {
      const res = await apiPost<AnswerGridResponse>(
        `/api/sessions/${sessionId}/answer-grid`,
        grid
      );
      setGrid(res.grid);
      setSaved(true);
      onConfirmedChange(res.grid);
    } catch (e) {
      setError(e instanceof Error ? e.message : "Failed to save grid");
    } finally {
      setSaving(false);
    }
  }, [grid, sessionId, onConfirmedChange]);

  if (loading) {
    return (
      <div className="card p-8 text-center">
        <div className="inline-block w-6 h-6 border-2 border-[var(--color-primary)] border-t-transparent rounded-full animate-spin" />
      </div>
    );
  }

  if (!grid) {
    return (
      <div className="card p-8 text-center">
        <p className="text-[var(--color-text-muted)]">
          {error || "尚未上傳任何資料，請回到上一步先解析檔案"}
        </p>
      </div>
    );
  }

  return (
    <div className="card p-5 space-y-4">
      <div className="flex items-center justify-between flex-wrap gap-3">
        <div>
          <h3 className="font-display text-lg font-semibold text-[var(--color-text)]">
            📋 確認答案表 (Answer Grid)
          </h3>
          <p className="text-xs text-[var(--color-text-muted)] mt-1">
            請核對學生作答與標準答案，確認後才能生成報告。支援單選題（A-Z）。
            學生欄輸入 <code className="px-1 bg-[var(--color-background)] rounded">=</code> 代表該題答對。
          </p>
        </div>
        <div className="flex items-center gap-2">
          <label className="text-sm text-[var(--color-text-muted)]">題數：</label>
          <input
            type="number"
            min={1}
            max={200}
            value={grid.total_questions}
            onChange={(e) => updateN(Number(e.target.value))}
            className="input !w-20 !py-1 text-sm"
          />
        </div>
      </div>

      <div className="overflow-x-auto max-h-[60vh] overflow-y-auto">
        <table className="w-full text-sm border-separate border-spacing-0">
          <thead className="sticky top-0 bg-[var(--color-surface)] z-10">
            <tr>
              <th className="text-left py-2 px-3 border-b border-[var(--color-border)] sticky left-0 bg-[var(--color-surface)] z-20 min-w-[120px]">
                學生
              </th>
              {qNums.map((n) => (
                <th
                  key={n}
                  className="text-center py-2 px-2 border-b border-[var(--color-border)] text-[var(--color-text-muted)] min-w-[48px]"
                >
                  Q{n}
                </th>
              ))}
            </tr>
          </thead>
          <tbody>
            {grid.students.map((s, si) => (
              <tr key={si}>
                <td className="py-1 px-3 border-b border-[var(--color-border)]/50 sticky left-0 bg-[var(--color-background)] z-10 font-medium text-[var(--color-text)]">
                  {s.name}
                </td>
                {qNums.map((n, qi) => {
                  const cell = s.answers[qi];
                  const isCorrect = cell === CORRECT_MARKER;
                  return (
                    <td
                      key={n}
                      className="border-b border-[var(--color-border)]/50 p-0.5"
                    >
                      <input
                        type="text"
                        maxLength={2}
                        defaultValue={cell ?? ""}
                        onBlur={(e) => updateStudentCell(si, qi, e.target.value)}
                        className={`w-full text-center py-1 bg-transparent border border-transparent hover:border-[var(--color-border)] focus:border-[var(--color-primary)] focus:outline-none rounded ${
                          isCorrect
                            ? "text-[var(--color-success)] font-semibold"
                            : "text-[var(--color-text)]"
                        }`}
                      />
                    </td>
                  );
                })}
              </tr>
            ))}

            {/* Answer key row */}
            <tr className="bg-[var(--color-primary)]/5">
              <td className="py-2 px-3 border-t-2 border-[var(--color-primary)] sticky left-0 bg-[var(--color-surface)] z-10 font-bold text-[var(--color-primary)]">
                ✅ 標準答案
              </td>
              {qNums.map((n, qi) => (
                <td
                  key={n}
                  className="border-t-2 border-[var(--color-primary)] p-0.5"
                >
                  <input
                    type="text"
                    maxLength={2}
                    defaultValue={grid.official_answers[qi] ?? ""}
                    onBlur={(e) => updateOfficialCell(qi, e.target.value)}
                    className="w-full text-center py-1 bg-transparent text-[var(--color-success)] font-semibold border border-transparent hover:border-[var(--color-border)] focus:border-[var(--color-primary)] focus:outline-none rounded"
                  />
                </td>
              ))}
            </tr>
          </tbody>
        </table>
      </div>

      {error && (
        <p className="text-sm text-red-400 text-center">{error}</p>
      )}

      <div className="flex items-center justify-between flex-wrap gap-3">
        <div className="text-xs text-[var(--color-text-muted)]">
          {saved ? (
            <span className="text-[var(--color-success)]">✓ 已確認（可生成報告）</span>
          ) : (
            <span className="text-amber-400">⚠ 尚未確認，編輯後請按下「確認儲存」</span>
          )}
        </div>
        <button
          onClick={handleSave}
          disabled={saving}
          className="btn btn-primary text-sm disabled:opacity-50"
        >
          {saving ? "儲存中..." : saved ? "重新儲存" : "確認儲存"}
        </button>
      </div>
    </div>
  );
}
