import { useQuery, useQueryClient } from "@tanstack/react-query";
import { Fragment, useEffect, useMemo, useState } from "react";
import { format } from "date-fns";
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 { Badge } from "@/components/ui/badge";
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger, DialogFooter } from "@/components/ui/dialog";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { Table, TableHeader, TableRow, TableHead, TableBody, TableCell } from "@/components/ui/table";
import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs";
import { Calendar } from "@/components/ui/calendar";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import {
  AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent,
  AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger,
} from "@/components/ui/alert-dialog";
import { Plus, Trash2, CalendarIcon, Lock, Pencil, RotateCcw, Save, Info, Loader2 } from "lucide-react";
import { toast } from "sonner";
import { money } from "./lib/format";
import { cn } from "@/lib/utils";

const TYPES = [
  { value: "asset",     label: "Assets",      tone: "bg-emerald-100 text-emerald-700", side: "debit"  as const },
  { value: "liability", label: "Liabilities", tone: "bg-rose-100 text-rose-700",       side: "credit" as const },
  { value: "equity",    label: "Equity",       tone: "bg-violet-100 text-violet-700",  side: "credit" as const },
  { value: "income",    label: "Income",       tone: "bg-blue-100 text-blue-700",      side: "credit" as const },
  { value: "expense",   label: "Expenses",     tone: "bg-amber-100 text-amber-700",    side: "debit"  as const },
] as const;

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

  // ── Account form (shared create/edit) ──
  const [open, setOpen] = useState(false);
  const [editId, setEditId] = useState<string | null>(null);
  const [name, setName] = useState("");
  const [code, setCode] = useState("");
  const [type, setType] = useState<string>("asset");
  const [isBank, setIsBank] = useState(false);
  const [isReserve, setIsReserve] = useState(false);
  const [description, setDescription] = useState("");
  const [parentId, setParentId] = useState<string>("");

  // ── Opening balances state ──
  const [obRows, setObRows] = useState<Record<string, { debit: string; credit: string }>>({});
  const [asOfDate, setAsOfDate] = useState<Date>(new Date());
  const [dateLocked, setDateLocked] = useState(false);

  // ── Queries ──
  const { data: accounts = [] } = useQuery({
    queryKey: ["accounts", cid],
    enabled: !!cid,
    queryFn: async () =>
      (await accounting.from("accounts").select("*").eq("company_id", cid).order("code", { ascending: true })).data ?? [],
  });

  const { data: obSetup } = useQuery({
    queryKey: ["ob-setup", cid],
    enabled: !!cid,
    queryFn: async () =>
      (await accounting.from("opening_balances_setup").select("*").eq("company_id", cid).maybeSingle()).data,
  });

  const { data: balances = [] } = useQuery({
    queryKey: ["ob", cid],
    enabled: !!cid,
    queryFn: async () =>
      (await accounting.from("opening_balances").select("*").eq("company_id", cid)).data ?? [],
  });

  useEffect(() => {
    if (obSetup) {
      setAsOfDate(new Date(obSetup.as_of_date));
      setDateLocked(obSetup.confirmed);
    }
  }, [obSetup]);

  useEffect(() => {
    const map: Record<string, { debit: string; credit: string }> = {};
    for (const b of balances as any[]) {
      map[b.account_id] = {
        debit: Number(b.debit) ? String(b.debit) : "",
        credit: Number(b.credit) ? String(b.credit) : "",
      };
    }
    setObRows(map);
  }, [balances]);

  const grouped = useMemo(() => {
    const out: Record<string, any[]> = {};
    for (const t of TYPES) out[t.value] = [];
    for (const a of accounts as any[]) (out[a.type] ??= []).push(a);
    return out;
  }, [accounts]);

  // ── Accounts actions ──
  const resetForm = () => {
    setEditId(null); setName(""); setCode(""); setType("asset");
    setIsBank(false); setIsReserve(false); setDescription(""); setParentId("");
  };

  const openEdit = (a: any) => {
    setEditId(a.id);
    setName(a.name ?? "");
    setCode(a.code ?? "");
    setType(a.type ?? "asset");
    setIsBank(a.is_bank ?? false);
    setIsReserve(a.is_reserve ?? false);
    setDescription(a.description ?? "");
    setParentId(a.parent_account_id ?? "");
    setOpen(true);
  };

  const saveAccount = async () => {
    if (!name.trim()) return toast.error("Name is required");
    const payload: any = {
      name: name.trim(),
      code: code.trim() || null,
      type: type as any,
      is_bank: isBank,
      is_reserve: isReserve,
      description: description || null,
      parent_account_id: parentId || null,
    };
    if (editId) {
      // Can't set self as parent
      if (parentId === editId) return toast.error("An account cannot be its own parent");
      const { error } = await accounting.from("accounts").update(payload).eq("id", editId);
      if (error) return toast.error(error.message);
      toast.success("Account updated");
    } else {
      const { error } = await accounting.from("accounts").insert({ ...payload, company_id: cid });
      if (error) return toast.error(error.message);
      toast.success("Account created");
    }
    setOpen(false); resetForm();
    qc.invalidateQueries({ queryKey: ["accounts", cid] });
  };

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

  // ── Opening balances actions ──
  const updateOb = (id: string, side: "debit" | "credit", v: string) => {
    setObRows((r) => ({ ...r, [id]: { debit: side === "debit" ? v : "", credit: side === "credit" ? v : "" } }));
  };

  const totalDebit = useMemo(() => Object.values(obRows).reduce((s, r) => s + (parseFloat(r.debit) || 0), 0), [obRows]);
  const totalCredit = useMemo(() => Object.values(obRows).reduce((s, r) => s + (parseFloat(r.credit) || 0), 0), [obRows]);
  const diff = totalDebit - totalCredit;
  const balanced = Math.abs(diff) < 0.005;

  const saveOb = async () => {
    if (!balanced) return toast.error("Debits and Credits must match");
    const { error: e1 } = await accounting.from("opening_balances_setup").upsert(
      { company_id: cid, as_of_date: format(asOfDate, "yyyy-MM-dd"), confirmed: true },
      { onConflict: "company_id" }
    );
    if (e1) return toast.error(e1.message);

    const rowsPayload = (accounts as any[])
      .map((a) => {
        const r = obRows[a.id];
        const d = parseFloat(r?.debit || "0") || 0;
        const c = parseFloat(r?.credit || "0") || 0;
        return { company_id: cid, account_id: a.id, debit: d, credit: c };
      })
      .filter((r) => r.debit !== 0 || r.credit !== 0);

    await accounting.from("opening_balances").delete().eq("company_id", cid);
    if (rowsPayload.length) {
      const { error: e2 } = await accounting.from("opening_balances").insert(rowsPayload);
      if (e2) return toast.error(e2.message);
    }

    // For every bank account with an opening balance, create (or replace) an
    // "Opening Balance" transaction so the bank register shows the correct starting balance.
    // Our trigger: balance = SUM(credit txns) - SUM(debit txns)
    // → asset account with debit OB → needs a "credit" transaction to produce a positive balance
    // → asset account with credit OB → needs a "debit" transaction (overdraft / unusual)
    const asOfStr = format(asOfDate, "yyyy-MM-dd");
    const bankAccountIds = (accounts as any[])
      .filter((a) => a.is_bank)
      .map((a) => a.id);

    if (bankAccountIds.length) {
      // Clear previous opening balance transactions for all bank accounts
      await accounting
        .from("transactions")
        .delete()
        .eq("company_id", cid)
        .eq("category", "Opening Balance")
        .in("account_id", bankAccountIds);

      // Insert new opening balance transactions
      const txRows = rowsPayload
        .filter((r) => bankAccountIds.includes(r.account_id) && (r.debit > 0 || r.credit > 0))
        .map((r) => {
          const amount = r.debit > 0 ? r.debit : r.credit;
          // Debit OB (normal positive balance) → credit tx adds to balance
          // Credit OB (unusual / overdraft) → debit tx subtracts from balance
          const type: "credit" | "debit" = r.debit > 0 ? "credit" : "debit";
          return {
            company_id: cid,
            account_id: r.account_id,
            date: asOfStr,
            description: "Opening Balance",
            amount,
            type,
            category: "Opening Balance",
          };
        });

      if (txRows.length) {
        const { error: e3 } = await accounting.from("transactions").insert(txRows);
        if (e3) toast.error(`Warning: opening balance transactions failed — ${e3.message}`);
      }
    }

    toast.success("Opening balances saved");
    setDateLocked(true);
    qc.invalidateQueries({ queryKey: ["ob-setup", cid] });
    qc.invalidateQueries({ queryKey: ["ob", cid] });
    qc.invalidateQueries({ queryKey: ["transactions", cid] });
    qc.invalidateQueries({ queryKey: ["accounts", cid] });
  };

  const resetOb = () => {
    setObRows({});
    toast.info("All balances cleared. Click Save to persist.");
  };

  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 items-center justify-between">
        <div>
          <h1 className="text-2xl font-semibold">Chart of Accounts</h1>
          <p className="text-sm text-muted-foreground">{(accounts as any[]).length} accounts across {TYPES.length} categories</p>
        </div>
        <Dialog open={open} onOpenChange={(v) => { setOpen(v); if (!v) resetForm(); }}>
          <DialogTrigger asChild>
            <Button onClick={resetForm}><Plus className="mr-1 h-4 w-4" /> New Account</Button>
          </DialogTrigger>
          <DialogContent className="max-w-lg">
            <DialogHeader><DialogTitle>{editId ? "Edit account" : "New account"}</DialogTitle></DialogHeader>
            <div className="space-y-4">
              <div><Label>Account name *</Label><Input maxLength={120} value={name} onChange={(e) => setName(e.target.value)} /></div>
              <div className="grid grid-cols-2 gap-3">
                <div><Label>Account code</Label><Input maxLength={20} placeholder="e.g. 1100" value={code} onChange={(e) => setCode(e.target.value)} /></div>
                <div>
                  <Label>Type</Label>
                  <Select value={type} onValueChange={(v) => { setType(v); setParentId(""); }}>
                    <SelectTrigger><SelectValue /></SelectTrigger>
                    <SelectContent>{TYPES.map((t) => <SelectItem key={t.value} value={t.value}>{t.label}</SelectItem>)}</SelectContent>
                  </Select>
                </div>
              </div>
              <div>
                <Label>Parent account <span className="text-muted-foreground text-xs font-normal">(makes this a sub-account)</span></Label>
                <Select
                  value={parentId || "__none__"}
                  onValueChange={(v) => setParentId(v === "__none__" ? "" : v)}
                >
                  <SelectTrigger><SelectValue placeholder="None — top-level account" /></SelectTrigger>
                  <SelectContent>
                    <SelectItem value="__none__">None (top-level)</SelectItem>
                    {(accounts as any[])
                      .filter((a: any) => a.id !== editId && a.type === type)
                      .map((a: any) => (
                        <SelectItem key={a.id} value={a.id}>
                          {a.code ? `${a.code} · ` : ""}{a.name}
                        </SelectItem>
                      ))}
                  </SelectContent>
                </Select>
              </div>
              <div><Label>Description</Label><Textarea maxLength={500} value={description} onChange={(e) => setDescription(e.target.value)} placeholder="Optional notes about this account" /></div>
              <label className="flex items-center gap-2 text-sm">
                <input type="checkbox" checked={isBank} onChange={(e) => setIsBank(e.target.checked)} />
                This is a bank, cash, or card account
              </label>
              <label className="flex items-center gap-2 text-sm">
                <input type="checkbox" checked={isReserve} onChange={(e) => setIsReserve(e.target.checked)} />
                Reserve fund account (appears on the Reserve Fund Schedule)
              </label>
            </div>
            <DialogFooter>
              <Button variant="outline" onClick={() => { setOpen(false); resetForm(); }}>Cancel</Button>
              <Button onClick={saveAccount}>{editId ? "Save changes" : "Create account"}</Button>
            </DialogFooter>
          </DialogContent>
        </Dialog>
      </div>

      <Tabs defaultValue="accounts">
        <TabsList>
          <TabsTrigger value="accounts">Accounts</TabsTrigger>
          <TabsTrigger value="opening-balances">Opening Balances</TabsTrigger>
        </TabsList>

        {/* ── Accounts tab ── */}
        <TabsContent value="accounts" className="mt-4 space-y-4">
          {TYPES.map((t) => {
            const rows = grouped[t.value] ?? [];
            const subtotal = rows.reduce((s: number, a: any) => s + Number(a.balance), 0);
            return (
              <Card key={t.value}>
                <div className="flex items-center justify-between border-b px-6 py-3">
                  <div className="flex items-center gap-3">
                    <Badge className={`${t.tone} border-0`}>{t.label}</Badge>
                    <span className="text-sm text-muted-foreground">{rows.length} {rows.length === 1 ? "account" : "accounts"}</span>
                  </div>
                  <div className="text-sm font-semibold">{money(subtotal, cur)}</div>
                </div>
                <CardContent className="p-0">
                  <Table>
                    <TableHeader>
                      <TableRow>
                        <TableHead className="w-28">Code</TableHead>
                        <TableHead>Account name</TableHead>
                        <TableHead>Parent</TableHead>
                        <TableHead className="text-right">Balance</TableHead>
                        <TableHead className="w-20"></TableHead>
                      </TableRow>
                    </TableHeader>
                    <TableBody>
                      {rows.map((a: any) => {
                        const parent = (accounts as any[]).find((p) => p.id === a.parent_account_id);
                        const isChild = !!a.parent_account_id;
                        return (
                        <TableRow key={a.id} className={isChild ? "bg-muted/20" : ""}>
                          <TableCell className={`font-mono text-xs text-muted-foreground ${isChild ? "pl-8" : ""}`}>{a.code ?? "—"}</TableCell>
                          <TableCell className={isChild ? "pl-8" : ""}>
                            <div className={`font-medium ${isChild ? "text-sm" : ""}`}>
                              {isChild && <span className="mr-1 text-muted-foreground">↳</span>}{a.name}
                            </div>
                            {a.description && <div className="text-xs text-muted-foreground">{a.description}</div>}
                            {a.is_bank && <div className="text-xs text-muted-foreground">Bank account</div>}
                            {a.is_reserve && <div className="text-xs text-emerald-600 font-medium">Reserve fund</div>}
                          </TableCell>
                          <TableCell className="text-xs text-muted-foreground">
                            {parent ? (
                              <span className="rounded bg-muted px-1.5 py-0.5">{parent.code ? `${parent.code} · ` : ""}{parent.name}</span>
                            ) : "—"}
                          </TableCell>
                          <TableCell className="text-right font-medium">{money(a.balance, cur)}</TableCell>
                          <TableCell>
                            <div className="flex justify-end gap-1">
                              <Button size="icon" variant="ghost" className="h-7 w-7" onClick={() => { openEdit(a); }}>
                                <Pencil className="h-3.5 w-3.5" />
                              </Button>
                              <Button size="icon" variant="ghost" className="h-7 w-7 text-destructive hover:text-destructive" onClick={() => removeAccount(a.id)}>
                                <Trash2 className="h-3.5 w-3.5" />
                              </Button>
                            </div>
                          </TableCell>
                        </TableRow>
                        );
                      })}
                      {rows.length === 0 && (
                        <TableRow>
                          <TableCell colSpan={5} className="text-center text-sm text-muted-foreground py-6">
                            No accounts in this category yet.
                          </TableCell>
                        </TableRow>
                      )}
                    </TableBody>
                  </Table>
                </CardContent>
              </Card>
            );
          })}
        </TabsContent>

        {/* ── Opening Balances tab ── */}
        <TabsContent value="opening-balances" className="mt-4 space-y-4">
          <div className="flex flex-wrap items-end justify-between gap-3">
            <div className="flex items-center gap-2">
              <div className="flex flex-col gap-1">
                <span className="text-xs text-muted-foreground">As of date</span>
                <div className="flex items-center gap-1">
                  <Popover>
                    <PopoverTrigger asChild>
                      <Button variant="outline" disabled={dateLocked} className={cn("w-[200px] justify-start text-left font-normal", dateLocked && "opacity-100")}>
                        <CalendarIcon className="mr-2 h-4 w-4" />
                        {format(asOfDate, "PPP")}
                        {dateLocked && <Lock className="ml-auto h-3.5 w-3.5 text-muted-foreground" />}
                      </Button>
                    </PopoverTrigger>
                    <PopoverContent className="w-auto p-0" align="start">
                      <Calendar mode="single" selected={asOfDate} onSelect={(d) => d && setAsOfDate(d)} initialFocus className="p-3 pointer-events-auto" />
                    </PopoverContent>
                  </Popover>
                  {dateLocked && (
                    <Button variant="ghost" size="icon" onClick={() => setDateLocked(false)} title="Edit date">
                      <Pencil className="h-4 w-4" />
                    </Button>
                  )}
                </div>
              </div>
            </div>
            <div className="flex items-center gap-2">
              {balanced ? (
                <Badge className="bg-emerald-100 text-emerald-700 border-0">Balanced</Badge>
              ) : (
                <Badge className="bg-red-100 text-red-700 border-0">Out of balance by {money(Math.abs(diff), cur)}</Badge>
              )}
              {obSetup?.confirmed && <Badge variant="outline">Last saved {format(new Date(obSetup.updated_at), "PP")}</Badge>}
            </div>
          </div>

          <div className="flex items-start gap-3 rounded-md border border-primary/20 bg-primary/5 px-4 py-3 text-sm">
            <Info className="h-4 w-4 mt-0.5 text-primary shrink-0" />
            <p>Enter starting balances from your previous accounting system. <strong>Debits must equal Credits to save.</strong> Leave zero-balance accounts blank.</p>
          </div>

          <Card>
            <CardContent className="p-0">
              <Table>
                <TableHeader>
                  <TableRow>
                    <TableHead className="w-28">Code</TableHead>
                    <TableHead>Account name</TableHead>
                    <TableHead className="w-32">Type</TableHead>
                    <TableHead className="text-right w-44">Debit</TableHead>
                    <TableHead className="text-right w-44">Credit</TableHead>
                  </TableRow>
                </TableHeader>
                <TableBody>
                  {TYPES.map((t) => {
                    const rs = grouped[t.value] ?? [];
                    if (!rs.length) return null;
                    return (
                      <Fragment key={t.value}>
                        <TableRow className="bg-muted/40 hover:bg-muted/40">
                          <TableCell colSpan={5} className="font-semibold text-xs uppercase tracking-wide text-muted-foreground py-2">
                            {t.label}
                          </TableCell>
                        </TableRow>
                        {rs.map((a: any) => {
                          const r = obRows[a.id] ?? { debit: "", credit: "" };
                          const isDebit = t.side === "debit";
                          return (
                            <TableRow key={a.id}>
                              <TableCell className="font-mono text-xs text-muted-foreground">{a.code ?? "—"}</TableCell>
                              <TableCell className="font-medium">{a.name}</TableCell>
                              <TableCell className="capitalize text-sm text-muted-foreground">{a.type}</TableCell>
                              <TableCell className="text-right">
                                {isDebit ? (
                                  <Input type="number" step="0.01" inputMode="decimal" value={r.debit}
                                    onChange={(e) => updateOb(a.id, "debit", e.target.value)}
                                    placeholder="0.00" className="text-right ml-auto max-w-[160px]" />
                                ) : <span className="text-muted-foreground">—</span>}
                              </TableCell>
                              <TableCell className="text-right">
                                {!isDebit ? (
                                  <Input type="number" step="0.01" inputMode="decimal" value={r.credit}
                                    onChange={(e) => updateOb(a.id, "credit", e.target.value)}
                                    placeholder="0.00" className="text-right ml-auto max-w-[160px]" />
                                ) : <span className="text-muted-foreground">—</span>}
                              </TableCell>
                            </TableRow>
                          );
                        })}
                      </Fragment>
                    );
                  })}
                  {(accounts as any[]).length === 0 && (
                    <TableRow>
                      <TableCell colSpan={5} className="text-center text-sm text-muted-foreground py-8">
                        No accounts yet. Create some in the Accounts tab first.
                      </TableCell>
                    </TableRow>
                  )}
                </TableBody>
              </Table>
              <div className="border-t bg-muted/30 px-4 py-3">
                <div className="grid grid-cols-[1fr_auto_auto_auto] items-center gap-6 text-sm">
                  <div className="font-semibold">Totals</div>
                  <div className="text-right"><span className="text-muted-foreground mr-2">Debits</span><span className="font-semibold tabular-nums">{money(totalDebit, cur)}</span></div>
                  <div className="text-right"><span className="text-muted-foreground mr-2">Credits</span><span className="font-semibold tabular-nums">{money(totalCredit, cur)}</span></div>
                  <div className="text-right">
                    <span className="text-muted-foreground mr-2">Difference</span>
                    <span className={cn("font-semibold tabular-nums", balanced ? "text-emerald-600" : "text-red-600")}>
                      {money(diff, cur)}
                    </span>
                  </div>
                </div>
              </div>
            </CardContent>
          </Card>

          <div className="flex justify-end gap-2">
            <AlertDialog>
              <AlertDialogTrigger asChild>
                <Button variant="outline"><RotateCcw className="mr-2 h-4 w-4" /> Reset All</Button>
              </AlertDialogTrigger>
              <AlertDialogContent>
                <AlertDialogHeader>
                  <AlertDialogTitle>Reset all opening balances?</AlertDialogTitle>
                  <AlertDialogDescription>This clears every entered debit and credit. Saved balances remain until you click Save.</AlertDialogDescription>
                </AlertDialogHeader>
                <AlertDialogFooter>
                  <AlertDialogCancel>Cancel</AlertDialogCancel>
                  <AlertDialogAction onClick={resetOb}>Reset</AlertDialogAction>
                </AlertDialogFooter>
              </AlertDialogContent>
            </AlertDialog>
            <Button onClick={saveOb} disabled={!balanced || (accounts as any[]).length === 0}>
              <Save className="mr-2 h-4 w-4" /> Save Opening Balances
            </Button>
          </div>
        </TabsContent>
      </Tabs>
    </div>
  );
}
