"use client";

import { useState } from "react";
import { CheckCircle2, Loader2, Sparkles } from "lucide-react";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Switch } from "@/components/ui/switch";
import {
  Popover,
  PopoverContent,
  PopoverTrigger,
} from "@/components/ui/popover";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";
import {
  APPRAISER_SIDE_LABELS,
  APPRAISER_SIDE_OPTIONS,
  DOC_TYPE_OPTIONS,
  PROTOCOL_SCOPE_OPTIONS,
  appraiserSideLabel,
  doctypeLabel,
  doctypeTone,
  type AppraiserSide,
  type DocType,
} from "@/lib/doc-types";
import {
  useExtractAppraiserFacts,
  usePatchDocument,
  type DocumentPatch,
  type ExtractAppraiserFactsResponse,
} from "@/lib/api/documents";

/*
 * Inline editor for a document's tags. Renders a colored Badge that opens a
 * Popover with:
 *   1. doc_type (always shown)
 *   2. appraiser_side  (only when doc_type === "appraisal")
 *   3. protocol_scope  (only when doc_type === "protocol") — ועדת הערר / מקומית
 *   4. is_post_hearing toggle (always shown) — moves the doc to overview group 4
 *
 * After a successful save we swap the Popover body to a confirmation view
 * with a "חלץ עובדות שמאיות עכשיו" button — extraction is expensive so we
 * never run it silently on save; the chair clicks this when they're done
 * tagging all appraisals in the case.
 */

