"use client";

import { useEffect, useMemo, useState } from "react";
import { Check, X, ChevronDown, ChevronLeft, Info, AlertTriangle } from "lucide-react";
import { toast } from "sonner";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { Skeleton } from "@/components/ui/skeleton";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import {
  useGoldset, useGoldsetScore, useTagGoldset, useCreateGoldsetSample,
  type GoldsetItem,
} from "@/lib/api/goldset";

const TYPES: { value: string; label: string }[] = [
  { value: "binding", label: "מחייבת" },
  { value: "interpretive", label: "פרשני" },
  { value: "application", label: "יישום" },
  { value: "obiter", label: "אמרת-אגב" },
  { value: "procedural", label: "פרוצדורלי" },
  { value: "persuasive", label: "משכנע" },
];

// Consistency between is_holding and the type (#81.7): a real holding is
// binding/interpretive/procedural/persuasive; a NON-holding is its reason —
// application (fact-bound) or obiter (not decided). Other pairings contradict.
const HOLDING_TYPES = new Set(["binding", "interpretive", "procedural", "persuasive"]);
const NON_HOLDING_TYPES = new Set(["application", "obiter"]);

function inconsistentTag(it: GoldsetItem): string | null {
  if (it.is_holding === null || !it.correct_type) return null;
  if (it.is_holding === true && NON_HOLDING_TYPES.has(it.correct_type)) {
    return "סימנת \"הלכה\" אך הסוג הוא יישום/אמרת-אגב — אלה דווקא הסיבות שמשהו אינו הלכה.";
  }
  if (it.is_holding === false && HOLDING_TYPES.has(it.correct_type)) {
    return "סימנת \"לא הלכה\" אך הסוג מציין הלכה (מחייבת/פרשני/…); ל\"לא\" מתאים יישום או אמרת-אגב.";
  }
  return null;
}

const FLAG_LABELS: Record<string, string> = {
  non_decision: "אי-הכרעה", truncated_quote: "ציטוט קטוע", thin_restatement: "ניסוח דק",
  quote_unverified: "ציטוט לא מאומת", nli_unsupported: "כלל לא נגזר", application: "יישום",
  near_duplicate: "כפילות-קרובה", nevo_preamble_leak: "דליפת רציו",
};

function cleanCitation(s: string | null | undefined): string {
  if (!s) return "—";
  return s.replace(/[‎‏‪-‮⁦-⁩]/g, "").trim();
}

// Source separation (פסקי-דין מול החלטות ועדת-ערר) for convenient tagging.
function sourceLabel(s: string | null): string {
  return s === "court_ruling" ? "פסק-דין"
    : s === "appeals_committee" ? "ועדת ערר" : "אחר";
}
const SOURCE_FILTERS: { value: "all" | "court_ruling" | "appeals_committee"; label: string }[] = [
  { value: "all", label: "הכל" },
  { value: "court_ruling", label: "פסקי דין" },
  { value: "appeals_committee", label: "ועדת ערר" },
];

function isTagged(it: GoldsetItem): boolean {
  // Fully tagged only when ALL THREE answers are set — otherwise, in
  // "hide tagged" mode, a card would vanish the moment is_holding is clicked,
  // before correct_type / quote_complete can be set.
  return it.is_holding !== null && it.quote_complete !== null && !!it.correct_type;
}

// The AI second-opinion disagrees with the human tag (on is_holding or type).
function aiDisagrees(it: GoldsetItem): boolean {
  if (!it.ai_generated_at) return false;
  const holdDiff = it.is_holding !== null && it.ai_is_holding !== null
    && it.is_holding !== it.ai_is_holding;
  const typeDiff = !!it.correct_type && !!it.ai_correct_type
    && it.correct_type !== it.ai_correct_type;
  return holdDiff || typeDiff;
}

// ─── Score panel ──────────────────────────────────────────────────────────────

