"use client";

import { useMemo, useState } from "react";
import { Card, CardContent } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { Input } from "@/components/ui/input";
import { EmptyState } from "@/components/ui/empty-state";
import { useAlertConfirm } from "@/components/ui/alert-dialog";
import { useLocalStorage } from "@/lib/hooks/use-local-storage";
import { ALL_ORGANIZATIONS } from "@/lib/sag/entities";
import { formatDate } from "@/lib/utils";
import { DocChat } from "@/components/app/doc-chat";
import { DocOcrButton } from "@/components/app/doc-ocr-button";
import { snapshotForAgentCall } from "@/lib/agents/context-snapshot";
import { EntityLinkedText } from "@/lib/docs/entity-link-renderer";

type DocType =
  | "Articles of Organization"
  | "EIN Letter (CP575)"
  | "Operating Agreement"
  | "License / Permit"
  | "Contract"
  | "Lease"
  | "Insurance"
  | "Tax Return"
  | "Bank Statement"
  | "Other";

const DOC_TYPES: DocType[] = [
  "Articles of Organization",
  "EIN Letter (CP575)",
  "Operating Agreement",
  "License / Permit",
  "Contract",
  "Lease",
  "Insurance",
  "Tax Return",
  "Bank Statement",
  "Other",
];

export interface VaultDoc {
  id: string;
  organizationSlug: string;
  docType: DocType;
  name: string;
  notes?: string;
  /** Local file:// link or OneDrive path the user pastes — not uploaded. */
  externalUrl?: string;
  /** Optional base64-inline storage for small docs (<= 500KB). */
  inlineData?: string;
  inlineMimeType?: string;
  fileSize?: number;
  aiSummary?: string;
  /** Full document body text extracted via Claude vision OCR (D1). */
  extractedText?: string;
  /** ISO timestamp when OCR was last run. */
  ocrAt?: string;
  /** Claude model used for OCR. */
  ocrModel?: string;
  uploadedAt: string;
}

const MAX_INLINE_BYTES = 500 * 1024;

