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 { Textarea } from "@/components/ui/textarea";
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 { Plus, Search, Trash2, Receipt, Loader2 } from "lucide-react";
import { toast } from "sonner";
import { money, fmtDate } from "./lib/format";
import { EmptyState } from "./components/EmptyState";
import { ensureUndepositedFunds } from "./lib/undeposited";

const generateNumber = () => `SR-${Date.now().toString().slice(-6)}`;
const today = () => new Date().toLocaleDateString("en-CA", { timeZone: "America/New_York" });

export default function AccountingSalesReceiptsPage() {
  const { companyId, loading: companyLoading, error: companyError, associationId } = useCompanyId();
  const cid = companyId ?? "";
  const cur = "USD";
  const qc = useQueryClient();

  const [open, setOpen] = useState(false);
  const [search, setSearch] = useState("");
  const [saving, setSaving] = useState(false);

  // Form state
  const [number, setNumber] = useState(generateNumber());
  const [date, setDate] = useState(today());
  const [customerName, setCustomerName] = useState("");
  const [customerAddress, setCustomerAddress] = useState("");
  const [incomeAccountId, setIncomeAccountId] = useState("");
  const [depositAccountId, setDepositAccountId] = useState("");
  const [quantity, setQuantity] = useState(1);
  const [rate, setRate] = useState(0);
  const [memo, setMemo] = useState("");

  const total = useMemo(() => +(Number(quantity) * Number(rate)).toFixed(2), [quantity, rate]);

  const { data: receipts = [], isLoading } = useQuery({
    queryKey: ["sales-receipts", cid],
    enabled: !!cid,
    queryFn: async () => {
      const { data } = await accounting
        .from("sales_receipts")
        .select("*, income_account:accounts!sales_receipts_income_account_id_fkey(name,code), deposit_account:accounts!sales_receipts_deposit_account_id_fkey(name,code)")
        .eq("company_id", cid)
        .order("receipt_date", { ascending: false })
        .order("created_at", { ascending: false });
      return data ?? [];
    },
  });

  const { data: incomeAccounts = [] } = useQuery({
    queryKey: ["income-accounts", cid],
    enabled: !!cid,
    queryFn: async () =>
      (await accounting.from("accounts").select("id,name,code").eq("company_id", cid).eq("type", "income").eq("is_archived", false).order("code")).data ?? [],
  });

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

  const reset = () => {
    setNumber(generateNumber());
    setDate(today());
    setCustomerName("");
    setCustomerAddress("");
    setIncomeAccountId("");
    setDepositAccountId("");
    setQuantity(1);
    setRate(0);
    setMemo("");
  };

  const openDialog = async () => {
    reset();
    // Make sure there's somewhere to deposit to.
    await ensureUndepositedFunds(cid);
    qc.invalidateQueries({ queryKey: ["deposit-accounts", cid] });
    setOpen(true);
  };

  const save = async () => {
    if (!number.trim()) return toast.error("Receipt number is required");
    if (!incomeAccountId) return toast.error("Select an income account");
    if (!depositAccountId) return toast.error("Select a deposit account");
    if (total <= 0) return toast.error("Amount must be greater than 0");

    setSaving(true);
    try {
      const incomeName = (incomeAccounts as any[]).find((a) => a.id === incomeAccountId)?.name ?? "Sale";
      const desc = `Sales Receipt ${number}${customerName ? " · " + customerName : ""} · ${incomeName}`;

      // 1. Record the receipt document
      const { data: sr, error: srErr } = await accounting
        .from("sales_receipts")
        .insert({
          company_id: cid,
          number,
          receipt_date: date,
          customer_name: customerName || null,
          customer_address: customerAddress || null,
          income_account_id: incomeAccountId,
          deposit_account_id: depositAccountId,
          quantity,
          rate,
          total,
          memo: memo || null,
        })
        .select("id")
        .single();
      if (srErr || !sr) throw new Error(srErr?.message ?? "Failed to save sales receipt");

      // 2. Post the money in: debit deposit account, credit income account.
      //    The transaction triggers handle GL posting + account balances.
      const { data: txn, error: txnErr } = await accounting
        .from("transactions")
        .insert({
          company_id: cid,
          account_id: depositAccountId,
          coa_account_id: incomeAccountId,
          date,
          type: "credit",
          amount: total,
          description: desc,
          category: "Sales Receipt",
          reference: number,
        })
        .select("id")
        .single();
      if (txnErr || !txn) {
        // Roll back the orphaned document so we don't leave a receipt with no GL impact.
        await accounting.from("sales_receipts").delete().eq("id", sr.id);
        throw new Error(txnErr?.message ?? "Failed to post sales receipt");
      }

      await accounting.from("sales_receipts").update({ transaction_id: txn.id }).eq("id", sr.id);

      toast.success("Sales receipt recorded");
      setOpen(false);
      reset();
      qc.invalidateQueries({ queryKey: ["sales-receipts", cid] });
      qc.invalidateQueries({ queryKey: ["accounts", cid] });
      qc.invalidateQueries({ queryKey: ["transactions", cid] });
    } catch (e: any) {
      toast.error(e?.message ?? "Failed");
    } finally {
      setSaving(false);
    }
  };

  const remove = async (r: any) => {
    if (!confirm(`Delete sales receipt ${r.number}? This also reverses its accounting entry.`)) return;
    // Delete the transaction first so its GL + balances are reversed by triggers.
    if (r.transaction_id) {
      const { error } = await accounting.from("transactions").delete().eq("id", r.transaction_id);
      if (error) return toast.error(error.message);
    }
    const { error } = await accounting.from("sales_receipts").delete().eq("id", r.id);
    if (error) return toast.error(error.message);
    toast.success("Sales receipt deleted");
    qc.invalidateQueries({ queryKey: ["sales-receipts", cid] });
    qc.invalidateQueries({ queryKey: ["accounts", cid] });
    qc.invalidateQueries({ queryKey: ["transactions", cid] });
  };

  const filtered = useMemo(() => {
    const q = search.trim().toLowerCase();
    if (!q) return receipts as any[];
    return (receipts as any[]).filter((r) =>
      `${r.number} ${r.customer_name ?? ""} ${r.income_account?.name ?? ""}`.toLowerCase().includes(q)
    );
  }, [receipts, search]);

  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">Sales Receipts</h1>
          <p className="text-sm text-muted-foreground">{filtered.length} of {(receipts as any[]).length}</p>
        </div>
        <Dialog open={open} onOpenChange={(v) => { if (!v) { setOpen(false); reset(); } }}>
          <DialogTrigger asChild>
            <Button className="bg-emerald-600 hover:bg-emerald-700 text-white" onClick={openDialog}>
              <Plus className="mr-1 h-4 w-4" /> New Sales Receipt
            </Button>
          </DialogTrigger>
          <DialogContent className="max-w-2xl">
            <DialogHeader><DialogTitle>New Sales Receipt</DialogTitle></DialogHeader>
            <div className="space-y-4">
              <div className="grid grid-cols-2 gap-4">
                <div>
                  <Label>Name</Label>
                  <Input value={customerName} maxLength={160} placeholder="Customer name"
                    onChange={(e) => setCustomerName(e.target.value)} />
                </div>
                <div>
                  <Label>Receipt #</Label>
                  <Input value={number} onChange={(e) => setNumber(e.target.value)} />
                </div>
                <div className="col-span-2">
                  <Label>Address</Label>
                  <Textarea rows={2} maxLength={400} value={customerAddress} placeholder="Street, city, state, zip"
                    onChange={(e) => setCustomerAddress(e.target.value)} />
                </div>
                <div>
                  <Label>Date</Label>
                  <Input type="date" value={date} onChange={(e) => setDate(e.target.value)} />
                </div>
                <div>
                  <Label>Deposit to</Label>
                  <Select value={depositAccountId} onValueChange={setDepositAccountId}>
                    <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>Account</Label>
                  <Select value={incomeAccountId} onValueChange={setIncomeAccountId}>
                    <SelectTrigger><SelectValue placeholder="Select income account" /></SelectTrigger>
                    <SelectContent>
                      {(incomeAccounts as any[]).map((a) => (
                        <SelectItem key={a.id} value={a.id}>
                          {a.code ? `${a.code} · ` : ""}{a.name}
                        </SelectItem>
                      ))}
                    </SelectContent>
                  </Select>
                </div>
                <div>
                  <Label>Price</Label>
                  <Input type="number" min={0} step="0.01" value={rate}
                    onChange={(e) => setRate(Number(e.target.value))} />
                </div>
                <div>
                  <Label>Quantity</Label>
                  <Input type="number" min={0} step="0.01" value={quantity}
                    onChange={(e) => setQuantity(Number(e.target.value))} />
                </div>
                <div className="col-span-2">
                  <Label>Memo</Label>
                  <Textarea rows={2} maxLength={400} value={memo}
                    onChange={(e) => setMemo(e.target.value)} placeholder="Optional" />
                </div>
              </div>
              <div className="flex items-center justify-between rounded-lg border border-border bg-muted/30 px-4 py-3 text-base">
                <span className="font-semibold">Total</span>
                <span className="font-semibold tabular-nums">{money(total, cur)}</span>
              </div>
            </div>
            <DialogFooter>
              <Button variant="outline" onClick={() => { setOpen(false); reset(); }}>Cancel</Button>
              <Button onClick={save} disabled={saving}>{saving ? "Saving…" : "Save sales receipt"}</Button>
            </DialogFooter>
          </DialogContent>
        </Dialog>
      </div>

      <Card className="border-border/60 shadow-sm">
        <CardContent className="p-4">
          <div className="relative min-w-[220px] max-w-sm">
            <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 receipt #, name or account…" className="h-9 pl-9"
              value={search} onChange={(e) => setSearch(e.target.value)} />
          </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">Receipt #</th>
                  <th className="px-6 py-3 text-left font-medium">Date</th>
                  <th className="px-6 py-3 text-left font-medium">Name</th>
                  <th className="px-6 py-3 text-left font-medium">Account</th>
                  <th className="px-6 py-3 text-right font-medium">Qty</th>
                  <th className="px-6 py-3 text-right font-medium">Price</th>
                  <th className="px-6 py-3 text-right font-medium">Total</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: 8 }).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((r: any) => (
                  <tr key={r.id}>
                    <td className="px-6 py-3 font-medium">{r.number}</td>
                    <td className="px-6 py-3 text-muted-foreground">{fmtDate(r.receipt_date)}</td>
                    <td className="px-6 py-3">{r.customer_name ?? "—"}</td>
                    <td className="px-6 py-3">{r.income_account?.name ?? "—"}</td>
                    <td className="px-6 py-3 text-right tabular-nums">{Number(r.quantity)}</td>
                    <td className="px-6 py-3 text-right tabular-nums">{money(r.rate, cur)}</td>
                    <td className="px-6 py-3 text-right font-semibold tabular-nums">{money(r.total, cur)}</td>
                    <td className="px-2 py-3 text-right">
                      <Button variant="ghost" size="icon" className="h-8 w-8 text-destructive hover:text-destructive" onClick={() => remove(r)}>
                        <Trash2 className="h-4 w-4" />
                      </Button>
                    </td>
                  </tr>
                ))}
                {!isLoading && filtered.length === 0 && (
                  <tr><td colSpan={8} className="p-0">
                    <EmptyState icon={Receipt} title="No sales receipts yet" description="Record a cash sale — money is deposited and income is booked in one step." />
                  </td></tr>
                )}
              </tbody>
            </table>
          </div>
        </CardContent>
      </Card>
    </div>
  );
}
