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, 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 { Sheet, SheetContent, SheetHeader, SheetTitle } from "@/components/ui/sheet";
import { Plus, Trash2, ChevronRight, AlertCircle, Loader2 } from "lucide-react";
import { toast } from "sonner";
import { money, fmtDate } from "./lib/format";

// Lines use a single signed amount: + = debit, − = credit
type JELine = { id: string; account_id: string; amount: string; description: string };

const newLine = (): JELine => ({
  id: crypto.randomUUID(),
  account_id: "",
  amount: "",
  description: "",
});

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

  const [open, setOpen] = useState(false);
  const [detailId, setDetailId] = useState<string | null>(null);
  const [date, setDate] = useState(new Date().toLocaleDateString("en-CA", { timeZone: "America/New_York" }));
  const [description, setDescription] = useState("");
  const [reference, setReference] = useState("");
  const [lines, setLines] = useState<JELine[]>([newLine(), newLine()]);
  const [saving, setSaving] = useState(false);

  const { data: entries = [] } = useQuery({
    queryKey: ["journal-entries", cid],
    enabled: !!cid,
    queryFn: async () =>
      (
        await accounting
          .from("journal_entries")
          .select("*, journal_entry_lines(*, accounts(name, code))")
          .eq("company_id", cid)
          .order("date", { ascending: false })
          .order("created_at", { ascending: false })
      ).data ?? [],
  });

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

  const detailEntry = useMemo(
    () => (detailId ? (entries as any[]).find((e) => e.id === detailId) : null),
    [entries, detailId]
  );

  // + amounts are debits, − amounts are credits
  const totalDebits = useMemo(
    () => lines.reduce((s, l) => { const a = Number(l.amount) || 0; return s + (a > 0 ? a : 0); }, 0),
    [lines]
  );
  const totalCredits = useMemo(
    () => lines.reduce((s, l) => { const a = Number(l.amount) || 0; return s + (a < 0 ? -a : 0); }, 0),
    [lines]
  );
  const signedTotal = totalDebits - totalCredits;
  const isBalanced = Math.abs(signedTotal) < 0.005;

  const setLine = (id: string, patch: Partial<JELine>) => {
    setLines((prev) => prev.map((l) => (l.id === id ? { ...l, ...patch } : l)));
  };

  const addLine = () => setLines((prev) => [...prev, newLine()]);
  const removeLine = (id: string) => {
    if (lines.length <= 2) return toast.error("Journal entries need at least 2 lines");
    setLines((prev) => prev.filter((l) => l.id !== id));
  };

  const resetForm = () => {
    setDate(new Date().toLocaleDateString("en-CA", { timeZone: "America/New_York" }));
    setDescription("");
    setReference("");
    setLines([newLine(), newLine()]);
  };

  const saveEntry = async () => {
    if (!description.trim()) return toast.error("Description required");
    const activeLines = lines.filter((l) => l.amount.trim() !== "" && (Number(l.amount) || 0) !== 0);
    if (activeLines.length < 2) return toast.error("Add at least two lines with an amount");
    if (activeLines.some((l) => !l.account_id)) return toast.error("All lines need an account");
    if (!isBalanced) return toast.error(`Entry is out of balance by ${money(Math.abs(signedTotal), cur)} — debits (+) must equal credits (−)`);
    if (totalDebits === 0) return toast.error("Entry amount can't be zero");

    setSaving(true);
    const { data: je, error: jeErr } = await accounting
      .from("journal_entries")
      .insert({ company_id: cid, date, description, reference: reference || null })
      .select("id")
      .single();
    if (jeErr || !je) { setSaving(false); return toast.error(jeErr?.message ?? "Failed to create entry"); }

    const lineRows = activeLines.map((l) => {
      const a = Number(l.amount) || 0;
      return {
        journal_entry_id: je.id,
        account_id: l.account_id,
        debit: a > 0 ? a : 0,
        credit: a < 0 ? -a : 0,
        description: l.description || null,
      };
    });

    const { error: linesErr } = await accounting.from("journal_entry_lines").insert(lineRows);
    setSaving(false);
    if (linesErr) return toast.error(linesErr.message);

    toast.success("Journal entry posted");
    setOpen(false);
    resetForm();
    qc.invalidateQueries({ queryKey: ["journal-entries", cid] });
  };

  const deleteEntry = async (id: string) => {
    if (!confirm("Delete this journal entry and all its lines?")) return;
    const { error } = await accounting.from("journal_entries").delete().eq("id", id);
    if (error) return toast.error(error.message);
    toast.success("Journal entry deleted");
    if (detailId === id) setDetailId(null);
    qc.invalidateQueries({ queryKey: ["journal-entries", cid] });
  };

  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">Journal Entries</h1>
          <p className="text-sm text-muted-foreground mt-0.5">Manual double-entry journal entries</p>
        </div>
        <Button onClick={() => { resetForm(); setOpen(true); }}>
          <Plus className="h-4 w-4 mr-1" /> New entry
        </Button>
      </div>

      <Card>
        <CardContent className="p-0">
          <Table>
            <TableHeader>
              <TableRow>
                <TableHead className="w-[110px]">Date</TableHead>
                <TableHead>Description</TableHead>
                <TableHead className="w-[100px]">Ref #</TableHead>
                <TableHead className="text-right w-[110px]">Debits</TableHead>
                <TableHead className="text-right w-[110px]">Credits</TableHead>
                <TableHead className="w-[80px]"></TableHead>
              </TableRow>
            </TableHeader>
            <TableBody>
              {(entries as any[]).map((e) => {
                const debits = (e.journal_entry_lines ?? []).reduce((s: number, l: any) => s + Number(l.debit), 0);
                const credits = (e.journal_entry_lines ?? []).reduce((s: number, l: any) => s + Number(l.credit), 0);
                return (
                  <TableRow
                    key={e.id}
                    className="cursor-pointer hover:bg-muted/50"
                    onClick={() => setDetailId(e.id)}
                  >
                    <TableCell className="text-sm">{fmtDate(e.date)}</TableCell>
                    <TableCell className="text-sm font-medium">
                      {e.description}
                      <span className="ml-2 text-xs text-muted-foreground">
                        {(e.journal_entry_lines ?? []).length} lines
                      </span>
                    </TableCell>
                    <TableCell className="text-sm text-muted-foreground">{e.reference ?? "—"}</TableCell>
                    <TableCell className="text-right text-sm">{money(debits, cur)}</TableCell>
                    <TableCell className="text-right text-sm">{money(credits, cur)}</TableCell>
                    <TableCell>
                      <div className="flex justify-end gap-1">
                        <Button size="icon" variant="ghost" className="h-7 w-7" onClick={(ev) => { ev.stopPropagation(); setDetailId(e.id); }}>
                          <ChevronRight className="h-4 w-4" />
                        </Button>
                        <Button size="icon" variant="ghost" className="h-7 w-7 text-destructive hover:text-destructive" onClick={(ev) => { ev.stopPropagation(); deleteEntry(e.id); }}>
                          <Trash2 className="h-3.5 w-3.5" />
                        </Button>
                      </div>
                    </TableCell>
                  </TableRow>
                );
              })}
              {entries.length === 0 && (
                <TableRow>
                  <TableCell colSpan={6} className="text-center text-muted-foreground py-10">
                    No journal entries yet.
                  </TableCell>
                </TableRow>
              )}
            </TableBody>
          </Table>
        </CardContent>
      </Card>

      {/* New journal entry dialog */}
      <Dialog open={open} onOpenChange={(o) => { setOpen(o); if (!o) resetForm(); }}>
        <DialogContent className="max-w-3xl max-h-[90vh] overflow-y-auto">
          <DialogHeader><DialogTitle>New journal entry</DialogTitle></DialogHeader>

          <div className="grid grid-cols-3 gap-3">
            <div className="col-span-2">
              <Label>Description *</Label>
              <Input value={description} onChange={(e) => setDescription(e.target.value)} placeholder="e.g. Accrued interest" />
            </div>
            <div>
              <Label>Date *</Label>
              <Input type="date" value={date} onChange={(e) => setDate(e.target.value)} />
            </div>
            <div>
              <Label>Reference #</Label>
              <Input value={reference} onChange={(e) => setReference(e.target.value)} placeholder="Optional" />
            </div>
          </div>

          <div className="mt-2">
            <div className="grid grid-cols-[1fr_160px_140px_32px] gap-2 text-xs font-medium text-muted-foreground px-1 pb-1">
              <span>Account</span>
              <span>Line description</span>
              <span className="text-right">Amount (+ debit / − credit)</span>
              <span></span>
            </div>
            <div className="space-y-2">
              {lines.map((line) => {
                const a = Number(line.amount) || 0;
                return (
                <div key={line.id} className="grid grid-cols-[1fr_160px_140px_32px] gap-2 items-center">
                  <Select value={line.account_id} onValueChange={(v) => setLine(line.id, { account_id: v })}>
                    <SelectTrigger className="h-8 text-sm"><SelectValue placeholder="Select account" /></SelectTrigger>
                    <SelectContent>
                      {(accounts as any[]).map((a) => (
                        <SelectItem key={a.id} value={a.id}>
                          {a.code ? `${a.code} · ` : ""}{a.name}
                        </SelectItem>
                      ))}
                    </SelectContent>
                  </Select>
                  <Input
                    className="h-8 text-sm"
                    placeholder="Optional"
                    value={line.description}
                    onChange={(e) => setLine(line.id, { description: e.target.value })}
                  />
                  <Input
                    className={`h-8 text-sm text-right tabular-nums ${a < 0 ? "text-red-600" : ""}`}
                    type="number"
                    step="0.01"
                    placeholder="0.00"
                    value={line.amount}
                    onChange={(e) => setLine(line.id, { amount: e.target.value })}
                  />
                  <Button size="icon" variant="ghost" className="h-7 w-7 text-muted-foreground" onClick={() => removeLine(line.id)}>
                    <Trash2 className="h-3.5 w-3.5" />
                  </Button>
                </div>
                );
              })}
            </div>

            <Button variant="outline" size="sm" className="mt-3" onClick={addLine}>
              <Plus className="h-3.5 w-3.5 mr-1" /> Add line
            </Button>

            {/* Totals row */}
            <div className="mt-3 grid grid-cols-[1fr_160px_140px_32px] gap-2 border-t pt-3">
              <div className="col-span-2 text-xs font-medium text-right text-muted-foreground self-center">
                Debits {money(totalDebits, cur)} · Credits {money(totalCredits, cur)}
              </div>
              <div className={`text-sm font-semibold text-right tabular-nums ${signedTotal !== 0 ? "text-destructive" : "text-emerald-700"}`}>
                {money(signedTotal, cur)}
              </div>
              <div />
            </div>

            {!isBalanced && totalDebits + totalCredits > 0 && (
              <div className="mt-2 flex items-center gap-2 rounded-md bg-destructive/10 px-3 py-2 text-sm text-destructive">
                <AlertCircle className="h-4 w-4 shrink-0" />
                Out of balance by {money(Math.abs(signedTotal), cur)} — debits (+) must equal credits (−)
              </div>
            )}
            {isBalanced && totalDebits > 0 && (
              <div className="mt-2 flex items-center gap-2 rounded-md bg-emerald-50 px-3 py-2 text-sm text-emerald-700">
                Entry is balanced
              </div>
            )}
          </div>

          <DialogFooter>
            <Button variant="outline" onClick={() => { setOpen(false); resetForm(); }}>Cancel</Button>
            <Button onClick={saveEntry} disabled={saving || !isBalanced || totalDebits === 0}>
              {saving ? "Posting…" : "Post entry"}
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      {/* Detail drawer */}
      <Sheet open={!!detailEntry} onOpenChange={(o) => !o && setDetailId(null)}>
        <SheetContent className="min-w-[480px] overflow-y-auto">
          <SheetHeader>
            <SheetTitle>Journal Entry</SheetTitle>
          </SheetHeader>
          {detailEntry && (
            <div className="mt-4 space-y-4 text-sm">
              <div className="grid grid-cols-2 gap-3">
                <div><div className="text-muted-foreground text-xs">Date</div><div>{fmtDate(detailEntry.date)}</div></div>
                <div><div className="text-muted-foreground text-xs">Reference</div><div>{detailEntry.reference ?? "—"}</div></div>
                <div className="col-span-2"><div className="text-muted-foreground text-xs">Description</div><div className="font-medium">{detailEntry.description}</div></div>
              </div>

              <Table>
                <TableHeader>
                  <TableRow>
                    <TableHead>Account</TableHead>
                    <TableHead>Description</TableHead>
                    <TableHead className="text-right">Debit</TableHead>
                    <TableHead className="text-right">Credit</TableHead>
                  </TableRow>
                </TableHeader>
                <TableBody>
                  {(detailEntry.journal_entry_lines ?? []).map((line: any) => (
                    <TableRow key={line.id}>
                      <TableCell className="text-sm">
                        {line.accounts?.code ? `${line.accounts.code} · ` : ""}{line.accounts?.name ?? "—"}
                      </TableCell>
                      <TableCell className="text-sm text-muted-foreground">{line.description ?? "—"}</TableCell>
                      <TableCell className="text-right text-sm">{line.debit > 0 ? money(line.debit, cur) : ""}</TableCell>
                      <TableCell className="text-right text-sm">{line.credit > 0 ? money(line.credit, cur) : ""}</TableCell>
                    </TableRow>
                  ))}
                  <TableRow className="bg-muted font-semibold">
                    <TableCell colSpan={2}>Total</TableCell>
                    <TableCell className="text-right text-sm">
                      {money((detailEntry.journal_entry_lines ?? []).reduce((s: number, l: any) => s + Number(l.debit), 0), cur)}
                    </TableCell>
                    <TableCell className="text-right text-sm">
                      {money((detailEntry.journal_entry_lines ?? []).reduce((s: number, l: any) => s + Number(l.credit), 0), cur)}
                    </TableCell>
                  </TableRow>
                </TableBody>
              </Table>

              <div className="pt-2">
                <Button variant="destructive" size="sm" onClick={() => deleteEntry(detailEntry.id)}>
                  <Trash2 className="h-3.5 w-3.5 mr-1" /> Delete entry
                </Button>
              </div>
            </div>
          )}
        </SheetContent>
      </Sheet>
    </div>
  );
}