export function DocumentVault() {
  const [docs, setDocs] = useLocalStorage<VaultDoc[]>("sag.docs", []);
  const [showAdd, setShowAdd] = useState(false);
  const [filterEntity, setFilterEntity] = useState<string>("all");
  const [filterType, setFilterType] = useState<DocType | "all">("all");
  const [search, setSearch] = useState("");
  const [summarizing, setSummarizing] = useState<string | null>(null);
  const [chattingId, setChattingId] = useState<string | null>(null);
  const [bodyOpenId, setBodyOpenId] = useState<string | null>(null);
  const { confirm: confirmAlert, AlertConfirmPortal } = useAlertConfirm();

  const filtered = useMemo(() => {
    return docs.filter((d) => {
      if (filterEntity !== "all" && d.organizationSlug !== filterEntity) return false;
      if (filterType !== "all" && d.docType !== filterType) return false;
      if (search && ![d.name, d.notes, d.aiSummary, d.extractedText].some((s) => s?.toLowerCase().includes(search.toLowerCase()))) return false;
      return true;
    });
  }, [docs, filterEntity, filterType, search]);

  const sorted = [...filtered].sort((a, b) => b.uploadedAt.localeCompare(a.uploadedAt));

  function addDoc(d: Omit<VaultDoc, "id" | "uploadedAt">) {
    const entry: VaultDoc = { ...d, id: `${Date.now()}`, uploadedAt: new Date().toISOString() };
    setDocs([entry, ...docs]);
    setShowAdd(false);
  }

  async function deleteDoc(id: string) {
    const ok = await confirmAlert({
      title: "Delete this document?",
      description: "This permanently removes the record. Cannot be undone.",
      actionLabel: "Delete",
      destructive: true,
    });
    if (!ok) return;
    setDocs(docs.filter((d) => d.id !== id));
  }

  async function summarize(d: VaultDoc) {
    setSummarizing(d.id);
    try {
      let textContent: string | undefined;
      if (d.inlineData && d.inlineMimeType?.startsWith("text/")) {
        try {
          textContent = atob(d.inlineData);
        } catch {
          textContent = undefined;
        }
      }
      const prompt = textContent
        ? `Summarize this document in 2-3 sentences. Identify key dates, deadlines, parties, and action items.\n\nFilename: ${d.name}\nDoc type: ${d.docType}\n\n${textContent.slice(0, 8000)}`
        : `I have a document I haven’t been able to extract text from. Filename: ${d.name}, Doc type: ${d.docType}, Entity: ${d.organizationSlug}, Notes: ${d.notes ?? "none"}. Based on the doc type alone, what should I look for when reviewing this?`;

      const resp = await fetch("/api/agents/secretary", {
        method: "POST",
        headers: { "content-type": "application/json" },
        body: JSON.stringify({
          messages: [{ role: "user", content: prompt }],
          contextSnapshot: snapshotForAgentCall(),
        }),
      });
      const data = await resp.json();
      if (!resp.ok) throw new Error(data.error || "Failed");
      setDocs(docs.map((x) => (x.id === d.id ? { ...x, aiSummary: data.message } : x)));
    } catch (e) {
      alert("Summary failed: " + (e instanceof Error ? e.message : "unknown"));
    } finally {
      setSummarizing(null);
    }
  }

  return (
    <>
    <div className="space-y-6">
      <Card>
        <CardContent className="p-4 flex flex-wrap items-center gap-3">
          <Input
            placeholder="Search docs..."
            value={search}
            onChange={(e) => setSearch(e.target.value)}
            className="max-w-xs"
          />
          <select
            value={filterEntity}
            onChange={(e) => setFilterEntity(e.target.value)}
            className="h-10 rounded-md border border-input bg-background px-3 text-sm"
          >
            <option value="all">All entities</option>
            {ALL_ORGANIZATIONS.map((o) => (
              <option key={o.slug} value={o.slug}>{o.emoji} {o.name}</option>
            ))}
          </select>
          <select
            value={filterType}
            onChange={(e) => setFilterType(e.target.value as DocType | "all")}
            className="h-10 rounded-md border border-input bg-background px-3 text-sm"
          >
            <option value="all">All doc types</option>
            {DOC_TYPES.map((t) => <option key={t} value={t}>{t}</option>)}
          </select>
          <span className="text-xs text-muted-foreground tabular-nums ml-2">
            {sorted.length} of {docs.length}
          </span>
          <Button variant="brand" size="sm" className="ml-auto" onClick={() => setShowAdd((v) => !v)}>
            {showAdd ? "Cancel" : "+ Add document"}
          </Button>
        </CardContent>
      </Card>

      {showAdd && <AddDocForm onAdd={addDoc} onCancel={() => setShowAdd(false)} />}

      {sorted.length === 0 ? (
        <EmptyState
          icon="📁"
          title="No documents yet"
          description="Add EIN letters, articles, licenses, contracts, leases — track them all in one place."
        />
      ) : (
        <div className="grid gap-3">
          {sorted.map((d) => {
            const org = ALL_ORGANIZATIONS.find((o) => o.slug === d.organizationSlug);
            return (
              <Card key={d.id}>
                <CardContent className="p-5">
                  <div className="flex items-start justify-between gap-3 flex-wrap">
                    <div className="min-w-0 flex-1">
                      <div className="flex items-center gap-2 flex-wrap mb-1">
                        <Badge variant="outline" className="text-[10px]">{d.docType}</Badge>
                        <span className="text-xs text-muted-foreground inline-flex items-center gap-1">
                          {org?.emoji ?? "🏢"} {org?.name ?? d.organizationSlug}
                        </span>
                        <span className="text-xs text-muted-foreground">· {formatDate(d.uploadedAt)}</span>
                        {d.fileSize && (
                          <span className="text-xs text-muted-foreground">
                            · {(d.fileSize / 1024).toFixed(1)} KB
                          </span>
                        )}
                      </div>
                      <h3 className="text-base font-semibold">{d.name}</h3>
                      {d.notes && <p className="mt-1 text-sm text-muted-foreground">{d.notes}</p>}
                      {d.aiSummary && (
                        <div className="mt-3 rounded-md bg-muted p-3">
                          <div className="section-label mb-1">AI summary</div>
                          <p className="text-sm whitespace-pre-wrap">{d.aiSummary}</p>
                        </div>
                      )}
                      {(() => {
                        const body = readableBody(d);
                        if (!body) return null;
                        const isOpen = bodyOpenId === d.id;
                        return (
                          <div className="mt-3">
                            <button
                              type="button"
                              onClick={() => setBodyOpenId(isOpen ? null : d.id)}
                              className="section-label hover:text-foreground"
                            >
                              {isOpen ? "Hide" : "Show"} document text
                            </button>
                            {isOpen && (
                              <div className="mt-2 rounded-md border bg-card p-3 max-h-96 overflow-auto text-sm whitespace-pre-wrap leading-relaxed">
                                <EntityLinkedText text={body} />
                              </div>
                            )}
                          </div>
                        );
                      })()}
                    </div>
                    <div className="flex items-center gap-2 shrink-0 flex-wrap">
                      {d.inlineData && (
                        <Button asChild variant="outline" size="sm">
                          <a href={`data:${d.inlineMimeType};base64,${d.inlineData}`} download={d.name}>
                            Download
                          </a>
                        </Button>
                      )}
                      {d.externalUrl && (
                        <Button asChild variant="outline" size="sm">
                          <a href={d.externalUrl} target="_blank" rel="noopener noreferrer">Open ↗</a>
                        </Button>
                      )}
                      {!d.aiSummary && (
                        <Button
                          variant="brand"
                          size="sm"
                          disabled={summarizing === d.id}
                          onClick={() => summarize(d)}
                        >
                          {summarizing === d.id ? "..." : "AI summarize"}
                        </Button>
                      )}
                      {d.inlineData && (
                        <DocOcrButton
                          doc={d}
                          onUpdate={(updated) =>
                            setDocs((prev) => prev.map((x) => (x.id === updated.id ? updated : x)))
                          }
                        />
                      )}
                      <Button
                        variant="outline"
                        size="sm"
                        onClick={() => setChattingId(chattingId === d.id ? null : d.id)}
                        disabled={!d.aiSummary && !d.notes && !d.inlineMimeType?.startsWith("text/")}
                        title={
                          !d.aiSummary && !d.notes && !d.inlineMimeType?.startsWith("text/")
                            ? "Summarize first to enable chat — or paste notes."
                            : "Chat with this document"
                        }
                      >
                        💬 Chat
                      </Button>
                      <Button variant="ghost" size="sm" onClick={() => deleteDoc(d.id)}>×</Button>
                    </div>
                  </div>
                  {chattingId === d.id && (
                    <div className="mt-4">
                      <DocChat
                        compact
                        title={d.name}
                        content={buildChatContext(d)}
                        suggestions={chatSuggestionsFor(d)}
                      />
                    </div>
                  )}
                </CardContent>
              </Card>
            );
          })}
        </div>
      )}

      <p className="text-xs text-muted-foreground">
        Documents saved locally in this browser. Small files (≤500 KB) stored inline; larger files held by reference only. Migrates to Supabase Storage when provisioned.
      </p>
    </div>
    <AlertConfirmPortal />
    </>
  );
}

