import { useQuery, useQueryClient } from "@tanstack/react-query";
import { useMemo, useState } from "react";
import { accounting } from "@/lib/accountingClient";
import { useCompanyId } from "./lib/useCompanyId";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Card, CardContent } from "@/components/ui/card";
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger, DialogFooter } from "@/components/ui/dialog";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { Textarea } from "@/components/ui/textarea";
import {
  DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { Plus, Search, Trash2, MoreHorizontal, CheckCircle2, FileText, DollarSign, Loader2 } from "lucide-react";
import { toast } from "sonner";
import { money, fmtDate } from "./lib/format";
import { DocumentForm } from "./components/DocumentForm";
import { StatusBadge } from "./components/StatusBadge";
import { EmptyState } from "./components/EmptyState";
import { ensureUndepositedFunds } from "./lib/undeposited";

const RANGES = [
  { value: "all", label: "All time" },
  { value: "30", label: "Last 30 days" },
  { value: "90", label: "Last 90 days" },
  { value: "year", label: "This year" },
];

export default function AccountingInvoicesPage() {
  const { companyId, loading: companyLoading, error: companyError, associationId, associationName } = useCompanyId();
  const cid = companyId ?? "";
  const cur = "USD";
  const qc = useQueryClient();
  const [open, setOpen] = useState(false);
  const [search, setSearch] = useState("");
  const [statusFilter, setStatusFilter] = useState("all");
  const [range, setRange] = useState("all");

  const { data: invoices = [], isLoading } = useQuery({
    queryKey: ["invoices", cid],
    enabled: !!cid,
    queryFn: async () => {
      const { data } = await accounting
        .from("invoices").select("*, customers(name)")
        .eq("company_id", cid).order("issue_date", { ascending: false });
      return data ?? [];
    },
  });

  const { data: customers = [] } = useQuery({
    queryKey: ["customers-lookup", cid],
    enabled: !!cid,
    queryFn: async () => (await accounting.from("customers").select("id,name").eq("company_id", cid).order("name")).data ?? [],
  });

  const filtered = useMemo(() => {
    const q = search.trim().toLowerCase();
    const now = new Date();
    let cutoff: Date | null = null;
    if (range === "30") cutoff = new Date(now.getTime() - 30 * 86400000);
    else if (range === "90") cutoff = new Date(now.getTime() - 90 * 86400000);
    else if (range === "year") cutoff = new Date(now.getFullYear(), 0, 1);
    return (invoices as any[]).filter((i: any) => {
      if (statusFilter !== "all" && i.status !== statusFilter) return false;
      if (cutoff && new Date(i.issue_date) < cutoff) return false;
      if (q) {
        const hay = `${i.number} ${i.customers?.name ?? ""}`.toLowerCase();
        if (!hay.includes(q)) return false;
      }
      return true;
    });
  }, [invoices, search, statusFilter, range]);

  const save = async (v: any) => {
    if (!v.number.trim()) return toast.error("Invoice number required");
    if (v.items.some((i: any) => !i.description.trim())) return toast.error("All items need a description");
    const { data: inv, error } = await accounting.from("invoices").insert({
      company_id: cid,
      customer_id: v.customerId || null,
      number: v.number,
      issue_date: v.issueDate,
      due_date: v.dueDate || null,
      subtotal: v.subtotal, tax: v.tax, total: v.total,
      notes: v.notes || null,
      status: v.status,
    }).select().single();
    if (error || !inv) return toast.error(error?.message ?? "Failed");
    const rows = v.items.map((it: any) => ({
      invoice_id: inv.id,
      description: it.description,
      quantity: it.quantity,
      rate: it.rate,
      amount: +(it.quantity * it.rate * (1 + it.taxPct / 100)).toFixed(2),
    }));
    await accounting.from("invoice_items").insert(rows);
    toast.success(v.status === "draft" ? "Draft saved" : "Invoice sent");
    setOpen(false);
    qc.invalidateQueries({ queryKey: ["invoices", cid] });
  };

  const setStatus = async (id: string, status: string) => {
    const { error } = await accounting.from("invoices").update({ status: status as any }).eq("id", id);
    if (error) return toast.error(error.message);
    qc.invalidateQueries({ queryKey: ["invoices", cid] });
  };

  const remove = async (id: string) => {
    const { error } = await accounting.from("invoices").delete().eq("id", id);
    if (error) return toast.error(error.message);
    qc.invalidateQueries({ queryKey: ["invoices", cid] });
  };

  // Receive Payment dialog
  const [payInv, setPayInv] = useState<any | null>(null);
  const [payDate, setPayDate] = useState(new Date().toLocaleDateString("en-CA", { timeZone: "America/New_York" }));
  const [payMethod, setPayMethod] = useState<"check" | "ach" | "wire" | "credit_card" | "cash" | "other">("check");
  const [payAccountId, setPayAccountId] = useState("");
  const [payReference, setPayReference] = useState("");
  const [payMemo, setPayMemo] = useState("");
  const [payAmount, setPayAmount] = useState(0);
  const [partialAction, setPartialAction] = useState<"open" | "writeoff">("open");
  const [paying, setPaying] = useState(false);

  const { data: depositAccounts = [] } = useQuery({
    queryKey: ["deposit-accounts", cid],
    enabled: !!cid,
    queryFn: async () => {
      const { data } = await accounting.from("accounts")
        .select("id,name,code,balance,is_bank,is_system")
        .eq("company_id", cid)
        .or("is_bank.eq.true,name.eq.Undeposited Funds")
        .order("code");
      return data ?? [];
    },
  });

  const openReceivePayment = async (inv: any) => {
    // Ensure Undeposited Funds exists
    await ensureUndepositedFunds(cid);
    qc.invalidateQueries({ queryKey: ["deposit-accounts", cid] });
    const balance = Math.max(0, Number(inv.total) - Number(inv.paid_amount ?? 0));
    setPayInv({ ...inv, balance });
    setPayAmount(balance);
    setPayDate(new Date().toLocaleDateString("en-CA", { timeZone: "America/New_York" }));
    setPayMethod("check");
    setPayReference("");
    setPayMemo("");
    setPartialAction("open");
    setPayAccountId("");
  };

  const savePayment = async () => {
    if (!payInv || !payAccountId) return toast.error("Deposit account required");
    if (!payAmount || payAmount <= 0) return toast.error("Invalid amount");
    setPaying(true);
    try {
      const acct = (depositAccounts as any[]).find((a) => a.id === payAccountId);
      const customerName = payInv.customers?.name ?? "Customer";
      const refLabel = payReference || payMethod.toUpperCase();

      // Ledger transaction (debit = money in)
      await accounting.from("transactions").insert({
        company_id: cid,
        account_id: payAccountId,
        date: payDate,
        type: "debit",
        amount: payAmount,
        description: `Customer Payment · ${customerName} · Invoice ${payInv.number}${payMemo ? " · " + payMemo : ""}`,
        category: "Customer Payment",
        reference: refLabel,
      });

      // Balance update (debit on asset = +)
      if (acct) {
        await accounting.from("accounts").update({ balance: Number(acct.balance) + Number(payAmount) }).eq("id", acct.id);
      }

      // Update invoice
      const newPaid = Number(payInv.paid_amount ?? 0) + Number(payAmount);
      const fullyPaid = newPaid >= Number(payInv.total);
      const writeoff = !fullyPaid && partialAction === "writeoff";
      await accounting.from("invoices").update({
        paid_amount: writeoff ? Number(payInv.total) : newPaid,
        status: (fullyPaid || writeoff) ? "paid" : "sent",
      }).eq("id", payInv.id);

      toast.success(fullyPaid ? "Payment received — invoice paid" : writeoff ? "Payment received — balance written off" : "Partial payment recorded");
      setPayInv(null);
      qc.invalidateQueries({ queryKey: ["invoices", cid] });
      qc.invalidateQueries({ queryKey: ["deposit-accounts", cid] });
      qc.invalidateQueries({ queryKey: ["accounts", cid] });
      qc.invalidateQueries({ queryKey: ["transactions", cid] });
    } catch (e: any) {
      toast.error(e?.message ?? "Failed");
    } finally {
      setPaying(false);
    }
  };

  const remainingAfter = payInv ? Math.max(0, Number(payInv.balance) - Number(payAmount)) : 0;
  const isPartial = remainingAfter > 0;

  if (!associationId) return <p className="text-sm text-muted-foreground">Select an association.</p>;
  if (companyLoading) return <div className="flex justify-center py-12"><Loader2 className="h-6 w-6 animate-spin text-muted-foreground" /></div>;
  if (companyError || !companyId) return <p className="text-sm text-muted-foreground text-center py-12">{companyError || "Accounting setup is not ready."}</p>;

  return (
    <div className="space-y-6">
      <div className="flex flex-wrap items-center justify-between gap-3">
        <div>
          <h1 className="text-2xl font-semibold tracking-tight">Invoices</h1>
          <p className="text-sm text-muted-foreground">{filtered.length} of {(invoices as any[]).length}</p>
        </div>
        <Dialog open={open} onOpenChange={setOpen}>
          <DialogTrigger asChild>
            <Button className="bg-emerald-600 hover:bg-emerald-700 text-white">
              <Plus className="mr-1 h-4 w-4" /> New Invoice
            </Button>
          </DialogTrigger>
          <DialogContent className="max-w-4xl">
            <DialogHeader><DialogTitle>New Invoice</DialogTitle></DialogHeader>
            <DocumentForm
              kind="Invoice"
              numberPrefix="INV"
              customers={customers as any}
              currency={cur}
              companyName={associationName ?? ""}
              dueDateLabel="Due Date"
              draftStatus="draft"
              sentStatus="sent"
              onSubmit={save}
              onClose={() => setOpen(false)}
            />
          </DialogContent>
        </Dialog>
      </div>

      <Card className="border-border/60 shadow-sm">
        <CardContent className="p-4">
          <div className="flex flex-wrap items-center gap-2">
            <div className="relative min-w-[220px] flex-1">
              <Search className="pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" />
              <Input placeholder="Search invoice # or customer…" className="h-9 pl-9"
                value={search} onChange={(e) => setSearch(e.target.value)} />
            </div>
            <Select value={statusFilter} onValueChange={setStatusFilter}>
              <SelectTrigger className="h-9 w-[160px]"><SelectValue placeholder="Status" /></SelectTrigger>
              <SelectContent>
                <SelectItem value="all">All statuses</SelectItem>
                <SelectItem value="draft">Draft</SelectItem>
                <SelectItem value="sent">Sent</SelectItem>
                <SelectItem value="overdue">Overdue</SelectItem>
                <SelectItem value="paid">Paid</SelectItem>
              </SelectContent>
            </Select>
            <Select value={range} onValueChange={setRange}>
              <SelectTrigger className="h-9 w-[160px]"><SelectValue placeholder="Date range" /></SelectTrigger>
              <SelectContent>
                {RANGES.map((r) => <SelectItem key={r.value} value={r.value}>{r.label}</SelectItem>)}
              </SelectContent>
            </Select>
          </div>
        </CardContent>
      </Card>

      <Card className="border-border/60 shadow-sm">
        <CardContent className="p-0">
          <div className="overflow-x-auto">
            <table className="w-full text-sm">
              <thead className="bg-muted/40 text-xs uppercase tracking-wider text-muted-foreground">
                <tr>
                  <th className="px-6 py-3 text-left font-medium">Invoice #</th>
                  <th className="px-6 py-3 text-left font-medium">Customer</th>
                  <th className="px-6 py-3 text-left font-medium">Date</th>
                  <th className="px-6 py-3 text-left font-medium">Due Date</th>
                  <th className="px-6 py-3 text-right font-medium">Amount</th>
                  <th className="px-6 py-3 text-left font-medium">Status</th>
                  <th className="w-10" />
                </tr>
              </thead>
              <tbody className="divide-y divide-border/60">
                {isLoading && Array.from({ length: 5 }).map((_, r) => (
                  <tr key={`sk-${r}`}>
                    {Array.from({ length: 7 }).map((_, c) => (
                      <td key={c} className="px-6 py-3"><div className="h-4 rounded bg-muted animate-pulse" style={{ width: `${40 + ((r * 13 + c * 17) % 50)}%` }} /></td>
                    ))}
                  </tr>
                ))}
                {!isLoading && filtered.map((i: any) => (
                  <tr key={i.id}>
                    <td className="px-6 py-3 font-medium">{i.number}</td>
                    <td className="px-6 py-3">{i.customers?.name ?? "—"}</td>
                    <td className="px-6 py-3 text-muted-foreground">{fmtDate(i.issue_date)}</td>
                    <td className="px-6 py-3 text-muted-foreground">{fmtDate(i.due_date)}</td>
                    <td className="px-6 py-3 text-right font-semibold tabular-nums">{money(i.total, cur)}</td>
                    <td className="px-6 py-3"><StatusBadge status={i.status} /></td>
                    <td className="px-2 py-3">
                      <DropdownMenu>
                        <DropdownMenuTrigger asChild>
                          <Button variant="ghost" size="icon" className="h-8 w-8"><MoreHorizontal className="h-4 w-4" /></Button>
                        </DropdownMenuTrigger>
                        <DropdownMenuContent align="end">
                          {i.status !== "paid" && (
                            <DropdownMenuItem onClick={() => openReceivePayment(i)}>
                              <DollarSign className="mr-2 h-4 w-4" /> Receive Payment
                            </DropdownMenuItem>
                          )}
                          {i.status !== "paid" && (
                            <DropdownMenuItem onClick={() => setStatus(i.id, "paid")}>
                              <CheckCircle2 className="mr-2 h-4 w-4" /> Mark as Paid
                            </DropdownMenuItem>
                          )}
                          {i.status === "draft" && (
                            <DropdownMenuItem onClick={() => setStatus(i.id, "sent")}>Mark as Sent</DropdownMenuItem>
                          )}
                          {i.status === "sent" && (
                            <DropdownMenuItem onClick={() => setStatus(i.id, "overdue")}>Mark as Overdue</DropdownMenuItem>
                          )}
                          <DropdownMenuItem className="text-red-600" onClick={() => remove(i.id)}>
                            <Trash2 className="mr-2 h-4 w-4" /> Delete
                          </DropdownMenuItem>
                        </DropdownMenuContent>
                      </DropdownMenu>
                    </td>
                  </tr>
                ))}
                {!isLoading && filtered.length === 0 && (
                  <tr><td colSpan={7} className="p-0">
                    <EmptyState icon={FileText} title="No invoices yet" description="Create your first invoice to start tracking what customers owe you." />
                  </td></tr>
                )}
              </tbody>
            </table>
          </div>
        </CardContent>
      </Card>

      {/* Receive Payment dialog */}
      <Dialog open={!!payInv} onOpenChange={(o) => !o && setPayInv(null)}>
        <DialogContent className="max-w-lg">
          <DialogHeader>
            <DialogTitle>Receive payment {payInv ? `· Invoice ${payInv.number}` : ""}</DialogTitle>
          </DialogHeader>
          {payInv && (
            <div className="space-y-3">
              <div className="text-sm text-muted-foreground">
                Customer: <b>{payInv.customers?.name ?? "—"}</b> · Balance: <b>{money(payInv.balance, cur)}</b>
              </div>
              <div className="grid grid-cols-2 gap-3">
                <div>
                  <Label>Payment date</Label>
                  <Input type="date" value={payDate} onChange={(e) => setPayDate(e.target.value)} />
                </div>
                <div>
                  <Label>Amount received</Label>
                  <Input type="number" min={0} step="0.01" value={payAmount} onChange={(e) => setPayAmount(Number(e.target.value))} />
                </div>
                <div>
                  <Label>Payment method</Label>
                  <Select value={payMethod} onValueChange={(v) => setPayMethod(v as any)}>
                    <SelectTrigger><SelectValue /></SelectTrigger>
                    <SelectContent>
                      <SelectItem value="check">Check</SelectItem>
                      <SelectItem value="ach">ACH</SelectItem>
                      <SelectItem value="wire">Wire</SelectItem>
                      <SelectItem value="credit_card">Credit Card</SelectItem>
                      <SelectItem value="cash">Cash</SelectItem>
                      <SelectItem value="other">Other</SelectItem>
                    </SelectContent>
                  </Select>
                </div>
                <div>
                  <Label>Deposit to</Label>
                  <Select value={payAccountId} onValueChange={setPayAccountId}>
                    <SelectTrigger><SelectValue placeholder="Select account" /></SelectTrigger>
                    <SelectContent>
                      {(depositAccounts as any[]).map((a) => (
                        <SelectItem key={a.id} value={a.id}>
                          {a.code ? `${a.code} · ` : ""}{a.name}{a.is_system ? " (holding)" : ""}
                        </SelectItem>
                      ))}
                    </SelectContent>
                  </Select>
                </div>
                <div className="col-span-2">
                  <Label>{payMethod === "check" ? "Check number" : "Reference"}</Label>
                  <Input value={payReference} onChange={(e) => setPayReference(e.target.value)} maxLength={40} />
                </div>
                <div className="col-span-2">
                  <Label>Memo</Label>
                  <Textarea rows={2} value={payMemo} onChange={(e) => setPayMemo(e.target.value)} maxLength={200} />
                </div>
                {isPartial && (
                  <div className="col-span-2 rounded-md border border-amber-300 bg-amber-50 p-3 space-y-2">
                    <div className="text-sm text-amber-900">
                      Remaining balance: <b>{money(remainingAfter, cur)}</b>
                    </div>
                    <div className="flex gap-2">
                      <Button size="sm" variant={partialAction === "open" ? "default" : "outline"} onClick={() => setPartialAction("open")}>
                        Keep open
                      </Button>
                      <Button size="sm" variant={partialAction === "writeoff" ? "default" : "outline"} onClick={() => setPartialAction("writeoff")}>
                        Write off remainder
                      </Button>
                    </div>
                  </div>
                )}
              </div>
            </div>
          )}
          <DialogFooter>
            <Button variant="outline" onClick={() => setPayInv(null)}>Cancel</Button>
            <Button onClick={savePayment} disabled={paying}>{paying ? "Saving…" : "Receive payment"}</Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>
    </div>
  );
}
