import { useState, useRef, useCallback, useEffect } from "react";
import { supabase } from "@/integrations/supabase/client";
import { saveBillInvoiceToDocuments } from "@/lib/saveBillToDocuments";
import { useToast } from "@/hooks/use-toast";
import {
  Upload, FileText, CheckCircle2, AlertCircle, Loader2,
  DollarSign, FilePlus, Download, Sparkles, X, AlertTriangle,
  Eye, Trash2, ClipboardList,
} from "lucide-react";
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from "@/components/ui/dialog";
import { Alert, AlertDescription } from "@/components/ui/alert";
import { Button } from "@/components/ui/button";
import { Label } from "@/components/ui/label";
import { Input } from "@/components/ui/input";
import { Textarea } from "@/components/ui/textarea";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { Checkbox } from "@/components/ui/checkbox";
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";

// ── Helpers ──────────────────────────────────────────────────────────────────
function toBase64(file: File): Promise<string> {
  return new Promise((res, rej) => {
    const r = new FileReader();
    r.onload = () => res((r.result as string).split(",")[1]);
    r.onerror = rej;
    r.readAsDataURL(file);
  });
}

function fmt(n: number | null | undefined) {
  if (n == null) return "—";
  return `$${Number(n).toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
}

type LineItem = {
  name?: string;
  description?: string;
  quantity?: number;
  unit_price?: number;
  amount?: number;
  expense_account_id?: string | null;
};

type ParsedInvoice = {
  vendor_name: string;
  invoice_number: string;
  invoice_date: string;
  due_date: string;
  subtotal: number;
  tax: number;
  other_charges: number;
  total_amount: number;
  currency: string;
  notes: string;
  line_items: LineItem[];
};

type SavedInvoice = {
  id: string;
  filename: string;
  vendor_name: string;
  invoice_number: string;
  invoice_date: string;
  due_date: string;
  total_amount: number;
  currency: string;
  notes: string;
  status: string | null;
  raw_pdf_url: string | null;
  line_items: LineItem[];
};

type QueueFile = {
  id: string;
  name: string;
  status: "uploading" | "parsing" | "saving" | "success" | "error";
  error?: string;
};

type PendingInvoice = {
  id: string;
  filename: string;
  file: File;
  pdfUrl: string | null;
  data: ParsedInvoice;
};

// ── Edge Function call ───────────────────────────────────────────────────────
async function extractInvoiceData(file: File) {
  const pdf_base64 = await toBase64(file);
  const url = `${import.meta.env.VITE_SUPABASE_URL}/functions/v1/parse-invoice`;

  const res = await fetch(url, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Authorization: `Bearer ${import.meta.env.VITE_SUPABASE_PUBLISHABLE_KEY}`,
      apikey: import.meta.env.VITE_SUPABASE_PUBLISHABLE_KEY,
    },
    body: JSON.stringify({ pdf_base64, filename: file.name }),
  });

  if (!res.ok) {
    const err = await res.json().catch(() => ({ error: res.statusText }));
    throw new Error(err.error || `Function returned ${res.status}`);
  }

  const { data, error } = await res.json();
  if (error) throw new Error(error);
  return data;
}

async function uploadPdf(file: File) {
  const path = `${Date.now()}_${file.name}`;
  const { data, error } = await supabase.storage.from("invoices").upload(path, file);
  if (error) return null;
  const { data: { publicUrl } } = supabase.storage.from("invoices").getPublicUrl(data.path);
  return publicUrl;
}

// ── CSV Export ────────────────────────────────────────────────────────────────
function escapeCSV(value: any) {
  if (value === null || value === undefined) return "";
  const str = String(value);
  return str.includes(",") || str.includes('"') || str.includes("\n")
    ? `"${str.replace(/"/g, '""')}"` : str;
}