function AddDocForm({ onAdd, onCancel }: { onAdd: (d: Omit<VaultDoc, "id" | "uploadedAt">) => void; onCancel: () => void }) {
  const [form, setForm] = useState<Omit<VaultDoc, "id" | "uploadedAt">>({
    organizationSlug: ALL_ORGANIZATIONS[0]?.slug ?? "south-armz-global",
    docType: "Other",
    name: "",
  });
  const [fileError, setFileError] = useState("");

  async function onFile(file: File) {
    setFileError("");
    if (file.size > MAX_INLINE_BYTES) {
      setFileError(`File is ${(file.size / 1024).toFixed(0)} KB — too large for inline storage. Use the External URL field instead.`);
      setForm({ ...form, name: form.name || file.name, fileSize: file.size });
      return;
    }
    const buf = await file.arrayBuffer();
    const b64 = arrayBufferToBase64(buf);
    setForm({
      ...form,
      name: form.name || file.name,
      inlineData: b64,
      inlineMimeType: file.type || "application/octet-stream",
      fileSize: file.size,
    });
  }

  function submit(e: React.FormEvent) {
    e.preventDefault();
    if (!form.name.trim()) return;
    onAdd(form);
  }

  return (
    <Card>
      <CardContent className="p-6">
        <form onSubmit={submit} className="grid gap-3 md:grid-cols-2">
          <Field label="Entity">
            <select
              value={form.organizationSlug}
              onChange={(e) => setForm({ ...form, organizationSlug: e.target.value })}
              className="w-full h-10 rounded-md border border-input bg-background px-3 text-sm"
            >
              {ALL_ORGANIZATIONS.map((o) => <option key={o.slug} value={o.slug}>{o.emoji} {o.name}</option>)}
            </select>
          </Field>
          <Field label="Document type">
            <select
              value={form.docType}
              onChange={(e) => setForm({ ...form, docType: e.target.value as DocType })}
              className="w-full h-10 rounded-md border border-input bg-background px-3 text-sm"
            >
              {DOC_TYPES.map((t) => <option key={t} value={t}>{t}</option>)}
            </select>
          </Field>
          <Field label="Name" className="md:col-span-2">
            <Input
              value={form.name}
              onChange={(e) => setForm({ ...form, name: e.target.value })}
              placeholder="e.g. Carolina Hemp Tours — CP575 EIN Letter"
              required
            />
          </Field>
          <Field label="Upload file (≤500 KB inline)">
            <input
              type="file"
              onChange={(e) => {
                const f = e.target.files?.[0];
                if (f) onFile(f);
              }}
              className="block w-full text-sm file:mr-3 file:py-2 file:px-3 file:rounded-md file:border file:border-input file:bg-background file:text-sm file:font-medium"
            />
            {fileError && <p className="mt-1 text-xs text-destructive">{fileError}</p>}
          </Field>
          <Field label="OR External URL (OneDrive / Drive / file://)">
            <Input
              value={form.externalUrl ?? ""}
              onChange={(e) => setForm({ ...form, externalUrl: e.target.value })}
              placeholder="https://onedrive.live.com/..."
            />
          </Field>
          <Field label="Notes" className="md:col-span-2">
            <Input
              value={form.notes ?? ""}
              onChange={(e) => setForm({ ...form, notes: e.target.value })}
            />
          </Field>
          <div className="md:col-span-2 flex justify-end gap-2">
            <Button variant="ghost" size="sm" type="button" onClick={onCancel}>Cancel</Button>
            <Button variant="brand" size="sm" type="submit">Save document</Button>
          </div>
        </form>
      </CardContent>
    </Card>
  );
}

