"use client";

import { useEffect, useMemo, useRef, 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 { Kpi, KpiStrip } from "@/components/ui/kpi";
import { Switch } from "@/components/ui/switch";
import { useAlertConfirm } from "@/components/ui/alert-dialog";
import { useToast } from "@/components/ui/toast";
import { useLocalStorage } from "@/lib/hooks/use-local-storage";
import { ALL_ORGANIZATIONS } from "@/lib/sag/entities";
import { formatCurrency } from "@/lib/utils";
import {
  BILL_CATEGORIES,
  migrateLegacyBill,
  PAYMENT_METHODS,
  type Bill,
  type BillAttachment,
  type BillCategory,
  type BillPayment,
  type BillStatus,
  type LegacyBill,
  type PaymentMethod,
} from "@/lib/finance/bill-types";
import { BillSuggestions } from "@/components/app/bill-suggestions";
import { BillReconcile } from "@/components/app/bill-reconcile";
import { buildSampleBills, isSampleBill } from "@/lib/finance/bill-samples";
import { logActivity } from "@/lib/activity/log";
import {
  SegmentedControl,
  SegmentedControlItem,
} from "@/components/ui/segmented-control";

type StatusFilter = "all" | BillStatus;

const STATUS_TONE: Record<BillStatus, "outline" | "info" | "success" | "destructive" | "warning"> = {
  Unscheduled: "outline",
  "Pending Review": "warning",
  Scheduled: "info",
  Paid: "success",
  Overdue: "destructive",
  Cancelled: "outline",
};

export function BillsInbox() {
  const [bills, setBills] = useLocalStorage<Bill[]>("sag.bills.v2", []);
  const [legacy, setLegacy] = useLocalStorage<LegacyBill[]>("sag.bills", []);
  const [showAdd, setShowAdd] = useState<"manual" | "csv" | "pdf" | null>(null);
  const [filter, setFilter] = useState<StatusFilter>("all");
  const [editingPaymentFor, setEditingPaymentFor] = useState<string | null>(null);
  const { toast } = useToast();
  const { confirm: confirmAlert, AlertConfirmPortal } = useAlertConfirm();

  // One-shot migration from v1 → v2.
  useEffect(() => {
    if (legacy.length === 0 || bills.length > 0) return;
    setBills(legacy.map(migrateLegacyBill));
    setLegacy([]);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  function addBill(b: Omit<Bill, "id" | "createdAt">) {
    setBills((prev) => [
      {
        ...b,
        id: `bill-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`,
        createdAt: new Date().toISOString(),
      },
      ...prev,
    ]);
  }

  function addBills(many: Array<Omit<Bill, "id" | "createdAt">>) {
    const now = Date.now();
    const created: Bill[] = many.map((b, i) => ({
      ...b,
      id: `bill-${now + i}-${Math.random().toString(36).slice(2, 6)}`,
      createdAt: new Date().toISOString(),
    }));
    setBills((prev) => [...created, ...prev]);
  }

  function updateBill(id: string, patch: Partial<Bill>) {
    setBills((prev) => prev.map((b) => (b.id === id ? { ...b, ...patch } : b)));
  }

  async function deleteBill(id: string) {
    const ok = await confirmAlert({
      title: "Delete this bill?",
      description: "This permanently removes the record. Cannot be undone.",
      actionLabel: "Delete",
      destructive: true,
    });
    if (!ok) return;
    const target = bills.find((b) => b.id === id);
    setBills((prev) => prev.filter((b) => b.id !== id));
    try {
      logActivity({
        source: "bills",
        verb: "deleted",
        title: target ? `Deleted bill from ${target.vendor}` : "Deleted bill",
        entitySlug: target?.entitySlug,
        amount: target?.amount,
        href: "/app/finance/bills",
      });
    } catch {
      // fire-and-forget
    }
  }

  function loadSampleData() {
    const samples = buildSampleBills();
    addBills(samples);
    try {
      logActivity({
        source: "bills",
        verb: "imported",
        title: `Loaded ${samples.length} sample bill${samples.length === 1 ? "" : "s"}`,
        href: "/app/finance/bills",
        meta: { sample: true, count: samples.length },
      });
    } catch {
      // fire-and-forget
    }
  }

  async function clearSampleData() {
    const count = bills.filter(isSampleBill).length;
    if (count === 0) return;
    const ok = await confirmAlert({
      title: `Remove all ${count} sample bills?`,
      description: "Your real bills stay.",
      actionLabel: "Remove samples",
      destructive: true,
    });
    if (!ok) return;
    setBills((prev) => prev.filter((b) => !isSampleBill(b)));
  }

  const sampleCount = bills.filter(isSampleBill).length;

  function logPayment(id: string, payment: BillPayment) {
    const target = bills.find((b) => b.id === id);
    updateBill(id, { payment, status: "Paid" });
    setEditingPaymentFor(null);
    toast({ title: "Payment logged", variant: "success" });
    try {
      logActivity({
        source: "bills",
        verb: "marked-paid",
        title: target ? `Paid ${target.vendor}` : "Marked bill paid",
        entitySlug: target?.entitySlug,
        amount: payment.amount,
        href: "/app/finance/bills",
        meta: {
          method: payment.method,
          paidDate: payment.paidDate,
          confirmationNumber: payment.confirmationNumber,
        },
      });
    } catch {
      // fire-and-forget
    }
  }

  // Derive status (auto-mark overdue if past due + unpaid).
  const today = new Date().toISOString().slice(0, 10);
  const derived = useMemo(
    () =>
      bills.map((b) =>
        b.status !== "Paid" && b.status !== "Cancelled" && b.dueDate < today
          ? { ...b, status: "Overdue" as BillStatus }
          : b
      ),
    [bills, today]
  );

  const filtered = filter === "all" ? derived : derived.filter((b) => b.status === filter);
  const sorted = useMemo(
    () => [...filtered].sort((a, b) => a.dueDate.localeCompare(b.dueDate)),
    [filtered]
  );

  // Stats.
  const monthStart = today.slice(0, 8) + "01";
  const monthEnd = new Date(new Date(monthStart).setMonth(new Date(monthStart).getMonth() + 1))
    .toISOString()
    .slice(0, 10);

  const thisMonth = derived.filter((b) => b.dueDate >= monthStart && b.dueDate < monthEnd);
  const dueThisMonth = thisMonth
    .filter((b) => b.status !== "Paid" && b.status !== "Cancelled")
    .reduce((a, b) => a + b.amount, 0);
  const paidThisMonth = thisMonth
    .filter((b) => b.status === "Paid")
    .reduce((a, b) => a + (b.payment?.amount ?? b.amount), 0);
  const overdueAmount = derived
    .filter((b) => b.status === "Overdue")
    .reduce((a, b) => a + b.amount, 0);
  const recurringMonthly = derived
    .filter((b) => b.recurring && b.recurrencePattern === "monthly")
    .reduce((a, b) => a + b.amount, 0);

  const counts: Record<BillStatus, number> = {
    Unscheduled: derived.filter((b) => b.status === "Unscheduled").length,
    "Pending Review": derived.filter((b) => b.status === "Pending Review").length,
    Scheduled: derived.filter((b) => b.status === "Scheduled").length,
    Paid: derived.filter((b) => b.status === "Paid").length,
    Overdue: derived.filter((b) => b.status === "Overdue").length,
    Cancelled: derived.filter((b) => b.status === "Cancelled").length,
  };

  return (
    <>
    <div className="space-y-6">
      <KpiStrip cols={4}>
        <Kpi label="Due this month" value={formatCurrency(dueThisMonth)} />
        <Kpi label="Paid this month" value={formatCurrency(paidThisMonth)} tone="emerald" />
        <Kpi label="Overdue" value={formatCurrency(overdueAmount)} tone="rose" />
        <Kpi label="Monthly recurring" value={formatCurrency(recurringMonthly)} />
      </KpiStrip>

      <Card>
        <CardContent className="p-4 flex items-center flex-wrap gap-2">
          <SegmentedControl
            value={filter}
            onValueChange={(v) => setFilter(v as StatusFilter)}
            aria-label="Filter bills by status"
            className="flex-wrap"
          >
            <SegmentedControlItem value="all" count={derived.length}>
              All
            </SegmentedControlItem>
            {(Object.keys(counts) as BillStatus[]).map((s) => (
              <SegmentedControlItem key={s} value={s} count={counts[s]}>
                {s}
              </SegmentedControlItem>
            ))}
          </SegmentedControl>
          <div className="md:ml-auto flex flex-wrap gap-2 w-full md:w-auto">
            <Button
              size="sm"
              variant={showAdd === "pdf" ? "brand" : "outline"}
              onClick={() => setShowAdd(showAdd === "pdf" ? null : "pdf")}
            >
              📎 Upload bill PDF
            </Button>
            <Button
              size="sm"
              variant={showAdd === "csv" ? "brand" : "outline"}
              onClick={() => setShowAdd(showAdd === "csv" ? null : "csv")}
            >
              📊 CSV import
            </Button>
            <Button
              size="sm"
              variant={showAdd === "manual" ? "brand" : "outline"}
              onClick={() => setShowAdd(showAdd === "manual" ? null : "manual")}
            >
              + Add bill
            </Button>
          </div>
        </CardContent>
      </Card>

      <BillSuggestions onAddBills={addBills} existingBills={bills} />

      <BillReconcile
        outstanding={derived.filter(
          (b) => b.status !== "Paid" && b.status !== "Cancelled"
        )}
        onMatch={logPayment}
      />

      {showAdd === "manual" && (
        <AddBillForm
          onAdd={(b) => {
            addBill(b);
            setShowAdd(null);
          }}
          onCancel={() => setShowAdd(null)}
        />
      )}
      {showAdd === "pdf" && (
        <PdfImport
          onAdd={(b) => {
            addBill(b);
            setShowAdd(null);
          }}
          onCancel={() => setShowAdd(null)}
        />
      )}
      {showAdd === "csv" && (
        <CsvImport
          onImport={(many) => {
            addBills(many);
            setShowAdd(null);
          }}
          onCancel={() => setShowAdd(null)}
        />
      )}

      {sorted.length === 0 ? (
        <EmptyState
          icon="🧾"
          title="No bills match this filter"
          description="Add a bill manually, drop a PDF / image to auto-extract fields, or bulk-import from a CSV."
          action={
            bills.length === 0 ? (
              <div className="flex flex-col items-center gap-2">
                <Button variant="brand" size="sm" onClick={loadSampleData}>
                  ✨ Load 12 sample bills
                </Button>
                <p className="text-[11px] text-muted-foreground">
                  Demo data tagged with <code>[SAMPLE]</code> in notes. One-click clear later.
                </p>
              </div>
            ) : undefined
          }
        />
      ) : (
        <div className="space-y-2">
          {sorted.map((b) => {
            const org = ALL_ORGANIZATIONS.find((o) => o.slug === b.entitySlug);
            const isOpenPayment = editingPaymentFor === b.id;
            return (
              <Card key={b.id}>
                <CardContent className="p-4">
                  <div className="flex items-start gap-3 flex-wrap">
                    <div className="min-w-0 flex-1">
                      <div className="flex items-center gap-2 flex-wrap mb-1">
                        <Badge variant={STATUS_TONE[b.status]}>{b.status}</Badge>
                        {b.category && <Badge variant="outline">{b.category}</Badge>}
                        {b.recurring && (
                          <Badge variant="secondary">↻ {b.recurrencePattern ?? "recurring"}</Badge>
                        )}
                        <Badge variant="outline" className="text-[10px]">
                          {SOURCE_LABEL[b.source]}
                        </Badge>
                        <span className="text-xs text-muted-foreground inline-flex items-center gap-1">
                          {org?.emoji} {org?.name}
                        </span>
                      </div>
                      <div className="flex items-baseline gap-3 flex-wrap">
                        <span className="text-base font-semibold">{b.vendor}</span>
                        <span className="text-base font-semibold tabular-nums">
                          {formatCurrency(b.amount)}
                        </span>
                        <span className="text-xs text-muted-foreground">
                          Due {b.dueDate}
                        </span>
                        {b.accountNumber && (
                          <span className="text-[11px] text-muted-foreground font-mono">
                            #{b.accountNumber}
                          </span>
                        )}
                      </div>
                      {b.payment && (
                        <p className="mt-1 text-[11px] text-green-700 dark:text-green-400">
                          ✓ Paid {b.payment.paidDate} via {b.payment.method}
                          {b.payment.confirmationNumber
                            ? ` — conf #${b.payment.confirmationNumber}`
                            : ""}
                          {b.payment.fromAccount ? ` from ${b.payment.fromAccount}` : ""}
                        </p>
                      )}
                      {b.notes && (
                        <p className="mt-1 text-xs text-muted-foreground italic">{b.notes}</p>
                      )}
                      {b.attachments.length > 0 && (
                        <div className="mt-2 flex flex-wrap gap-2">
                          {b.attachments.map((a) => (
                            <a
                              key={a.id}
                              href={`/api/social/media/${a.id}`}
                              target="_blank"
                              rel="noopener noreferrer"
                              className="text-[11px] inline-flex items-center gap-1 rounded border bg-muted/30 px-2 py-1 hover:bg-accent"
                            >
                              {a.mime.startsWith("image/") ? "🖼️" : "📄"}{" "}
                              {a.filename ?? a.id}
                            </a>
                          ))}
                        </div>
                      )}
                    </div>
                    <div className="flex flex-wrap items-center gap-1 shrink-0 w-full md:w-auto">
                      {b.status !== "Paid" && b.status !== "Cancelled" && (
                        <Button
                          variant="brand"
                          size="sm"
                          onClick={() => setEditingPaymentFor(isOpenPayment ? null : b.id)}
                        >
                          {isOpenPayment ? "Cancel" : "Log payment"}
                        </Button>
                      )}
                      {b.status === "Unscheduled" && (
                        <Button
                          variant="outline"
                          size="sm"
                          onClick={() => updateBill(b.id, { status: "Scheduled" })}
                        >
                          Schedule
                        </Button>
                      )}
                      <Button variant="ghost" size="sm" onClick={() => deleteBill(b.id)}>
                        ×
                      </Button>
                    </div>
                  </div>
                  {isOpenPayment && (
                    <PaymentForm
                      defaultAmount={b.amount}
                      onSave={(p) => logPayment(b.id, p)}
                      onCancel={() => setEditingPaymentFor(null)}
                    />
                  )}
                </CardContent>
              </Card>
            );
          })}
        </div>
      )}

      {sampleCount > 0 && (
        <div className="text-center">
          <Button variant="ghost" size="sm" onClick={clearSampleData}>
            🧹 Clear {sampleCount} sample bill{sampleCount === 1 ? "" : "s"}
          </Button>
        </div>
      )}

      <p className="text-xs text-muted-foreground">
        Bills saved locally in this browser. PDF / image upload uses Claude vision for
        field extraction. Outbound ACH from SAG Manager itself isn’t wired (regulatory work) —
        log payments here as the system of record once they clear in your bank or card UI.
      </p>
    </div>
    <AlertConfirmPortal />
    </>
  );
}

const SOURCE_LABEL: Record<Bill["source"], string> = {
  manual: "Manual",
  gmail: "Gmail",
  pdf: "PDF/Image",
  csv: "CSV",
  plaid: "Plaid",
};

// ──────────────────────────────────────────────────────────────────────────
// Manual add form (kept simple — categorisation now included)
// ──────────────────────────────────────────────────────────────────────────

function AddBillForm({
  initial,
  onAdd,
  onCancel,
}: {
  initial?: Partial<Bill>;
  onAdd: (b: Omit<Bill, "id" | "createdAt">) => void;
  onCancel: () => void;
}) {
  const [vendor, setVendor] = useState(initial?.vendor ?? "");
  const [amount, setAmount] = useState(
    initial?.amount != null ? String(initial.amount) : ""
  );
  const [dueDate, setDueDate] = useState(
    initial?.dueDate ?? new Date().toISOString().slice(0, 10)
  );
  const [entitySlug, setEntitySlug] = useState(initial?.entitySlug ?? "south-armz-global");
  const [category, setCategory] = useState<BillCategory | "">(
    initial?.category ?? ""
  );
  const [accountNumber, setAccountNumber] = useState(initial?.accountNumber ?? "");
  const [recurring, setRecurring] = useState(initial?.recurring ?? false);
  const [recurrencePattern, setRecurrencePattern] = useState(
    initial?.recurrencePattern ?? "monthly"
  );
  const [notes, setNotes] = useState(initial?.notes ?? "");
  const [attachments, setAttachments] = useState<BillAttachment[]>(initial?.attachments ?? []);

  function submit(e: React.FormEvent) {
    e.preventDefault();
    const n = parseFloat(amount);
    if (!vendor.trim() || isNaN(n)) return;
    onAdd({
      vendor: vendor.trim(),
      amount: n,
      dueDate,
      entitySlug,
      status: "Unscheduled",
      recurring,
      recurrencePattern: recurring ? recurrencePattern : undefined,
      notes: notes.trim() || undefined,
      category: category || undefined,
      accountNumber: accountNumber.trim() || undefined,
      source: initial?.source ?? "manual",
      sourceRef: initial?.sourceRef,
      attachments,
    });
  }

  return (
    <Card>
      <CardContent className="p-6">
        <form onSubmit={submit} className="grid gap-3 md:grid-cols-2">
          <Field label="Vendor">
            <Input
              value={vendor}
              onChange={(e) => setVendor(e.target.value)}
              placeholder="e.g. Duke Energy"
              required
            />
          </Field>
          <Field label="Amount">
            <Input
              type="number"
              step="0.01"
              value={amount}
              onChange={(e) => setAmount(e.target.value)}
              placeholder="0.00"
              required
            />
          </Field>
          <Field label="Due date">
            <Input
              type="date"
              value={dueDate}
              onChange={(e) => setDueDate(e.target.value)}
              required
            />
          </Field>
          <Field label="Entity">
            <select
              value={entitySlug}
              onChange={(e) => setEntitySlug(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="Category">
            <select
              value={category}
              onChange={(e) => setCategory(e.target.value as BillCategory | "")}
              className="w-full h-10 rounded-md border border-input bg-background px-3 text-sm"
            >
              <option value="">— Uncategorized —</option>
              {BILL_CATEGORIES.map((c) => (
                <option key={c} value={c}>
                  {c}
                </option>
              ))}
            </select>
          </Field>
          <Field label="Account / invoice number (optional)">
            <Input
              value={accountNumber}
              onChange={(e) => setAccountNumber(e.target.value)}
              placeholder="e.g. 7-823-091"
            />
          </Field>
          <div className="md:col-span-2 flex items-center gap-3">
            <label className="flex items-center gap-2 text-sm cursor-pointer">
              <Switch
                checked={recurring}
                onCheckedChange={setRecurring}
                aria-label="Recurring"
              />
              Recurring
            </label>
            {recurring && (
              <select
                value={recurrencePattern}
                onChange={(e) => setRecurrencePattern(e.target.value)}
                className="h-9 rounded-md border border-input bg-background px-3 text-sm"
              >
                <option value="monthly">Monthly</option>
                <option value="quarterly">Quarterly</option>
                <option value="annual">Annual</option>
                <option value="weekly">Weekly</option>
              </select>
            )}
          </div>
          {attachments.length > 0 && (
            <div className="md:col-span-2">
              <label className="text-xs text-muted-foreground">Attachments</label>
              <div className="mt-1 flex flex-wrap gap-2">
                {attachments.map((a) => (
                  <div
                    key={a.id}
                    className="text-[11px] inline-flex items-center gap-1 rounded border bg-muted/30 px-2 py-1"
                  >
                    {a.mime.startsWith("image/") ? "🖼️" : "📄"} {a.filename ?? a.id}
                    <button
                      type="button"
                      onClick={() =>
                        setAttachments((prev) => prev.filter((x) => x.id !== a.id))
                      }
                      className="ml-1 text-muted-foreground hover:text-destructive"
                    >
                      ×
                    </button>
                  </div>
                ))}
              </div>
            </div>
          )}
          <Field label="Notes" className="md:col-span-2">
            <textarea
              value={notes}
              onChange={(e) => setNotes(e.target.value)}
              className="w-full rounded-md border border-input bg-background p-2 text-sm"
              rows={2}
            />
          </Field>
          <div className="md:col-span-2 flex items-center justify-end gap-2">
            <Button variant="ghost" size="sm" onClick={onCancel} type="button">
              Cancel
            </Button>
            <Button variant="brand" size="sm" type="submit">
              Add bill
            </Button>
          </div>
        </form>
      </CardContent>
    </Card>
  );
}

// ──────────────────────────────────────────────────────────────────────────
// PDF / image import — Claude vision extracts vendor/amount/due/category
// ──────────────────────────────────────────────────────────────────────────

interface ExtractedBill {
  vendor?: string;
  amount?: number;
  dueDate?: string | null;
  accountNumber?: string | null;
  category?: string;
  lineItems?: Array<{ description: string; amount: number }>;
  confidence?: "high" | "medium" | "low";
  notes?: string;
}

function PdfImport({
  onAdd,
  onCancel,
}: {
  onAdd: (b: Omit<Bill, "id" | "createdAt">) => void;
  onCancel: () => void;
}) {
  const [stage, setStage] = useState<"idle" | "uploading" | "extracting" | "review">("idle");
  const [error, setError] = useState<string>("");
  const [attachment, setAttachment] = useState<BillAttachment | null>(null);
  const [extracted, setExtracted] = useState<ExtractedBill | null>(null);
  const fileInputRef = useRef<HTMLInputElement>(null);

  async function handleFile(file: File) {
    setError("");
    setStage("uploading");
    try {
      const fd = new FormData();
      fd.append("file", file);
      fd.append("source", "upload");
      const uploadResp = await fetch("/api/social/media", { method: "POST", body: fd });
      const uploadData = await uploadResp.json();
      if (!uploadResp.ok) throw new Error(uploadData.error || "Upload failed");
      const att: BillAttachment = {
        id: uploadData.media.id,
        mime: uploadData.media.mime,
        filename: file.name,
        source: "upload",
      };
      setAttachment(att);

      setStage("extracting");
      const extractResp = await fetch("/api/bills/extract", {
        method: "POST",
        headers: { "content-type": "application/json" },
        body: JSON.stringify({ mediaId: att.id }),
      });
      const extractData = await extractResp.json();
      if (!extractResp.ok) {
        // Surface but still let user fill in manually with the attachment.
        setError(extractData.error || "Extraction failed");
        setExtracted({});
      } else {
        setExtracted(extractData.extracted ?? {});
      }
      setStage("review");
    } catch (e) {
      setError(e instanceof Error ? e.message : "Unknown error");
      setStage("idle");
    }
  }

  if (stage === "review" && attachment) {
    const initial: Partial<Bill> = {
      vendor: extracted?.vendor,
      amount: extracted?.amount,
      dueDate: extracted?.dueDate || undefined,
      accountNumber: extracted?.accountNumber || undefined,
      category: BILL_CATEGORIES.includes((extracted?.category ?? "") as BillCategory)
        ? (extracted?.category as BillCategory)
        : undefined,
      notes:
        extracted?.notes ||
        (extracted?.lineItems && extracted.lineItems.length > 0
          ? `Line items: ${extracted.lineItems.map((l) => `${l.description} ${l.amount}`).join("; ")}`
          : undefined),
      source: "pdf",
      sourceRef: attachment.id,
      attachments: [attachment],
    };
    return (
      <div className="space-y-3">
        <Card className="border-dashed">
          <CardContent className="p-4 text-sm">
            <div className="flex items-center justify-between flex-wrap gap-2">
              <div>
                <strong>Extracted fields</strong> — review + edit before saving. Confidence:{" "}
                <Badge variant={extracted?.confidence === "high" ? "success" : "warning"}>
                  {extracted?.confidence ?? "unknown"}
                </Badge>
              </div>
              <Button variant="ghost" size="sm" onClick={onCancel}>
                Discard
              </Button>
            </div>
            {error && <p className="mt-2 text-xs text-destructive">{error}</p>}
          </CardContent>
        </Card>
        <AddBillForm initial={initial} onAdd={onAdd} onCancel={onCancel} />
      </div>
    );
  }

  return (
    <Card>
      <CardContent className="p-6 space-y-3">
        <div className="flex items-center justify-between">
          <div>
            <h3 className="text-base font-semibold">Upload bill PDF or image</h3>
            <p className="text-xs text-muted-foreground">
              Claude vision extracts vendor, amount, due date, account #, and category. Review
              the fields before saving.
            </p>
          </div>
          <Button variant="ghost" size="sm" onClick={onCancel}>
            Cancel
          </Button>
        </div>
        <div
          className="rounded-md border border-dashed bg-muted/30 p-8 text-center cursor-pointer hover:bg-muted/50"
          onClick={() => fileInputRef.current?.click()}
          onDragOver={(e) => {
            e.preventDefault();
            e.dataTransfer.dropEffect = "copy";
          }}
          onDrop={(e) => {
            e.preventDefault();
            if (e.dataTransfer.files.length > 0) void handleFile(e.dataTransfer.files[0]);
          }}
        >
          <div className="text-3xl mb-2">📎</div>
          <p className="text-sm font-medium">
            {stage === "uploading"
              ? "Uploading…"
              : stage === "extracting"
                ? "Claude is reading your bill…"
                : "Drop a PDF, JPG, or PNG here, or click to browse"}
          </p>
          <p className="text-[11px] text-muted-foreground mt-1">
            Max 50 MB. Stored at <code>.data/social-media/</code> (mode 600, gitignored).
          </p>
        </div>
        {error && <p className="text-xs text-destructive">{error}</p>}
        <input
          ref={fileInputRef}
          type="file"
          accept="image/png,image/jpeg,image/webp,application/pdf"
          className="hidden"
          onChange={(e) => {
            if (e.target.files && e.target.files.length > 0) {
              void handleFile(e.target.files[0]);
              e.target.value = "";
            }
          }}
        />
      </CardContent>
    </Card>
  );
}

// ──────────────────────────────────────────────────────────────────────────
// CSV bulk import
// ──────────────────────────────────────────────────────────────────────────

interface CsvCandidate {
  vendor: string;
  amount: number;
  dueDate?: string;
  entitySlug?: string;
  category?: string;
  accountNumber?: string;
  notes?: string;
  recurring?: boolean;
  recurrencePattern?: string;
  rowError?: string;
}

function CsvImport({
  onImport,
  onCancel,
}: {
  onImport: (bills: Array<Omit<Bill, "id" | "createdAt">>) => void;
  onCancel: () => void;
}) {
  const [csvText, setCsvText] = useState("");
  const [candidates, setCandidates] = useState<CsvCandidate[] | null>(null);
  const [parsing, setParsing] = useState(false);
  const [error, setError] = useState<string>("");

  async function parse() {
    setError("");
    setParsing(true);
    try {
      const resp = await fetch("/api/bills/import-csv", {
        method: "POST",
        headers: { "content-type": "application/json" },
        body: JSON.stringify({ csv: csvText }),
      });
      const data = await resp.json();
      if (!resp.ok) throw new Error(data.error || "Parse failed");
      setCandidates(data.candidates ?? []);
    } catch (e) {
      setError(e instanceof Error ? e.message : "Failed");
    } finally {
      setParsing(false);
    }
  }

  function commit() {
    if (!candidates) return;
    const ok = candidates.filter((c) => !c.rowError);
    const bills: Array<Omit<Bill, "id" | "createdAt">> = ok.map((c) => {
      const validCategory = BILL_CATEGORIES.includes((c.category ?? "") as BillCategory)
        ? (c.category as BillCategory)
        : undefined;
      return {
        vendor: c.vendor,
        amount: c.amount,
        dueDate: c.dueDate ?? new Date().toISOString().slice(0, 10),
        entitySlug: c.entitySlug ?? "south-armz-global",
        category: validCategory,
        accountNumber: c.accountNumber,
        notes: c.notes,
        recurring: !!c.recurring,
        recurrencePattern: c.recurrencePattern,
        status: "Unscheduled",
        source: "csv",
        attachments: [],
      };
    });
    onImport(bills);
  }

  return (
    <Card>
      <CardContent className="p-6 space-y-3">
        <div className="flex items-center justify-between flex-wrap gap-2">
          <div>
            <h3 className="text-base font-semibold">Bulk import bills from CSV</h3>
            <p className="text-xs text-muted-foreground">
              Required columns: <code>vendor</code>, <code>amount</code>. Recognized columns:{" "}
              <code>dueDate</code>, <code>entity</code>, <code>category</code>,{" "}
              <code>accountNumber</code>, <code>notes</code>, <code>recurring</code>,{" "}
              <code>recurrencePattern</code>. Case-insensitive; common aliases (payee/merchant
              → vendor, total → amount) are accepted.
            </p>
          </div>
          <Button variant="ghost" size="sm" onClick={onCancel}>
            Cancel
          </Button>
        </div>
        <textarea
          value={csvText}
          onChange={(e) => setCsvText(e.target.value)}
          rows={8}
          className="w-full rounded-md border border-input bg-background p-3 text-sm font-mono"
          placeholder="vendor,amount,dueDate,category,entity&#10;Duke Energy,142.31,2026-06-01,Utilities,south-armz-global"
        />
        <div className="flex items-center gap-2">
          <Button variant="brand" size="sm" disabled={parsing || !csvText.trim()} onClick={parse}>
            {parsing ? "Parsing…" : "Parse CSV"}
          </Button>
          {candidates && (
            <Button
              size="sm"
              variant="outline"
              disabled={candidates.every((c) => c.rowError)}
              onClick={commit}
            >
              Import {candidates.filter((c) => !c.rowError).length} bill
              {candidates.filter((c) => !c.rowError).length === 1 ? "" : "s"}
            </Button>
          )}
        </div>
        {error && <p className="text-xs text-destructive">{error}</p>}
        {candidates && candidates.length > 0 && (
          <div className="rounded-md border bg-background overflow-x-auto">
            <table className="w-full min-w-[640px] text-xs">
              <thead className="section-label border-b">
                <tr>
                  <th className="px-2 py-1.5 text-left">Vendor</th>
                  <th className="px-2 py-1.5 text-right">Amount</th>
                  <th className="px-2 py-1.5 text-left">Due</th>
                  <th className="px-2 py-1.5 text-left">Category</th>
                  <th className="px-2 py-1.5 text-left">Entity</th>
                  <th className="px-2 py-1.5 text-left">Error</th>
                </tr>
              </thead>
              <tbody>
                {candidates.map((c, i) => (
                  <tr
                    key={i}
                    className={`border-b last:border-0 ${
                      c.rowError ? "bg-destructive/5" : ""
                    }`}
                  >
                    <td className="px-2 py-1.5">{c.vendor}</td>
                    <td className="px-2 py-1.5 text-right tabular-nums">
                      {Number.isFinite(c.amount) ? formatCurrency(c.amount) : "—"}
                    </td>
                    <td className="px-2 py-1.5 font-mono">{c.dueDate ?? "—"}</td>
                    <td className="px-2 py-1.5">{c.category ?? "—"}</td>
                    <td className="px-2 py-1.5">{c.entitySlug ?? "—"}</td>
                    <td className="px-2 py-1.5 text-destructive">{c.rowError ?? ""}</td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        )}
      </CardContent>
    </Card>
  );
}

// ──────────────────────────────────────────────────────────────────────────
// Payment logging form
// ──────────────────────────────────────────────────────────────────────────

function PaymentForm({
  defaultAmount,
  onSave,
  onCancel,
}: {
  defaultAmount: number;
  onSave: (p: BillPayment) => void;
  onCancel: () => void;
}) {
  const [method, setMethod] = useState<PaymentMethod>("Truist Bill Pay");
  const [paidDate, setPaidDate] = useState(new Date().toISOString().slice(0, 10));
  const [amount, setAmount] = useState(String(defaultAmount));
  const [confirmationNumber, setConfirmationNumber] = useState("");
  const [fromAccount, setFromAccount] = useState("");
  const [notes, setNotes] = useState("");
  const { toast } = useToast();

  function submit() {
    const n = parseFloat(amount);
    if (!Number.isFinite(n) || n <= 0) {
      toast({ title: "Enter a positive amount.", variant: "warning" });
      return;
    }
    onSave({
      method,
      paidDate,
      amount: n,
      confirmationNumber: confirmationNumber.trim() || undefined,
      fromAccount: fromAccount.trim() || undefined,
      notes: notes.trim() || undefined,
    });
  }

  return (
    <div className="mt-4 rounded-md border bg-muted/30 p-4 space-y-3">
      <div className="text-xs font-semibold text-muted-foreground">Log payment</div>
      <div className="grid gap-3 md:grid-cols-3">
        <Field label="Method">
          <select
            value={method}
            onChange={(e) => setMethod(e.target.value as PaymentMethod)}
            className="w-full h-10 rounded-md border border-input bg-background px-3 text-sm"
          >
            {PAYMENT_METHODS.map((m) => (
              <option key={m} value={m}>
                {m}
              </option>
            ))}
          </select>
        </Field>
        <Field label="Paid date">
          <Input
            type="date"
            value={paidDate}
            onChange={(e) => setPaidDate(e.target.value)}
          />
        </Field>
        <Field label="Amount">
          <Input
            type="number"
            step="0.01"
            value={amount}
            onChange={(e) => setAmount(e.target.value)}
          />
        </Field>
        <Field label="Confirmation # (optional)">
          <Input
            value={confirmationNumber}
            onChange={(e) => setConfirmationNumber(e.target.value)}
            placeholder="e.g. CONF1234"
          />
        </Field>
        <Field label="From account (optional)">
          <Input
            value={fromAccount}
            onChange={(e) => setFromAccount(e.target.value)}
            placeholder="e.g. Truist ****1234"
          />
        </Field>
        <Field label="Notes (optional)">
          <Input
            value={notes}
            onChange={(e) => setNotes(e.target.value)}
            placeholder="Anything to flag"
          />
        </Field>
      </div>
      <div className="flex items-center justify-end gap-2">
        <Button variant="ghost" size="sm" onClick={onCancel}>
          Cancel
        </Button>
        <Button variant="brand" size="sm" onClick={submit}>
          Save payment
        </Button>
      </div>
    </div>
  );
}

// ──────────────────────────────────────────────────────────────────────────
// Shared primitives
// ──────────────────────────────────────────────────────────────────────────

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>
  );
}