// ── Component ────────────────────────────────────────────────────────────────
export default function AIInvoiceParserPage() {
  const { toast } = useToast();
  const [queueFiles, setQueueFiles] = useState<QueueFile[]>([]);
  const [savedInvoices, setSavedInvoices] = useState<SavedInvoice[]>([]);
  const [loading, setLoading] = useState(false);
  const [dragOver, setDragOver] = useState(false);
  const fileInputRef = useRef<HTMLInputElement>(null);

  // Pending review queue (parsed but not yet approved/discarded)
  const [pendingReviews, setPendingReviews] = useState<PendingInvoice[]>([]);

  // Review dialog state
  const [reviewOpen, setReviewOpen] = useState(false);
  const [reviewPendingId, setReviewPendingId] = useState<string | null>(null);
  const [reviewData, setReviewData] = useState<ParsedInvoice | null>(null);
  const [reviewFile, setReviewFile] = useState<File | null>(null);
  const [reviewPdfUrl, setReviewPdfUrl] = useState<string | null>(null);
  const [reviewForm, setReviewForm] = useState({
    association_id: "",
    expense_account_id: "",
    approval_member_ids: [] as string[],
    vendor_id: "",
    description: "",
  });
  const [submittingReview, setSubmittingReview] = useState(false);
  const [vendorNotFound, setVendorNotFound] = useState<string | null>(null);

  // Lookup data
  const [associations, setAssociations] = useState<any[]>([]);
  const [accounts, setAccounts] = useState<any[]>([]);
  const [vendors, setVendors] = useState<any[]>([]);
  const [boardMembers, setBoardMembers] = useState<any[]>([]);

  // Fetch associations & accounts on mount
  useEffect(() => {
    Promise.all([
      supabase.from("associations").select("id, name").eq("status", "active").order("name"),
      supabase.from("chart_of_accounts").select("id, account_name, account_number, account_type, association_id").eq("account_type", "expense").order("account_number"),
      supabase.from("vendors").select("id, name, association_id, association_ids").eq("is_active", true).order("name"),
    ]).then(([aRes, coaRes, vRes]) => {
      setAssociations(aRes.data || []);
      setAccounts(coaRes.data || []);
      setVendors(vRes.data || []);
    });
  }, []);

  // Fetch board members when association changes in review form
  useEffect(() => {
    if (!reviewForm.association_id) { setBoardMembers([]); return; }
    supabase
      .from("board_members")
      .select("id, member_name, member_email, approval_authority")
      .eq("association_id", reviewForm.association_id)
      .eq("approval_authority", true)
      .order("member_name")
      .then(({ data }) => setBoardMembers(data || []));
  }, [reviewForm.association_id]);

  const filteredAccounts = reviewForm.association_id
    ? accounts.filter((a: any) => !a.association_id || a.association_id === reviewForm.association_id)
    : [];

  const filteredVendors = reviewForm.association_id
    ? vendors.filter((v: any) => v.association_id === reviewForm.association_id || (Array.isArray(v.association_ids) && v.association_ids.includes(reviewForm.association_id)))
    : [];

  // Auto-match vendor when association changes and reviewData exists
  useEffect(() => {
    if (!reviewData?.vendor_name || !reviewForm.association_id) return;
    const parsedName = reviewData.vendor_name.toLowerCase().trim();
    const matched = filteredVendors.find((v: any) => v.name.toLowerCase().trim() === parsedName);
    if (matched) {
      setReviewForm(prev => ({ ...prev, vendor_id: matched.id }));
      setVendorNotFound(null);
    } else {
      setReviewForm(prev => ({ ...prev, vendor_id: "" }));
      setVendorNotFound(reviewData.vendor_name);
    }
  }, [reviewForm.association_id, reviewData?.vendor_name, filteredVendors.length]);

  const exportToCSV = async () => {
    const headers = [
      "Invoice Number", "Bill Date", "Due Date", "Vendor",
      "Line Items", "Descriptions", "Total", "Currency", "Memo / Notes",
    ];
    const rows = savedInvoices.map((inv) => {
      const lineItems = Array.isArray(inv.line_items) ? inv.line_items : [];
      const itemNames = lineItems.map((li) => li.name || "").filter(Boolean).join(" | ");
      const itemDescs = lineItems.map((li) => li.description || "").filter(Boolean).join(" | ");
      return [
        escapeCSV(inv.invoice_number), escapeCSV(inv.invoice_date),
        escapeCSV(inv.due_date), escapeCSV(inv.vendor_name),
        escapeCSV(itemNames || inv.notes), escapeCSV(itemDescs),
        escapeCSV(inv.total_amount),
        escapeCSV(inv.currency || "USD"), escapeCSV(inv.notes),
      ].join(",");
    });
    const csv = [headers.join(","), ...rows].join("\n");
    const { saveCsv } = await import("@/lib/saveFile");
    await saveCsv(csv, `invoices_${new Date().toISOString().slice(0, 10)}.csv`);
  };

  const processFile = useCallback(async (file: File, queueId: string) => {
    try {
      setQueueFiles((p) => p.map((x) => x.id === queueId ? { ...x, status: "uploading" } : x));

      // Upload PDF in background
      let rawPdfUrl: string | null = null;
      try { rawPdfUrl = await uploadPdf(file); } catch (_) {}

      // Parse
      setQueueFiles((p) => p.map((x) => x.id === queueId ? { ...x, status: "parsing" } : x));
      const extracted = await extractInvoiceData(file);

      // Success - open review dialog instead of auto-saving
      setQueueFiles((p) => p.map((x) => x.id === queueId ? { ...x, status: "success" } : x));

      const parsed: ParsedInvoice = {
        vendor_name: extracted.vendor_name || "Unknown Vendor",
        invoice_number: extracted.invoice_number || "",
        invoice_date: extracted.invoice_date || "",
        due_date: extracted.due_date || "",
        subtotal: extracted.subtotal || 0,
        tax: extracted.tax || 0,
        other_charges: extracted.other_charges || 0,
        total_amount: extracted.total_amount || 0,
        currency: extracted.currency || "USD",
        notes: extracted.notes || "",
        line_items: extracted.line_items || [],
      };

      // Push into pending review queue
      const pendingId = crypto.randomUUID();
      const pending: PendingInvoice = {
        id: pendingId,
        filename: file.name,
        file,
        pdfUrl: rawPdfUrl,
        data: parsed,
      };
      setPendingReviews((prev) => [...prev, pending]);
    } catch (err: any) {
      setQueueFiles((p) => p.map((x) => x.id === queueId ? { ...x, status: "error", error: err.message } : x));
      toast({ title: "Parse failed", description: err.message, variant: "destructive" });
    }
  }, [toast]);

  const openReview = useCallback((pendingId: string) => {
    const p = pendingReviews.find((x) => x.id === pendingId);
    if (!p) return;
    setReviewPendingId(pendingId);
    setReviewData(p.data);
    setReviewFile(p.file);
    setReviewPdfUrl(p.pdfUrl);
    setReviewForm({
      association_id: associations[0]?.id || "",
      expense_account_id: "",
      approval_member_ids: [],
      vendor_id: "",
      description: p.data.notes || "",
    });
    setVendorNotFound(null);
    setReviewOpen(true);
  }, [pendingReviews, associations]);

  const discardPending = useCallback((pendingId: string) => {
    setPendingReviews((prev) => prev.filter((p) => p.id !== pendingId));
  }, []);



  const handleSubmitReview = async () => {
    if (!reviewData || !reviewForm.association_id || !reviewForm.vendor_id) {
      toast({ variant: "destructive", title: "Missing fields", description: "Please select an association and vendor." });
      return;
    }

    setSubmittingReview(true);
    try {
      // Build description from line items
      const lineDesc = reviewData.line_items.map((li) => li.description || li.name).filter(Boolean).join("; ");
      const description = reviewForm.description || lineDesc || reviewData.notes || reviewFile?.name || "";

      // Save to invoices table
      const { data: userData } = await supabase.auth.getUser();

      const { data: invoice, error: invoiceErr } = await supabase
        .from("invoices")
        .insert({
          vendor_name: reviewData.vendor_name,
          invoice_number: reviewData.invoice_number || null,
          issue_date: reviewData.invoice_date || null,
          due_date: reviewData.due_date || null,
          amount: reviewData.total_amount || 0,
          description,
          association_id: reviewForm.association_id,
          status: "pending",
          created_by: userData?.user?.id || null,
          category: reviewForm.expense_account_id || null,
          raw_pdf_url: reviewPdfUrl,
          line_items: reviewData.line_items,
        })
        .select()
        .single();

      if (invoiceErr) throw invoiceErr;

      // Create bill in bills table
      const { data: newBill, error: billErr } = await supabase.from("bills").insert({
        association_id: reviewForm.association_id,
        vendor_id: reviewForm.vendor_id || null,
        description: description || `Bill from ${reviewData.vendor_name}`,
        amount: reviewData.total_amount || 0,
        bill_date: reviewData.invoice_date || new Date().toISOString().split("T")[0],
        due_date: reviewData.due_date || null,
        invoice_number: reviewData.invoice_number || null,
        expense_account_id: reviewForm.expense_account_id || null,
        attachment_url: reviewPdfUrl,
        status: "pending",
        created_by: userData?.user?.id || null,
        notes: reviewData.vendor_name,
        source_invoice_id: invoice.id,
      }).select("id").single();

      if (billErr) throw billErr;

      // File invoice PDF into Documents > Vendor Invoices for this association
      saveBillInvoiceToDocuments({
        associationId: reviewForm.association_id,
        attachmentUrl: reviewPdfUrl,
        vendorName: reviewData.vendor_name,
        invoiceNumber: reviewData.invoice_number,
        invoiceDate: reviewData.invoice_date,
        uploadedBy: userData?.user?.id || null,
      });

      // Create bill approvals for each selected approver
      if (reviewForm.approval_member_ids.length > 0) {
        const approvalRows = reviewForm.approval_member_ids.map((memberId) => {
          const bm = boardMembers.find((m: any) => m.id === memberId);
          return {
            association_id: reviewForm.association_id,
            bill_id: newBill?.id || null,
            vendor_name: bm?.member_name || reviewData.vendor_name,
            amount: reviewData.total_amount || 0,
            invoice_id: invoice.id,
            status: "pending",
            notes: description || null,
          };
        });
        await supabase.from("bill_approvals").insert(approvalRows);
      }

      // Add to saved list
      const saved: SavedInvoice = {
        id: invoice.id,
        filename: reviewFile?.name || "invoice.pdf",
        vendor_name: reviewData.vendor_name,
        invoice_number: reviewData.invoice_number,
        invoice_date: reviewData.invoice_date,
        due_date: reviewData.due_date,
        total_amount: reviewData.total_amount,
        currency: reviewData.currency,
        notes: reviewData.notes,
        status: "converted_to_bill",
        raw_pdf_url: reviewPdfUrl,
        line_items: reviewData.line_items,
      };
      setSavedInvoices((prev) => [saved, ...prev]);

      // Remove from pending review queue and auto-advance to the next one
      const currentId = reviewPendingId;
      const remaining = pendingReviews.filter((p) => p.id !== currentId);
      setPendingReviews(remaining);
      setReviewOpen(false);
      setReviewData(null);
      setReviewFile(null);
      setReviewPendingId(null);
      toast({ title: "Bill Created", description: `Bill for ${reviewData.vendor_name} has been submitted for approval.` });

      // If more remain, open the next after a short delay so dialog can close
      if (remaining.length > 0) {
        const next = remaining[0];
        setTimeout(() => {
          setReviewPendingId(next.id);
          setReviewData(next.data);
          setReviewFile(next.file);
          setReviewPdfUrl(next.pdfUrl);
          setReviewForm({
            association_id: associations[0]?.id || "",
            expense_account_id: "",
            approval_member_ids: [],
            vendor_id: "",
            description: next.data.notes || "",
          });
          setVendorNotFound(null);
          setReviewOpen(true);
        }, 200);
      }
    } catch (err: any) {
      toast({ variant: "destructive", title: "Failed to create bill", description: err.message });
    } finally {
      setSubmittingReview(false);
    }
  };

  const handleFiles = useCallback((selectedFiles: File[]) => {
    const pdfs = selectedFiles.filter((f) => f.type === "application/pdf");
    if (!pdfs.length) {
      toast({ title: "Only PDF files are supported", variant: "destructive" });
      return;
    }

    pdfs.forEach((file) => {
      const queueId = crypto.randomUUID();
      setQueueFiles((prev) => [{ id: queueId, name: file.name, status: "uploading" }, ...prev]);
      processFile(file, queueId);
    });
  }, [processFile, toast]);

  const handleDrop = (e: React.DragEvent) => {
    e.preventDefault();
    setDragOver(false);
    const dropped = Array.from(e.dataTransfer.files).filter((f) => f.type === "application/pdf");
    if (dropped.length) handleFiles(dropped);
  };

  const handleFileInput = (e: React.ChangeEvent<HTMLInputElement>) => {
    const selected = Array.from(e.target.files || []);
    if (selected.length) handleFiles(selected);
    e.target.value = "";
  };

  const removeQueueFile = (id: string) => setQueueFiles((prev) => prev.filter((f) => f.id !== id));

  const runningTotal = savedInvoices.reduce((s, i) => s + (Number(i.total_amount) || 0), 0);

  const statusConfig: Record<string, { label: string; color: string; icon: any; spin: boolean }> = {
    uploading: { label: "Uploading…", color: "text-primary", icon: Loader2, spin: true },
    parsing:   { label: "AI Parsing…", color: "text-accent-foreground", icon: Sparkles, spin: false },
    saving:    { label: "Saving…", color: "text-primary", icon: Loader2, spin: true },
    success:   { label: "Success", color: "text-emerald-500", icon: CheckCircle2, spin: false },
    error:     { label: "Error", color: "text-destructive", icon: AlertCircle, spin: false },
  };

  return (
    <div className="space-y-6">
      {/* ── Page Header ─────────────────────────────────────────────────── */}
      <div className="flex flex-col sm:flex-row sm:items-end justify-between gap-6 border-b border-border pb-6">
        <div>
          <p className="text-xs uppercase tracking-[0.2em] text-primary mb-2 flex items-center gap-2">
            <span className="inline-block w-4 h-px bg-primary" />
            AI-Powered
          </p>
          <h1 className="text-2xl font-bold text-foreground flex items-center gap-2">
            <FileText className="h-6 w-6 text-primary" />
            Invoice Parser
          </h1>
          <p className="text-sm text-muted-foreground mt-1">
            Upload PDFs — AI extracts structured data and sends to Bill Approvals.
          </p>
        </div>

        <div className="flex items-stretch gap-3 shrink-0">
          <div className="flex items-center gap-3 px-5 py-3 rounded-xl bg-card border border-border shadow-sm">
            <div className="p-2 rounded-lg bg-primary/10">
              <DollarSign className="w-4 h-4 text-primary" />
            </div>
            <div>
              <p className="text-[10px] uppercase tracking-widest text-muted-foreground">Running Total</p>
              <p className="text-lg font-bold text-foreground leading-none mt-0.5">
                {fmt(runningTotal)}
              </p>
            </div>
          </div>

          {savedInvoices.length > 0 && (
            <button
              onClick={exportToCSV}
              className="flex items-center gap-2 px-4 py-3 rounded-xl bg-primary text-primary-foreground font-bold text-sm hover:bg-primary/90 active:scale-95 transition-all duration-150 shadow-sm"
            >
              <Download className="w-4 h-4" />
              Export CSV
            </button>
          )}
        </div>
      </div>

      {/* ── Two-column layout ────────────────────────────────────────────── */}
      <div className="grid grid-cols-1 lg:grid-cols-5 gap-6">
        {/* Left: Upload (2/5) */}
        <div className="lg:col-span-2 space-y-5">
          <div
            className={`relative rounded-2xl border-2 border-dashed transition-all duration-200 cursor-pointer
              ${dragOver
                ? "border-primary bg-primary/5 scale-[1.01]"
                : "border-border bg-card hover:border-muted-foreground/40"
              }`}
            onClick={() => fileInputRef.current?.click()}
            onDragOver={(e) => { e.preventDefault(); setDragOver(true); }}
            onDragLeave={() => setDragOver(false)}
            onDrop={handleDrop}
          >
            <input
              type="file" ref={fileInputRef} className="hidden"
              accept="application/pdf" multiple onChange={handleFileInput}
            />
            <div className="flex flex-col items-center justify-center py-14 px-6 text-center">
              <div className={`mb-4 p-4 rounded-2xl transition-colors ${dragOver ? "bg-primary/20" : "bg-muted"}`}>
                <Upload className={`w-8 h-8 transition-colors ${dragOver ? "text-primary" : "text-muted-foreground"}`} />
              </div>
              <p className="font-semibold text-foreground text-sm">
                {dragOver ? "Drop to upload" : "Click or drag PDFs here"}
              </p>
              <p className="text-xs text-muted-foreground mt-1">Supports .pdf · up to 50MB each</p>
            </div>
          </div>

          {queueFiles.length > 0 && (
            <div className="rounded-2xl bg-card border border-border overflow-hidden">
              <div className="px-4 py-3 border-b border-border flex justify-between items-center">
                <span className="text-xs font-semibold uppercase tracking-widest text-muted-foreground">
                  Processing Queue
                </span>
                <span className="text-xs text-muted-foreground">{queueFiles.length} file{queueFiles.length !== 1 ? "s" : ""}</span>
              </div>
              <div className="divide-y divide-border max-h-72 overflow-y-auto">
                {queueFiles.map((file) => {
                  const cfg = statusConfig[file.status];
                  if (!cfg) return null;
                  const Icon = cfg.icon;
                  return (
                    <div key={file.id} className="px-4 py-3 flex items-center gap-3 group">
                      <div className="p-1.5 rounded-lg bg-muted shrink-0">
                        <FileText className="w-3.5 h-3.5 text-muted-foreground" />
                      </div>
                      <span className="flex-1 truncate text-xs text-foreground" title={file.name}>
                        {file.name}
                      </span>
                      <span className={`flex items-center gap-1 text-xs shrink-0 ${cfg.color}`}>
                        <Icon className={`w-3 h-3 ${cfg.spin ? "animate-spin" : ""}`} />
                        {cfg.label}
                      </span>
                      {(file.status === "success" || file.status === "error") && (
                        <button onClick={() => removeQueueFile(file.id)}
                          className="opacity-0 group-hover:opacity-100 transition-opacity ml-1">
                          <X className="w-3 h-3 text-muted-foreground hover:text-foreground" />
                        </button>
                      )}
                    </div>
                  );
                })}
              </div>
            </div>
          )}

          {pendingReviews.length > 0 && (
            <div className="rounded-2xl bg-card border-2 border-primary/40 overflow-hidden shadow-sm">
              <div className="px-4 py-3 border-b border-border flex justify-between items-center bg-primary/5">
                <span className="text-xs font-semibold uppercase tracking-widest text-primary flex items-center gap-2">
                  <ClipboardList className="w-3.5 h-3.5" />
                  Awaiting Your Review
                </span>
                <span className="text-xs font-bold text-primary">{pendingReviews.length} pending</span>
              </div>
              <div className="divide-y divide-border max-h-80 overflow-y-auto">
                {pendingReviews.map((p) => (
                  <div key={p.id} className="px-4 py-3 flex items-center gap-3 hover:bg-muted/40 transition-colors">
                    <div className="p-1.5 rounded-lg bg-primary/10 shrink-0">
                      <FileText className="w-3.5 h-3.5 text-primary" />
                    </div>
                    <div className="flex-1 min-w-0">
                      <p className="text-xs font-semibold text-foreground truncate" title={p.filename}>
                        {p.data.vendor_name}
                      </p>
                      <p className="text-[11px] text-muted-foreground truncate">
                        {fmt(p.data.total_amount)} · {p.filename}
                      </p>
                    </div>
                    <Button
                      size="sm"
                      variant="default"
                      className="h-7 px-2 text-xs gap-1"
                      onClick={() => openReview(p.id)}
                    >
                      <Eye className="w-3 h-3" />
                      Review
                    </Button>
                    <button
                      onClick={() => discardPending(p.id)}
                      className="p-1 rounded hover:bg-destructive/10 text-muted-foreground hover:text-destructive transition-colors"
                      title="Discard"
                    >
                      <Trash2 className="w-3.5 h-3.5" />
                    </button>
                  </div>
                ))}
              </div>
            </div>
          )}
        </div>

        {/* Right: Saved Invoices (3/5) */}
        <div className="lg:col-span-3 flex flex-col rounded-2xl bg-card border border-border overflow-hidden" style={{ minHeight: "520px" }}>
          <div className="px-5 py-4 border-b border-border flex justify-between items-center shrink-0">
            <div className="flex items-center gap-3">
              <span className="text-sm font-semibold text-foreground">Saved Invoices</span>
              <span className="text-xs px-2 py-0.5 rounded-full bg-muted text-primary font-mono">
                {savedInvoices.length}
              </span>
            </div>
          </div>

          <div className="flex-1 overflow-y-auto p-4 space-y-3">
            {loading ? (
              <div className="flex items-center justify-center h-full">
                <Loader2 className="w-6 h-6 animate-spin text-primary" />
              </div>
            ) : savedInvoices.length === 0 ? (
              <div className="flex flex-col items-center justify-center h-full gap-4 text-muted-foreground">
                <FileText className="w-12 h-12 opacity-20" />
                <p className="text-sm">No invoices yet — upload a PDF to begin.</p>
              </div>
            ) : (
              savedInvoices.map((inv) => (
                <div key={inv.id}
                  className="group p-4 rounded-xl bg-background border border-border hover:border-muted-foreground/40 transition-all duration-150">
                  <div className="flex justify-between items-start gap-3">
                    <div className="min-w-0">
                      <h4 className="font-bold text-foreground text-sm truncate">
                        {inv.vendor_name || "Unknown Vendor"}
                      </h4>
                      <p className="text-xs text-muted-foreground truncate mt-0.5" title={inv.filename}>
                        {inv.filename}
                      </p>
                    </div>
                    <div className="text-right shrink-0">
                      <p className="font-bold text-foreground tabular-nums">
                        {fmt(inv.total_amount)}
                      </p>
                      <p className="text-xs text-muted-foreground mt-0.5">{inv.invoice_date || "—"}</p>
                    </div>
                  </div>

                  <div className="flex flex-wrap items-center gap-x-4 gap-y-1 mt-3 pt-3 border-t border-border text-xs text-muted-foreground">
                    {inv.invoice_number && <span className="font-mono">#{inv.invoice_number}</span>}
                    {inv.due_date && <span>Due {inv.due_date}</span>}
                    {inv.notes && (
                      <span className="truncate max-w-[180px]" title={inv.notes}>{inv.notes}</span>
                    )}
                    {inv.raw_pdf_url && inv.raw_pdf_url !== "#" && (
                      <a href={inv.raw_pdf_url} target="_blank" rel="noopener noreferrer"
                        className="text-primary hover:underline ml-auto">
                        View PDF ↗
                      </a>
                    )}
                  </div>

                  <div className="mt-3">
                    {inv.status === "converted_to_bill" ? (
                      <div className="w-full text-center py-1.5 text-xs rounded-lg text-emerald-500 bg-emerald-500/10 border border-emerald-500/20 flex items-center justify-center gap-1.5">
                        <CheckCircle2 className="w-3.5 h-3.5" /> Bill Approval Created
                      </div>
                    ) : (
                      <p className="text-xs text-muted-foreground text-center py-1.5">Saved — not yet sent to approvals</p>
                    )}
                  </div>
                </div>
              ))
            )}
          </div>
        </div>
      </div>

      {/* ── Review Parsed Invoice Dialog ─────────────────────────────────── */}
      <Dialog open={reviewOpen} onOpenChange={(o) => { setReviewOpen(o); if (!o) setReviewPendingId(null); }}>
        <DialogContent className="sm:max-w-2xl max-h-[90vh] overflow-y-auto">
          <DialogHeader>
            <DialogTitle className="flex items-center gap-2">
              <Sparkles className="h-5 w-5 text-primary" />
              Review Parsed Invoice
              {pendingReviews.length > 1 && (
                <span className="ml-2 text-xs font-normal text-muted-foreground">
                  ({Math.max(1, pendingReviews.length - pendingReviews.findIndex(p => p.id === reviewPendingId))} of {pendingReviews.length} remaining)
                </span>
              )}
            </DialogTitle>
          </DialogHeader>

          {reviewData && (
            <div className="space-y-5">
              {/* Parsed Header Info */}
              <div className="grid grid-cols-2 sm:grid-cols-4 gap-3 p-4 rounded-lg bg-muted/50 border border-border">
                <div>
                  <p className="text-[10px] uppercase tracking-widest text-muted-foreground">Vendor</p>
                  <p className="text-sm font-semibold text-foreground">{reviewData.vendor_name}</p>
                </div>
                <div>
                  <p className="text-[10px] uppercase tracking-widest text-muted-foreground">Invoice #</p>
                  <p className="text-sm font-mono text-foreground">{reviewData.invoice_number || "—"}</p>
                </div>
                <div>
                  <p className="text-[10px] uppercase tracking-widest text-muted-foreground">Date</p>
                  <p className="text-sm text-foreground">{reviewData.invoice_date || "—"}</p>
                </div>
                <div>
                  <p className="text-[10px] uppercase tracking-widest text-muted-foreground">Due Date</p>
                  <p className="text-sm text-foreground">{reviewData.due_date || "—"}</p>
                </div>
              </div>

              {/* Line Items Table - Editable */}
              <div>
                <div className="flex items-center justify-between mb-2">
                  <Label className="text-xs uppercase tracking-widest text-muted-foreground">
                    Line Items ({reviewData.line_items.length})
                  </Label>
                  <Button
                    type="button"
                    variant="outline"
                    size="sm"
                    onClick={() => setReviewData({
                      ...reviewData,
                      line_items: [...reviewData.line_items, { name: "", description: "", quantity: 1, unit_price: 0, amount: 0 }],
                    })}
                  >
                    <FilePlus className="w-3 h-3 mr-1" /> Add Item
                  </Button>
                </div>
                {reviewData.line_items.length === 0 ? (
                  <div className="border border-dashed border-border rounded-lg p-4 text-center text-sm text-muted-foreground">
                    No line items parsed. Click "Add Item" to add one manually.
                  </div>
                ) : (
                  <div className="border border-border rounded-lg overflow-x-auto">
                    <Table>
                      <TableHeader>
                        <TableRow>
                          <TableHead className="text-xs w-[140px]">Item</TableHead>
                          <TableHead className="text-xs">Description</TableHead>
                          <TableHead className="text-xs text-right w-[60px]">Qty</TableHead>
                          <TableHead className="text-xs text-right w-[90px]">Unit Price</TableHead>
                          <TableHead className="text-xs text-right w-[100px]">Amount</TableHead>
                          <TableHead className="text-xs w-[210px]">GL Account</TableHead>
                          <TableHead className="text-xs w-[40px]"></TableHead>
                        </TableRow>
                      </TableHeader>
                      <TableBody>
                        {reviewData.line_items.map((li, idx) => {
                          const updateItem = (patch: Partial<LineItem>) => {
                            const next = [...reviewData.line_items];
                            next[idx] = { ...next[idx], ...patch };
                            setReviewData({ ...reviewData, line_items: next });
                          };
                          return (
                            <TableRow key={idx}>
                              <TableCell className="p-1">
                                <Input
                                  value={li.name || ""}
                                  onChange={(e) => updateItem({ name: e.target.value })}
                                  className="h-8 text-sm"
                                  placeholder="Item"
                                />
                              </TableCell>
                              <TableCell className="p-1">
                                <Input
                                  value={li.description || ""}
                                  onChange={(e) => updateItem({ description: e.target.value })}
                                  className="h-8 text-sm"
                                  placeholder="Description"
                                />
                              </TableCell>
                              <TableCell className="p-1">
                                <Input
                                  type="number"
                                  value={li.quantity ?? ""}
                                  onChange={(e) => updateItem({ quantity: e.target.value === "" ? undefined : Number(e.target.value) })}
                                  className="h-8 text-sm text-right tabular-nums"
                                />
                              </TableCell>
                              <TableCell className="p-1">
                                <Input
                                  type="number"
                                  step="0.01"
                                  value={li.unit_price ?? ""}
                                  onChange={(e) => updateItem({ unit_price: e.target.value === "" ? undefined : Number(e.target.value) })}
                                  className="h-8 text-sm text-right tabular-nums"
                                />
                              </TableCell>
                              <TableCell className="p-1">
                                <Input
                                  type="number"
                                  step="0.01"
                                  value={li.amount ?? ""}
                                  onChange={(e) => updateItem({ amount: e.target.value === "" ? undefined : Number(e.target.value) })}
                                  className="h-8 text-sm text-right tabular-nums font-medium"
                                />
                              </TableCell>
                              <TableCell className="p-1">
                                <Select
                                  value={li.expense_account_id || ""}
                                  onValueChange={(v) => updateItem({ expense_account_id: v })}
                                  disabled={!reviewForm.association_id}
                                >
                                  <SelectTrigger className="h-8 text-xs">
                                    <SelectValue placeholder={reviewForm.association_id ? "Select GL" : "Select assoc."} />
                                  </SelectTrigger>
                                  <SelectContent>
                                    {filteredAccounts.map((a: any) => (
                                      <SelectItem key={a.id} value={a.id} className="text-xs">
                                        {a.account_number} - {a.account_name}
                                      </SelectItem>
                                    ))}
                                  </SelectContent>
                                </Select>
                              </TableCell>
                              <TableCell className="p-1 text-center">
                                <Button
                                  type="button"
                                  variant="ghost"
                                  size="icon"
                                  className="h-7 w-7 text-destructive hover:text-destructive"
                                  onClick={() => {
                                    const next = reviewData.line_items.filter((_, i) => i !== idx);
                                    setReviewData({ ...reviewData, line_items: next });
                                  }}
                                >
                                  <Trash2 className="w-3.5 h-3.5" />
                                </Button>
                              </TableCell>
                            </TableRow>
                          );
                        })}
                      </TableBody>
                    </Table>
                  </div>
                )}
                {reviewData.line_items.length > 0 && (
                  <p className="text-[11px] text-muted-foreground mt-1">
                    Sum of items: <span className="font-medium tabular-nums">{fmt(reviewData.line_items.reduce((s, li) => s + (Number(li.amount) || 0), 0))}</span>
                  </p>
                )}
              </div>

              {/* Totals */}
              <div className="flex justify-end">
                <div className="space-y-1 text-sm w-48">
                  {reviewData.subtotal > 0 && (
                    <div className="flex justify-between"><span className="text-muted-foreground">Subtotal</span><span className="tabular-nums">{fmt(reviewData.subtotal)}</span></div>
                  )}
                  {reviewData.tax > 0 && (
                    <div className="flex justify-between"><span className="text-muted-foreground">Tax</span><span className="tabular-nums">{fmt(reviewData.tax)}</span></div>
                  )}
                  {reviewData.other_charges > 0 && (
                    <div className="flex justify-between"><span className="text-muted-foreground">Other</span><span className="tabular-nums">{fmt(reviewData.other_charges)}</span></div>
                  )}
                  <div className="flex justify-between font-bold border-t border-border pt-1">
                    <span>Total</span><span className="tabular-nums">{fmt(reviewData.total_amount)}</span>
                  </div>
                </div>
              </div>

              {/* Association & Approver Selection */}
              <div className="border-t border-border pt-4 space-y-4">
                <p className="text-xs uppercase tracking-widest text-muted-foreground font-semibold">Bill Approval Settings</p>

                <div>
                  <Label>Client / Association <span className="text-destructive">*</span></Label>
                  <Select
                    value={reviewForm.association_id}
                    onValueChange={(v) => setReviewForm({ ...reviewForm, association_id: v, expense_account_id: "", approval_member_ids: [], vendor_id: "" })}
                  >
                    <SelectTrigger><SelectValue placeholder="Select Association" /></SelectTrigger>
                    <SelectContent>
                      {associations.map((a: any) => <SelectItem key={a.id} value={a.id}>{a.name}</SelectItem>)}
                    </SelectContent>
                  </Select>
                </div>

                {/* Vendor Selection */}
                {vendorNotFound && (
                  <Alert className="border-amber-300 bg-amber-50 text-amber-900">
                    <AlertTriangle className="h-4 w-4" />
                    <AlertDescription>
                      Vendor "<strong>{vendorNotFound}</strong>" wasn't auto-matched. Pick the correct vendor from the list below, or{" "}
                      <a href="/dashboard/vendors" target="_blank" rel="noopener noreferrer" className="underline font-semibold text-primary">
                        add a new vendor
                      </a>.
                    </AlertDescription>
                  </Alert>
                )}
                <div>
                  <Label>Vendor <span className="text-destructive">*</span></Label>
                  <Select
                    value={reviewForm.vendor_id}
                    onValueChange={(v) => {
                      setReviewForm({ ...reviewForm, vendor_id: v });
                      setVendorNotFound(null);
                    }}
                    disabled={!reviewForm.association_id}
                  >
                    <SelectTrigger><SelectValue placeholder={reviewForm.association_id ? "Select vendor" : "Select association first"} /></SelectTrigger>
                    <SelectContent>
                      {filteredVendors.map((v: any) => <SelectItem key={v.id} value={v.id}>{v.name}</SelectItem>)}
                    </SelectContent>
                  </Select>
                </div>

                <div className="grid grid-cols-2 gap-4">
                  <div>
                    <Label>GL Account (Expense)</Label>
                    <Select
                      value={reviewForm.expense_account_id}
                      onValueChange={(v) => {
                        setReviewForm({ ...reviewForm, expense_account_id: v });
                        // Autofill: apply to any line items that don't already have a GL account
                        if (reviewData) {
                          const next = reviewData.line_items.map((li) =>
                            li.expense_account_id ? li : { ...li, expense_account_id: v }
                          );
                          setReviewData({ ...reviewData, line_items: next });
                        }
                      }}
                      disabled={!reviewForm.association_id}
                    >
                      <SelectTrigger>
                        <SelectValue placeholder={reviewForm.association_id ? "Select GL Account" : "Select association first"} />
                      </SelectTrigger>
                      <SelectContent>
                        {filteredAccounts.map((a: any) => (
                          <SelectItem key={a.id} value={a.id}>{a.account_number} - {a.account_name}</SelectItem>
                        ))}
                      </SelectContent>
                    </Select>
                    <p className="text-[11px] text-muted-foreground mt-1">
                      Default for all lines. Override per-line in the table above if needed.
                    </p>
                  </div>

                  <div>
                    <Label>Request Approval From</Label>
                    <div className="border rounded-md p-3 max-h-[150px] overflow-y-auto bg-muted/30 space-y-2 mt-1">
                      {!reviewForm.association_id ? (
                        <p className="text-sm text-muted-foreground italic">Select an association first.</p>
                      ) : boardMembers.length === 0 ? (
                        <p className="text-sm text-muted-foreground italic">No board members with approval authority found.</p>
                      ) : (
                        boardMembers.map((bm: any) => (
                          <div key={bm.id} className="flex items-center space-x-2 bg-background p-2 rounded border">
                            <Checkbox
                              id={`inv-approver-${bm.id}`}
                              checked={reviewForm.approval_member_ids.includes(bm.id)}
                              onCheckedChange={(checked) => {
                                setReviewForm(prev => ({
                                  ...prev,
                                  approval_member_ids: checked
                                    ? [...prev.approval_member_ids, bm.id]
                                    : prev.approval_member_ids.filter((id: string) => id !== bm.id),
                                }));
                              }}
                            />
                            <Label htmlFor={`inv-approver-${bm.id}`} className="cursor-pointer flex-1">
                              <span className="font-medium text-sm">{bm.member_name}</span>
                              {bm.member_email && <span className="text-xs text-muted-foreground block">{bm.member_email}</span>}
                            </Label>
                          </div>
                        ))
                      )}
                    </div>
                    {reviewForm.approval_member_ids.length > 0 && (
                      <p className="text-xs text-muted-foreground mt-1">{reviewForm.approval_member_ids.length} approver(s) selected</p>
                    )}
                  </div>
                </div>

                <div>
                  <Label>Description / Memo</Label>
                  <Textarea
                    placeholder="Optional notes for the bill approval..."
                    value={reviewForm.description}
                    onChange={(e) => setReviewForm({ ...reviewForm, description: e.target.value })}
                    rows={2}
                  />
                </div>
              </div>
            </div>
          )}

          <DialogFooter className="mt-4">
            <Button variant="outline" onClick={() => setReviewOpen(false)} disabled={submittingReview}>
              Cancel
            </Button>
            <Button onClick={handleSubmitReview} disabled={submittingReview || !reviewForm.association_id || !reviewForm.vendor_id} className="gap-2">
              {submittingReview ? (
                <Loader2 className="h-4 w-4 animate-spin" />
              ) : (
                <FilePlus className="h-4 w-4" />
              )}
              Create Bill Approval
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>
    </div>
  );
}