export function DocumentTypeEditor({
  caseNumber,
  docId,
  docType,
  appraiserSide,
  isPostHearing,
  protocolScope,
}: {
  caseNumber: string;
  docId: string;
  docType: string;
  appraiserSide?: string;
  isPostHearing?: boolean;
  protocolScope?: string;
}) {
  // Effective stored scope: absent === "appeal" (ועדת הערר) by convention.
  const storedScope = protocolScope === "lower" ? "lower" : "appeal";
  const storedPost = isPostHearing === true;

  const [open, setOpen] = useState(false);
  const [draftType, setDraftType] = useState<string>(docType || "");
  const [draftSide, setDraftSide] = useState<string>(appraiserSide || "");
  const [draftScope, setDraftScope] = useState<string>(storedScope);
  const [draftPost, setDraftPost] = useState<boolean>(storedPost);
  const [saved, setSaved] = useState(false);
  const [extractResult, setExtractResult] =
    useState<ExtractAppraiserFactsResponse | null>(null);
  const patch = usePatchDocument(caseNumber);
  const extract = useExtractAppraiserFacts(caseNumber);

  function reset() {
    setDraftType(docType || "");
    setDraftSide(appraiserSide || "");
    setDraftScope(storedScope);
    setDraftPost(storedPost);
    setSaved(false);
    setExtractResult(null);
    patch.reset();
    extract.reset();
  }

  const isAppraisal = draftType === "appraisal";
  const isProtocol = draftType === "protocol";
  const sideMissing = isAppraisal && !draftSide;
  const dirty =
    draftType !== docType ||
    (isAppraisal && draftSide !== (appraiserSide || "")) ||
    (isProtocol && draftScope !== storedScope) ||
    draftPost !== storedPost;

  async function handleSave() {
    if (sideMissing || !dirty) return;
    const body: DocumentPatch = {};
    if (draftType !== docType) body.doc_type = draftType;
    if (isAppraisal && draftSide !== (appraiserSide || "")) {
      body.appraiser_side = draftSide;
    }
    // If the new type is NOT appraisal but the doc previously had a side,
    // clear it so it doesn't dangle confusingly in metadata.
    if (!isAppraisal && appraiserSide) body.appraiser_side = "";

    // protocol_scope: store only the non-default "lower"; anything else clears
    // back to the implicit ועדת-הערר default. Also clear when leaving protocol.
    if (isProtocol && draftScope !== storedScope) {
      body.protocol_scope = draftScope === "lower" ? "lower" : "";
    } else if (!isProtocol && protocolScope) {
      body.protocol_scope = "";
    }

    if (draftPost !== storedPost) body.is_post_hearing = draftPost;

    // Swallow the rejection — errors surface via `patch.isError`; an unhandled
    // rejection from this async click handler would otherwise leak.
    try {
      await patch.mutateAsync({ docId, patch: body });
      setSaved(true);
    } catch {
      /* surfaced via patch.isError */
    }
  }

  async function handleExtract() {
    try {
      const result = await extract.mutateAsync();
      setExtractResult(result);
    } catch {
      /* surfaced via extract.isError */
    }
  }

  // Build the on-badge label: "שומה · שמאי הוועדה" when both present.
  const badgeText =
    docType === "appraisal" && appraiserSide
      ? `${doctypeLabel(docType)} · ${appraiserSideLabel(appraiserSide)}`
      : doctypeLabel(docType);

  return (
    <Popover
      open={open}
      onOpenChange={(next) => {
        setOpen(next);
        if (next) reset();
      }}
    >
      <PopoverTrigger asChild>
        <button
          type="button"
          className="shrink-0 cursor-pointer outline-none focus-visible:ring-2 focus-visible:ring-gold/50 rounded-full"
          title="לחץ לשינוי תיוג"
        >
          <Badge
            variant="outline"
            className={`rounded-full px-2 py-0.5 text-[0.7rem] ${doctypeTone(docType)} hover:opacity-80`}
          >
            {badgeText}
          </Badge>
        </button>
      </PopoverTrigger>
      <PopoverContent className="w-80 space-y-3" align="end" dir="rtl">
        {saved ? (
          <PostSaveView
            isAppraisal={isAppraisal}
            extract={extract}
            extractResult={extractResult}
            onExtract={handleExtract}
            onClose={() => setOpen(false)}
          />
        ) : (
          <>
            <div className="space-y-1.5">
              <label className="text-xs text-ink-muted">סוג מסמך</label>
              <Select value={draftType} onValueChange={setDraftType} dir="rtl">
                <SelectTrigger className="w-full">
                  <SelectValue placeholder="בחר סוג" />
                </SelectTrigger>
                <SelectContent>
                  {DOC_TYPE_OPTIONS.map((opt) => (
                    <SelectItem key={opt.value} value={opt.value}>
                      {opt.label}
                    </SelectItem>
                  ))}
                </SelectContent>
              </Select>
            </div>

            {isAppraisal && (
              <div className="space-y-1.5">
                <label className="text-xs text-ink-muted">צד השמאי</label>
                <Select value={draftSide} onValueChange={setDraftSide} dir="rtl">
                  <SelectTrigger className="w-full">
                    <SelectValue placeholder="בחר צד" />
                  </SelectTrigger>
                  <SelectContent>
                    {APPRAISER_SIDE_OPTIONS.map((opt) => (
                      <SelectItem key={opt.value} value={opt.value}>
                        {opt.label}
                      </SelectItem>
                    ))}
                  </SelectContent>
                </Select>
                {sideMissing && (
                  <p className="text-[0.7rem] text-warn">
                    נדרש לציין את הצד לפני חילוץ עובדות שמאיות.
                  </p>
                )}
                <p className="text-[0.65rem] text-ink-muted leading-tight">
                  ערכים: {Object.values(APPRAISER_SIDE_LABELS).join(" · ")}
                </p>
              </div>
            )}

            {isProtocol && (
              <div className="space-y-1.5">
                <label className="text-xs text-ink-muted">פרוטוקול של</label>
                <Select value={draftScope} onValueChange={setDraftScope} dir="rtl">
                  <SelectTrigger className="w-full">
                    <SelectValue />
                  </SelectTrigger>
                  <SelectContent>
                    {PROTOCOL_SCOPE_OPTIONS.map((opt) => (
                      <SelectItem key={opt.value} value={opt.value}>
                        {opt.label}
                      </SelectItem>
                    ))}
                  </SelectContent>
                </Select>
                <p className="text-[0.65rem] text-ink-muted leading-tight">
                  ועדת הערר → קבוצת הפרוטוקול · מקומית/מחוזית → מסמכים נלווים
                </p>
              </div>
            )}

            <div className="flex items-start justify-between gap-3 rounded-md border border-rule bg-parchment/40 px-3 py-2.5">
              <div className="space-y-0.5">
                <label
                  htmlFor={`post-${docId}`}
                  className="text-xs font-medium text-ink block"
                >
                  התקבל אחרי הדיון
                </label>
                <p className="text-[0.65rem] text-ink-muted leading-tight">
                  מעביר את המסמך לקבוצת המסמכים שלאחר הדיון ומזין את בלוק-ח
                </p>
              </div>
              <Switch
                id={`post-${docId}`}
                checked={draftPost}
                onCheckedChange={setDraftPost}
              />
            </div>

            {patch.isError && (
              <p className="text-[0.7rem] text-danger">
                שמירה נכשלה. נסה שוב.
              </p>
            )}

            <div className="flex justify-end gap-2 pt-1">
              <Button
                type="button"
                variant="ghost"
                size="sm"
                onClick={() => setOpen(false)}
                disabled={patch.isPending}
              >
                ביטול
              </Button>
              <Button
                type="button"
                size="sm"
                onClick={handleSave}
                disabled={!dirty || sideMissing || patch.isPending}
              >
                {patch.isPending && (
                  <Loader2 className="w-3.5 h-3.5 animate-spin" />
                )}
                שמור
              </Button>
            </div>
          </>
        )}
      </PopoverContent>
    </Popover>
  );
}