function Field({ label, children, className }: { label: string; children: React.ReactNode; className?: string }) {
  return (
    <div className={className}>
      <label className="text-xs text-muted-foreground">{label}</label>
      <div className="mt-1">{children}</div>
    </div>
  );
}

function arrayBufferToBase64(buf: ArrayBuffer): string {
  const bytes = new Uint8Array(buf);
  let binary = "";
  for (let i = 0; i < bytes.byteLength; i++) binary += String.fromCharCode(bytes[i]);
  return btoa(binary);
}

/**
 * Returns the readable body text for a doc, preferring OCR-extracted text
 * (D1) and falling back to inline base64 for text/* MIME types. Returns
 * an empty string for non-text or unreadable docs so the caller can skip
 * rendering.
 */
function readableBody(d: VaultDoc): string {
  if (d.extractedText && d.extractedText.trim()) return d.extractedText;
  if (d.inlineData && d.inlineMimeType?.startsWith("text/")) {
    try {
      return atob(d.inlineData);
    } catch {
      return "";
    }
  }
  return "";
}

function buildChatContext(d: VaultDoc): string {
  const parts: string[] = [];
  if (d.aiSummary) parts.push(`# AI summary\n\n${d.aiSummary}`);
  if (d.notes) parts.push(`# Notes\n\n${d.notes}`);
  if (d.inlineData && d.inlineMimeType?.startsWith("text/")) {
    try {
      const text = atob(d.inlineData);
      parts.push(`# Full document text\n\n${text}`);
    } catch {
      // ignore decode errors
    }
  }
  parts.push(`Document type: ${d.docType}.`);
  return parts.join("\n\n");
}

function chatSuggestionsFor(d: VaultDoc): string[] {
  const generic = ["What's the key takeaway?", "Are there any deadlines?", "What action items do I have?"];
  if (d.docType === "License / Permit") {
    return ["When does this expire?", "What renewal steps are required?", "What's the issuing agency?"];
  }
  if (d.docType === "Contract" || d.docType === "Lease") {
    return ["What's the termination clause?", "What are the auto-renewal terms?", "What payments are owed?"];
  }
  if (d.docType === "EIN Letter (CP575)") {
    return ["What's the EIN?", "What's the legal name on file?", "What's the responsible party?"];
  }
  if (d.docType === "Tax Return") {
    return ["What was the taxable income?", "Are there carryforwards?", "What's the year filed?"];
  }
  return generic;
}