function ScorePanel({ batch }: { batch: string }) {
  const { data } = useGoldsetScore(batch);
  const [open, setOpen] = useState(true);
  if (!data || data.labeled === 0) return null;
  const rows = Object.entries(data.validators);
  // negatives so far (truly "not a holding") = tp+fn of any validator.
  const af = data.validators.any_flag;
  const negatives = af ? af.tp + af.fn : 0;
  return (
    <div className="rounded-lg border border-rule bg-surface">
      <button
        type="button"
        onClick={() => setOpen((v) => !v)}
        className="w-full flex items-center gap-2 px-4 py-2.5 text-sm hover:bg-gold-wash/30"
        aria-expanded={open}
      >
        {open ? <ChevronDown className="w-4 h-4" /> : <ChevronLeft className="w-4 h-4" />}
        <span className="font-semibold text-navy">ציון הוולידטורים מול התיוג</span>
        <span className="text-ink-muted">({data.labeled} מתויגות)</span>
      </button>
      {open && (
        <div className="px-4 pb-3 overflow-x-auto">
          <p className="text-[0.72rem] text-ink-muted mb-2">
            המדדים מודדים זיהוי <strong>"לא-הלכה"</strong> (יישום / ציטוט-קטוע / אי-הכרעה...).
            {negatives < 10
              ? ` עד כה תויגו רק ${negatives} פריטי "לא הלכה" — המספרים יהפכו משמעותיים ככל שיצטברו עוד (במיוחד מבקט המסומנים).`
              : " precision גבוה = מעט אזעקות-שווא; recall גבוה = תופס את רוב ה'לא-הלכה'."}
          </p>
          <table className="w-full text-sm tabular-nums">
            <thead>
              <tr className="text-ink-muted text-[0.72rem] border-b border-rule">
                <th className="text-start py-1 ps-1">ולידטור</th>
                <th className="text-start">Precision</th>
                <th className="text-start">Recall</th>
                <th className="text-start">F1</th>
                <th className="text-start">tp/fp/fn/tn</th>
              </tr>
            </thead>
            <tbody>
              {rows.map(([name, v]) => (
                <tr key={name} className="border-b border-rule-soft last:border-0">
                  <td className="py-1 ps-1 text-navy">{name}</td>
                  <td>{v.precision.toFixed(2)}</td>
                  <td>{v.recall.toFixed(2)}</td>
                  <td className="font-semibold">{v.f1.toFixed(2)}</td>
                  <td className="text-ink-muted text-[0.72rem]">
                    {v.tp}/{v.fp}/{v.fn}/{v.tn}
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      )}
    </div>
  );
}

// ─── Rule-type help (info popover) ────────────────────────────────────────────

const TYPE_HELP: { label: string; def: string; test: string; example: string }[] = [
  {
    label: "מחייבת",
    def: "העיקרון שהיה הכרחי להכרעה — ה-holding האמיתי. בר-הסתמכות מלא.",
    test: "מבחן וומבו: הפוך את הכלל — אם התוצאה הייתה משתנה → מחייבת.",
    example: "נטל ההוכחה בהיטל השבחה מוטל על הוועדה המקומית.",
  },
  {
    label: "פרשני",
    def: "קביעה שמפרשת הוראת-חוק / מונח / תכנית (מה המשמעות של סעיף X).",
    test: "עונה ל'מה פירוש הנורמה?' ולא ל'מה הדין?'.",
    example: "תכלית הפטור לפי ס' 19(ב)(4) היא לעודד פעילות ציבורית.",
  },
  {
    label: "יישום",
    def: "החלת כלל על עובדות התיק הספציפי — תלוי-עובדות, לא בר-הכללה (לרוב 'לא הלכה').",
    test: "מכיל 'במקרה דנן', שמות-צדדים, סכומים, המבנה הקונקרטי.",
    example: "במקרה דנן ההיתר בטל כי השומה שגתה ב-12,000 ₪.",
  },
  {
    label: "אמרת-אגב",
    def: "נאמר אגב אורחא, לא הכרחי להכרעה; הערכאה לא הכריעה בו. לא מחייב.",
    test: "מבחן וומבו הפוך: היפוך הכלל לא משנה את התוצאה. דגלים: 'למעלה מן הצורך', 'מבלי לקבוע מסמרות'.",
    example: "אף שאיננו נדרשים להכריע, נעיר כי ייתכן ש...",
  },
  {
    label: "פרוצדורלי",
    def: "כלל סדר-דין: מועדים, סמכות, זכות-עמידה, מיצוי הליכים, נטל.",
    test: "עוסק ב'איך' מתנהל ההליך, לא במהות התכנונית.",
    example: "המועד להגשת ערר הוא 30 יום.",
  },
  {
    label: "משכנע",
    def: "אסמכתה לא-מחייבת את הערכאה — שכנוע בלבד.",
    test: "מקור שאינו כובל: ועדת-ערר אחרת, דעת-מיעוט, ספרות.",
    example: "ועדת ערר ירושלים מסתמכת על החלטת ועדת ערר ממחוז אחר.",
  },
];

function RuleTypeHelp() {
  return (
    <Popover>
      <PopoverTrigger asChild>
        <button
          type="button"
          className="inline-flex items-center text-ink-muted hover:text-gold-deep"
          aria-label="הסבר על סוגי ההלכה"
          title="הסבר על הסוגים"
        >
          <Info className="w-3.5 h-3.5" />
        </button>
      </PopoverTrigger>
      <PopoverContent align="start" className="w-[min(92vw,560px)] max-h-[70vh] overflow-y-auto p-0">
        <div className="p-3 border-b border-rule">
          <p className="font-semibold text-navy text-sm">סוגי ההלכה — במה הם נבדלים</p>
          <p className="text-[0.72rem] text-ink-muted mt-0.5">
            כלל-אצבע: סימנת "הלכה" → לרוב מחייבת / פרשני / פרוצדורלי / משכנע. סימנת "לא" → לרוב יישום / אמרת-אגב.
          </p>
        </div>
        <ul className="divide-y divide-rule-soft">
          {TYPE_HELP.map((t) => (
            <li key={t.label} className="p-3 space-y-1" dir="rtl">
              <div className="font-semibold text-navy text-sm">{t.label}</div>
              <div className="text-[0.78rem] text-ink-soft leading-relaxed">{t.def}</div>
              <div className="text-[0.72rem] text-ink-muted"><span className="font-medium">מבחן:</span> {t.test}</div>
              <div className="text-[0.72rem] text-ink-muted"><span className="font-medium">דוגמה:</span> {t.example}</div>
            </li>
          ))}
        </ul>
      </PopoverContent>
    </Popover>
  );
}

// ─── Tag card ─────────────────────────────────────────────────────────────────

function TagCard({
  it, focused, onTag,
}: {
  it: GoldsetItem;
  focused: boolean;
  onTag: (tag: { is_holding?: boolean; correct_type?: string; quote_complete?: boolean }) => void;
}) {
  const tagged = isTagged(it);
  return (
    <div
      data-goldset-id={it.id}
      className={`rounded-lg border bg-surface p-4 space-y-3 transition-colors
        ${focused ? "border-gold ring-2 ring-gold/40 shadow-md" : tagged ? "border-rule-soft opacity-70" : "border-rule"}`}
    >
      <div className="flex items-center gap-2 text-[0.72rem] text-ink-muted flex-wrap">
        <span className="font-semibold text-navy">{cleanCitation(it.case_number)}</span>
        <Badge variant="outline"
          className={`text-[0.65rem] ${it.source_type === "court_ruling"
            ? "bg-navy-soft/30 text-navy border-navy/30"
            : "bg-gold-wash text-gold-deep border-gold/40"}`}>
          {sourceLabel(it.source_type)}
        </Badge>
        <Badge variant="outline" className="text-[0.65rem]">מכונה: {it.rule_type}</Badge>
        {it.confidence != null && (
          <Badge variant="outline" className="text-[0.65rem] tabular-nums">ביטחון {it.confidence.toFixed(2)}</Badge>
        )}
        {(it.quality_flags ?? []).map((f) => (
          <Badge key={f} variant="outline" className="text-[0.65rem] bg-danger-bg text-danger border-danger/40">
            {FLAG_LABELS[f] ?? f}
          </Badge>
        ))}
        {tagged && (
          <Badge variant="outline" className="text-[0.65rem] bg-gold-wash text-gold-deep border-gold/40 ms-auto">
            <Check className="w-3 h-3 me-1" /> תויג
          </Badge>
        )}
      </div>

      <p className="text-navy font-medium leading-relaxed" dir="rtl">{it.rule_statement}</p>
      <blockquote className="text-ink-soft text-sm leading-relaxed border-r-2 border-gold pr-3" dir="rtl">
        &ldquo;{it.supporting_quote}&rdquo;
      </blockquote>

      {it.ai_generated_at && (() => {
        const aiType = TYPES.find((t) => t.value === it.ai_correct_type)?.label ?? it.ai_correct_type;
        const holdDisagree = it.is_holding !== null && it.ai_is_holding !== null
          && it.is_holding !== it.ai_is_holding;
        const typeDisagree = !!it.correct_type && !!it.ai_correct_type
          && it.correct_type !== it.ai_correct_type;
        const anyTag = it.is_holding !== null || !!it.correct_type;
        return (
          <div className={`rounded-md border p-2.5 text-[0.78rem] space-y-1
            ${holdDisagree ? "border-amber-400 bg-amber-50" : "border-rule bg-rule-soft/20"}`} dir="rtl">
            <div className="flex items-center gap-2 flex-wrap">
              <span className="font-semibold text-navy">🤖 המלצת AI:</span>
              <span>{it.ai_is_holding ? "הלכה" : "לא הלכה"}</span>
              {aiType && <span className="text-ink-muted">· {aiType}</span>}
              {anyTag && (
                <span className={`ms-auto text-[0.7rem] px-1.5 py-0.5 rounded
                  ${holdDisagree || typeDisagree
                    ? "bg-amber-100 text-amber-800"
                    : "bg-emerald-50 text-emerald-700"}`}>
                  {holdDisagree ? "⚠ חולק על 'הלכה/לא'"
                    : typeDisagree ? "⚠ חולק על הסוג"
                    : "✓ מסכים איתך"}
                </span>
              )}
            </div>
            {it.ai_rationale && <div className="text-ink-soft leading-relaxed">{it.ai_rationale}</div>}
          </div>
        );
      })()}

      <div className="grid gap-3 sm:grid-cols-3 pt-1 border-t border-rule-soft">
        {/* is_holding */}
        <div>
          <div className="text-[0.7rem] text-ink-muted mb-1">האם זו הלכה אמיתית?</div>
          <div className="flex gap-1">
            <Button size="sm" variant={it.is_holding === true ? "default" : "ghost"}
              className={it.is_holding === true ? "bg-gold text-navy hover:bg-gold-deep" : ""}
              onClick={() => onTag({ is_holding: true })}>הלכה (H)</Button>
            <Button size="sm" variant={it.is_holding === false ? "default" : "ghost"}
              className={it.is_holding === false ? "bg-danger text-parchment hover:bg-danger" : "text-danger"}
              onClick={() => onTag({ is_holding: false })}>לא (N)</Button>
          </div>
        </div>
        {/* correct_type */}
        <div>
          <div className="text-[0.7rem] text-ink-muted mb-1 flex items-center gap-1">
            הסוג הנכון
            <RuleTypeHelp />
          </div>
          <div className="flex gap-1 flex-wrap">
            {TYPES.map((t) => (
              <Button key={t.value} size="sm"
                variant={it.correct_type === t.value ? "default" : "ghost"}
                className={`text-[0.7rem] px-2 ${it.correct_type === t.value ? "bg-navy text-parchment hover:bg-navy-soft" : ""}`}
                onClick={() => onTag({ correct_type: t.value })}>{t.label}</Button>
            ))}
          </div>
          {inconsistentTag(it) && (
            <p className="mt-1 text-[0.68rem] text-amber-700 flex items-start gap-1">
              <AlertTriangle className="w-3 h-3 mt-0.5 shrink-0" />
              {inconsistentTag(it)}
            </p>
          )}
        </div>
        {/* quote_complete */}
        <div>
          <div className="text-[0.7rem] text-ink-muted mb-1">הציטוט שלם?</div>
          <div className="flex gap-1">
            <Button size="sm" variant={it.quote_complete === true ? "default" : "ghost"}
              className={it.quote_complete === true ? "bg-gold text-navy hover:bg-gold-deep" : ""}
              onClick={() => onTag({ quote_complete: true })}>שלם (C)</Button>
            <Button size="sm" variant={it.quote_complete === false ? "default" : "ghost"}
              className={it.quote_complete === false ? "bg-danger text-parchment hover:bg-danger" : "text-danger"}
              onClick={() => onTag({ quote_complete: false })}>קטוע (X)</Button>
          </div>
        </div>
      </div>
    </div>
  );
}

// ─── Main panel ───────────────────────────────────────────────────────────────

export function GoldsetPanel() {
  const batch = "default";
  const { data, isPending, error } = useGoldset(batch);
  const tag = useTagGoldset(batch);
  const createSample = useCreateGoldsetSample(batch);
  const [focusedId, setFocusedId] = useState<string | null>(null);
  // Single mutually-exclusive view mode — can't get "stuck" like the old
  // independent toggles (where the disagree filter hid the untagged items).
  const [viewMode, setViewMode] =
    useState<"all" | "untagged" | "tagged" | "disagree">("all");
  const [sourceFilter, setSourceFilter] =
    useState<"all" | "court_ruling" | "appeals_committee">("all");

  const items = useMemo(() => data?.items ?? [], [data]);
  const taggedCount = items.filter(isTagged).length;
  const untaggedCount = items.length - taggedCount;
  const disagreeCount = items.filter(aiDisagrees).length;
  const sourceCounts = useMemo(() => ({
    court_ruling: items.filter((i) => i.source_type === "court_ruling").length,
    appeals_committee: items.filter((i) => i.source_type === "appeals_committee").length,
  }), [items]);
  const visible = useMemo(() => {
    let v = items;
    if (sourceFilter !== "all") v = v.filter((i) => i.source_type === sourceFilter);
    if (viewMode === "untagged") v = v.filter((i) => !isTagged(i));
    else if (viewMode === "tagged") v = v.filter(isTagged);
    else if (viewMode === "disagree") v = v.filter(aiDisagrees);
    // group-sort: כל פסקי-הדין יחד, ואז כל החלטות ועדת-הערר (הפרדה ברורה).
    const order = (s: string | null) =>
      s === "court_ruling" ? 0 : s === "appeals_committee" ? 1 : 2;
    return [...v].sort((a, b) => order(a.source_type) - order(b.source_type));
  }, [items, viewMode, sourceFilter]);

  const focused = focusedId ? visible.find((i) => i.id === focusedId) ?? null : null;

  useEffect(() => {
    if (focusedId && visible.some((i) => i.id === focusedId)) return;
    setFocusedId(visible[0]?.id ?? null);
  }, [focusedId, visible]);

  useEffect(() => {
    if (!focusedId) return;
    document.querySelector(`[data-goldset-id="${focusedId}"]`)
      ?.scrollIntoView({ block: "nearest", behavior: "smooth" });
  }, [focusedId]);

  const move = (delta: 1 | -1) => {
    if (!visible.length) return;
    const idx = focusedId ? visible.findIndex((i) => i.id === focusedId) : -1;
    const next = idx < 0 ? (delta > 0 ? 0 : visible.length - 1)
      : Math.max(0, Math.min(visible.length - 1, idx + delta));
    setFocusedId(visible[next].id);
  };

  const doTag = async (
    it: GoldsetItem,
    t: { is_holding?: boolean; correct_type?: string; quote_complete?: boolean },
  ) => {
    try {
      await tag.mutateAsync({ id: it.id, tag: t });
    } catch (e) {
      toast.error(e instanceof Error ? e.message : "שגיאה");
    }
  };

  useEffect(() => {
    const onKey = (e: KeyboardEvent) => {
      const tagName = (e.target as HTMLElement)?.tagName?.toLowerCase();
      if (tagName === "input" || tagName === "textarea" || tagName === "select") return;
      if (e.key === "j") { e.preventDefault(); move(1); }
      else if (e.key === "k") { e.preventDefault(); move(-1); }
      else if (focused && (e.key === "h" || e.key === "H")) { e.preventDefault(); doTag(focused, { is_holding: true }); }
      else if (focused && (e.key === "n" || e.key === "N")) { e.preventDefault(); doTag(focused, { is_holding: false }); }
      else if (focused && (e.key === "c" || e.key === "C")) { e.preventDefault(); doTag(focused, { quote_complete: true }); }
      else if (focused && (e.key === "x" || e.key === "X")) { e.preventDefault(); doTag(focused, { quote_complete: false }); }
    };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [focused, visible]);

  if (error) {
    return <div className="rounded bg-danger-bg border border-danger/40 px-6 py-5 text-danger text-center">{error.message}</div>;
  }
  if (isPending) {
    return <div className="space-y-3">{[...Array(3)].map((_, i) => <Skeleton key={i} className="h-40 w-full" />)}</div>;
  }
  if (!items.length) {
    return (
      <div className="text-center text-ink-muted py-16 space-y-4">
        <p className="text-lg">אין מדגם-זהב עדיין.</p>
        <Button disabled={createSample.isPending}
          onClick={() => createSample.mutate(150)}
          className="bg-gold text-navy hover:bg-gold-deep">
          צור מדגם של 150 הלכות לתיוג
        </Button>
      </div>
    );
  }

  const pct = items.length ? Math.round((taggedCount / items.length) * 100) : 0;

  return (
    <div className="space-y-4">
      <ScorePanel batch={batch} />

      {/* source separation — פסקי-דין מול החלטות ועדת-ערר */}
      <div className="flex items-center gap-1 rounded-lg border border-rule p-0.5 bg-rule-soft/30 w-fit">
        {SOURCE_FILTERS.map((s) => (
          <Button key={s.value} size="sm"
            variant={sourceFilter === s.value ? "default" : "ghost"}
            className={sourceFilter === s.value ? "bg-gold text-navy hover:bg-gold-deep" : ""}
            onClick={() => setSourceFilter(s.value)}>
            {s.label}
            {s.value === "court_ruling" && ` (${sourceCounts.court_ruling})`}
            {s.value === "appeals_committee" && ` (${sourceCounts.appeals_committee})`}
          </Button>
        ))}
      </div>

      <div className="flex items-center gap-3 flex-wrap text-sm">
        <span className="text-navy font-semibold tabular-nums">{taggedCount}/{items.length} תויגו</span>
        <div className="h-2 w-40 rounded-full bg-rule-soft overflow-hidden">
          <div className="h-full bg-gold" style={{ width: `${pct}%` }} />
        </div>
        <span className="text-ink-muted text-[0.72rem]">
          מקלדת: <kbd className="bg-rule-soft px-1.5 rounded">J</kbd>/<kbd className="bg-rule-soft px-1.5 rounded">K</kbd>
          {" "}· הלכה <kbd className="bg-rule-soft px-1.5 rounded">H</kbd> / לא <kbd className="bg-rule-soft px-1.5 rounded">N</kbd>
          {" "}· ציטוט שלם <kbd className="bg-rule-soft px-1.5 rounded">C</kbd> / קטוע <kbd className="bg-rule-soft px-1.5 rounded">X</kbd>
        </span>
        <div className="ms-auto flex items-center gap-1 rounded-lg border border-rule p-0.5 bg-rule-soft/30">
          {([
            { v: "all", label: `הכל (${items.length})` },
            { v: "untagged", label: `לא תויגו (${untaggedCount})` },
            { v: "tagged", label: `תויגו (${taggedCount})` },
            { v: "disagree", label: `⚠ אי-הסכמות (${disagreeCount})` },
          ] as const).map((m) => (
            <Button key={m.v} size="sm"
              variant={viewMode === m.v ? "default" : "ghost"}
              className={viewMode === m.v
                ? (m.v === "disagree" ? "bg-amber-500 text-white hover:bg-amber-600" : "bg-gold text-navy hover:bg-gold-deep")
                : (m.v === "disagree" ? "text-amber-700" : "")}
              onClick={() => setViewMode(m.v)}>
              {m.label}
            </Button>
          ))}
        </div>
      </div>

      <div className="space-y-3">
        {visible.map((it) => (
          <TagCard key={it.id} it={it} focused={it.id === focusedId}
            onTag={(t) => doTag(it, t)} />
        ))}
      </div>
    </div>
  );
}