// Re-export types so callers don't need to dual-import.
export type { AppraiserSide, DocType };


/* ── Post-save view: saved confirmation + extract action ─────────────
 *
 * Extraction is case-scoped (runs across every appraisal tagged in the
 * case), so the button sits here rather than per-doc. If the chair is
 * mid-tagging, clicking extract may return sides_missing with the list
 * of still-untagged appraisals — we surface that list instead of a
 * generic error.
 */

function PostSaveView({
  isAppraisal,
  extract,
  extractResult,
  onExtract,
  onClose,
}: {
  isAppraisal: boolean;
  extract: ReturnType<typeof useExtractAppraiserFacts>;
  extractResult: ExtractAppraiserFactsResponse | null;
  onExtract: () => void;
  onClose: () => void;
}) {
  const pending = extract.isPending;

  return (
    <div className="space-y-3">
      <div className="flex items-center gap-2 text-success">
        <CheckCircle2 className="w-4 h-4" />
        <span className="text-sm font-medium">התיוג נשמר</span>
      </div>

      {isAppraisal && !extractResult && (
        <p className="text-[0.72rem] text-ink-muted leading-relaxed">
          ההתגיה עודכנה. אם סיימת לתייג את כל השומות בתיק, הפעל חילוץ
          עובדות שמאיות (תכניות + היתרים + סתירות בין שמאים).
        </p>
      )}

      {extractResult?.status === "completed" && (
        <div className="rounded-md border border-success/30 bg-success-bg px-2.5 py-2 text-[0.72rem] text-ink space-y-0.5">
          <p>
            <strong>הושלם.</strong> חולצו {extractResult.total_facts} עובדות
            מ-{extractResult.appraisal_count} שומות.
          </p>
          {extractResult.conflicts.length > 0 && (
            <p>זוהו {extractResult.conflicts.length} סתירות בין שמאים.</p>
          )}
        </div>
      )}

      {extractResult?.status === "queued" && (
        <div className="rounded-md border border-info/30 bg-info-bg px-2.5 py-2 text-[0.72rem] text-ink space-y-0.5">
          <p>
            <strong>נשלח לאנליטיקאי.</strong> ה-issue נפתח ב-Paperclip והחילוץ
            ירוץ ברקע. תראה comment בעברית עם התוצאה כשהוא יסיים — לרוב כמה
            דקות.
          </p>
        </div>
      )}

      {extractResult?.status === "skipped" && (
        <div className="rounded-md border border-warn/40 bg-warn-bg px-2.5 py-2 text-[0.72rem] text-ink space-y-0.5">
          <p>
            <strong>לא ניתן להפעיל אוטומטית</strong> ({extractResult.reason}).
            הפעל ידנית מ-Claude Code:
            <code className="ms-1 select-all">mcp__legal-ai__extract_appraiser_facts</code>
          </p>
        </div>
      )}

      {extractResult?.status === "no_appraisals" && (
        <p className="text-[0.72rem] text-ink-muted">
          אין בתיק מסמכים מתויגים כ-שומה.
        </p>
      )}

      {extractResult?.status === "sides_missing" && (
        <div className="rounded-md border border-warn/40 bg-warn-bg px-2.5 py-2 text-[0.72rem] text-ink space-y-1">
          <p>
            נותרו {extractResult.missing.length} שומות ללא תיוג צד. תייג אותן
            לפני הפעלת החילוץ:
          </p>
          <ul className="list-disc ps-4 space-y-0.5">
            {extractResult.missing.map((m) => (
              <li key={m.document_id} className="truncate">
                {m.title}
              </li>
            ))}
          </ul>
        </div>
      )}

      {extract.isError && !extractResult && (
        <p className="text-[0.72rem] text-danger">
          החילוץ נכשל. נסה שוב.
        </p>
      )}

      <div className="flex justify-end gap-2 pt-1">
        <Button type="button" variant="ghost" size="sm" onClick={onClose}>
          סגור
        </Button>
        {isAppraisal && (
          <Button
            type="button"
            size="sm"
            onClick={onExtract}
            disabled={pending}
          >
            {pending ? (
              <Loader2 className="w-3.5 h-3.5 animate-spin" />
            ) : (
              <Sparkles className="w-3.5 h-3.5" />
            )}
            {extractResult ? "הפעל שוב" : "חלץ עובדות שמאיות עכשיו"}
          </Button>
        )}
      </div>

      {pending && (
        <p className="text-[0.68rem] text-ink-muted leading-tight">
          שולח לאנליטיקאי דרך Paperclip — לוקח שנייה. החילוץ עצמו ירוץ אצל
          האנליטיקאי וייתן comment כשיסיים.
        </p>
      )}
    </div>
  );
}
