import { useMemo, useState } from "react";
import { useQuery, useQueryClient } from "@tanstack/react-query";
import { accounting } from "@/lib/accountingClient";
import { supabase } from "@/integrations/supabase/client";
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 { Badge } from "@/components/ui/badge";
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 { Plus, Trash2, Pencil, Loader2, Play, Pause, RefreshCw } from "lucide-react";
import { toast } from "sonner";
import { money, fmtDate } from "./lib/format";

type Kind = "bill" | "journal";
type Freq = "weekly" | "monthly" | "quarterly" | "yearly";
type Item = { description: string; quantity: number; rate: number; account_id: string | null };
type Line = { account_id: string; amount: string; description: string };

const FREQS: { value: Freq; label: string }[] = [
  { value: "weekly", label: "Weekly" },
  { value: "monthly", label: "Monthly" },
  { value: "quarterly", label: "Quarterly" },
  { value: "yearly", label: "Yearly" },
];
const todayISO = () => new Date().toLocaleDateString("en-CA", { timeZone: "America/New_York" });
const newItem = (): Item => ({ description: "", quantity: 1, rate: 0, account_id: null });
const newLine = (): Line => ({ account_id: "", amount: "", description: "" });

function scheduleLabel(t: any): string {
  const every = t.interval_count > 1 ? `every ${t.interval_count} ` : "";
  const unit = { weekly: "week", monthly: "month", quarterly: "quarter", yearly: "year" }[t.frequency as Freq];
  const plural = t.interval_count > 1 ? "s" : "";
  const dom = t.day_of_month && t.frequency !== "weekly" ? ` on day ${t.day_of_month}` : "";
  return `${every}${unit}${plural}${dom}`.replace(/^every 1 /, "");
}
function templateAmount(t: any): number {
  const p = t.payload ?? {};
  if (t.kind === "bill") {
    const sub = (p.items ?? []).reduce((s: number, i: any) => s + Number(i.quantity || 0) * Number(i.rate || 0), 0);
    return sub * (1 + Number(p.tax_pct || 0) / 100);
  }
  return (p.lines ?? []).reduce((s: number, l: any) => s + Math.max(0, Number(l.amount || 0)), 0);
}

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

  const [open, setOpen] = useState(false);
  const [editingId, setEditingId] = useState<string | null>(null);
  const [saving, setSaving] = useState(false);
  const [generating, setGenerating] = useState(false);

  // shared schedule fields
  const [kind, setKind] = useState<Kind>("bill");
  const [name, setName] = useState("");
  const [frequency, setFrequency] = useState<Freq>("monthly");
  const [intervalCount, setIntervalCount] = useState("1");
  const [dayOfMonth, setDayOfMonth] = useState("");
  const [startDate, setStartDate] = useState(todayISO());
  const [endDate, setEndDate] = useState("");
  // bill fields
  const [vendorId, setVendorId] = useState("");
  const [dueDays, setDueDays] = useState("30");
  const [memo, setMemo] = useState("");
  const [items, setItems] = useState<Item[]>([newItem()]);
  // journal fields
  const [jDescription, setJDescription] = useState("");
  const [jReference, setJReference] = useState("");
  const [lines, setLines] = useState<Line[]>([newLine(), newLine()]);

  const { data: templates = [], isLoading } = useQuery({
    queryKey: ["recurring-templates", cid],
    enabled: !!cid,
    queryFn: async () =>
      (await accounting.from("recurring_templates").select("*").eq("company_id", cid).order("next_run_date")).data ?? [],
  });

  const { data: vendors = [] } = useQuery({
    queryKey: ["vendors-lookup", associationId],
    enabled: !!associationId,
    queryFn: async () => (await supabase.from("vendors").select("id,name").eq("is_active", true)
      .or(`association_id.eq.${associationId},association_ids.cs.{${associationId}}`).order("name")).data ?? [],
  });

  const { data: accounts = [] } = useQuery({
    queryKey: ["recurring-accounts", cid],
    enabled: !!cid,
    queryFn: async () => (await accounting.from("accounts").select("id,name,code,type,is_bank")
      .eq("company_id", cid).eq("is_archived", false).order("code")).data ?? [],
  });
  const billAccounts = useMemo(() => (accounts as any[]).filter((a) => !a.is_bank && ["expense", "asset", "equity", "liability"].includes(a.type)), [accounts]);

  const resetForm = () => {
    setEditingId(null); setKind("bill"); setName(""); setFrequency("monthly"); setIntervalCount("1");
    setDayOfMonth(""); setStartDate(todayISO()); setEndDate("");
    setVendorId(""); setDueDays("30"); setMemo(""); setItems([newItem()]);
    setJDescription(""); setJReference(""); setLines([newLine(), newLine()]);
  };
  const openCreate = () => { resetForm(); setOpen(true); };
  const openEdit = (t: any) => {
    const p = t.payload ?? {};
    setEditingId(t.id); setKind(t.kind); setName(t.name); setFrequency(t.frequency);
    setIntervalCount(String(t.interval_count)); setDayOfMonth(t.day_of_month ? String(t.day_of_month) : "");
    setStartDate(t.next_run_date ?? t.start_date ?? todayISO()); setEndDate(t.end_date ?? "");
    if (t.kind === "bill") {
      setVendorId(p.vendor_public_id ?? ""); setDueDays(String(p.due_days ?? 30));
      setMemo(p.memo ?? "");
      setItems((p.items ?? []).length ? p.items.map((i: any) => ({ description: i.description ?? "", quantity: Number(i.quantity ?? 1), rate: Number(i.rate ?? 0), account_id: i.account_id ?? null })) : [newItem()]);
    } else {
      setJDescription(p.description ?? ""); setJReference(p.reference ?? "");
      setLines((p.lines ?? []).length ? p.lines.map((l: any) => ({ account_id: l.account_id ?? "", amount: String(l.amount ?? ""), description: l.description ?? "" })) : [newLine(), newLine()]);
    }
    setOpen(true);
  };

  const billTotal = useMemo(() => items.reduce((s, i) => s + Number(i.quantity || 0) * Number(i.rate || 0), 0), [items]);
  const jSigned = useMemo(() => lines.reduce((s, l) => s + (Number(l.amount) || 0), 0), [lines]);
  const jBalanced = Math.abs(jSigned) < 0.005;

  const save = async () => {
    if (!name.trim()) return toast.error("Give the template a name");
    const n = Math.max(1, parseInt(intervalCount) || 1);
    const dom = dayOfMonth ? Math.min(31, Math.max(1, parseInt(dayOfMonth))) : null;
    let payload: any;
    if (kind === "bill") {
      if (!vendorId) return toast.error("Select a vendor");
      const liveItems = items.filter((i) => i.account_id && (Number(i.quantity) * Number(i.rate)) !== 0);
      if (!liveItems.length) return toast.error("Add at least one line with an account and amount");
      // resolve the public vendor to its accounting.vendors row (find-or-create)
      const { data: acctVendor, error: vErr } = await supabase.rpc("ensure_accounting_vendor", { _association_id: associationId, _public_vendor_id: vendorId });
      if (vErr) return toast.error(vErr.message);
      payload = {
        vendor_id: acctVendor, vendor_public_id: vendorId,
        due_days: parseInt(dueDays) || 0, tax_pct: 0, memo: memo || null,
        items: liveItems.map((i) => ({ account_id: i.account_id, description: i.description, quantity: Number(i.quantity), rate: Number(i.rate) })),
      };
    } else {
      const liveLines = lines.filter((l) => l.account_id && Number(l.amount));
      if (liveLines.length < 2) return toast.error("Add at least two lines with an account and amount");
      if (!jBalanced) return toast.error(`Out of balance by ${money(Math.abs(jSigned), cur)} — debits (+) must equal credits (−)`);
      payload = {
        description: jDescription || name, reference: jReference || null,
        lines: liveLines.map((l) => ({ account_id: l.account_id, amount: Number(l.amount), description: l.description || null })),
      };
    }
    setSaving(true);
    const row: any = {
      company_id: cid, kind, name: name.trim(), frequency, interval_count: n, day_of_month: dom,
      start_date: startDate, next_run_date: startDate, end_date: endDate || null, payload,
    };
    let error;
    if (editingId) {
      // keep start_date stable on edit; update everything else incl. next_run_date
      delete row.start_date;
      ({ error } = await accounting.from("recurring_templates").update(row).eq("id", editingId));
    } else {
      ({ error } = await accounting.from("recurring_templates").insert(row));
    }
    setSaving(false);
    if (error) return toast.error(error.message);
    toast.success(editingId ? "Recurring template updated" : "Recurring template created");
    setOpen(false); resetForm();
    qc.invalidateQueries({ queryKey: ["recurring-templates", cid] });
  };

  const togglePause = async (t: any) => {
    const { error } = await accounting.from("recurring_templates").update({ active: !t.active }).eq("id", t.id);
    if (error) return toast.error(error.message);
    qc.invalidateQueries({ queryKey: ["recurring-templates", cid] });
  };
  const remove = async (t: any) => {
    if (!confirm(`Delete recurring ${t.kind} "${t.name}"? Already-generated bills/journals are kept.`)) return;
    const { error } = await accounting.from("recurring_templates").delete().eq("id", t.id);
    if (error) return toast.error(error.message);
    toast.success("Template deleted");
    qc.invalidateQueries({ queryKey: ["recurring-templates", cid] });
  };
  const generateDue = async () => {
    setGenerating(true);
    const { data, error } = await accounting.rpc("generate_due_recurring", { p_as_of: todayISO(), p_company_id: cid });
    setGenerating(false);
    if (error) return toast.error(error.message);
    const n = Number(data) || 0;
    toast.success(n ? `Generated ${n} item${n === 1 ? "" : "s"}` : "Nothing due right now");
    qc.invalidateQueries({ queryKey: ["recurring-templates", cid] });
    qc.invalidateQueries({ queryKey: ["bills", cid] });
    qc.invalidateQueries({ queryKey: ["journal-entries", cid] });
    qc.invalidateQueries({ queryKey: ["reports-data", cid] });
  };

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

  const dueCount = (templates as any[]).filter((t) => t.active && t.next_run_date <= todayISO()).length;

  return (
    <div className="space-y-4">
      <div className="flex items-center justify-between gap-2">
        <div>
          <h1 className="text-xl font-bold tracking-tight">Recurring Bills &amp; Journals</h1>
          <p className="text-sm text-muted-foreground">Templates auto-generate nightly; {dueCount > 0 ? `${dueCount} due now.` : "nothing due right now."}</p>
        </div>
        <div className="flex gap-2">
          <Button variant="outline" onClick={generateDue} disabled={generating}>
            {generating ? <Loader2 className="mr-1 h-4 w-4 animate-spin" /> : <RefreshCw className="mr-1 h-4 w-4" />} Generate due now
          </Button>
          <Button onClick={openCreate}><Plus className="mr-1 h-4 w-4" /> New recurring</Button>
        </div>
      </div>

      <Card>
        <CardContent className="p-0">
          {isLoading ? (
            <div className="p-8 text-center"><Loader2 className="h-5 w-5 animate-spin mx-auto text-muted-foreground" /></div>
          ) : (templates as any[]).length === 0 ? (
            <div className="p-10 text-center text-sm text-muted-foreground">No recurring templates yet. Click <strong>New recurring</strong> to set up a recurring bill or journal entry.</div>
          ) : (
            <Table>
              <TableHeader>
                <TableRow>
                  <TableHead>Name</TableHead><TableHead>Type</TableHead><TableHead>Schedule</TableHead>
                  <TableHead>Next run</TableHead><TableHead className="text-right">Amount</TableHead>
                  <TableHead>Status</TableHead><TableHead className="text-right">Actions</TableHead>
                </TableRow>
              </TableHeader>
              <TableBody>
                {(templates as any[]).map((t) => {
                  const due = t.active && t.next_run_date <= todayISO();
                  return (
                    <TableRow key={t.id}>
                      <TableCell className="font-medium">{t.name}</TableCell>
                      <TableCell><Badge variant="outline" className="capitalize">{t.kind}</Badge></TableCell>
                      <TableCell className="capitalize text-muted-foreground">{scheduleLabel(t)}</TableCell>
                      <TableCell className={due ? "text-amber-600 font-medium" : ""}>{fmtDate(t.next_run_date)}{due ? " · due" : ""}</TableCell>
                      <TableCell className="text-right tabular-nums">{money(templateAmount(t), cur)}</TableCell>
                      <TableCell>{t.active ? <Badge>Active</Badge> : <Badge variant="secondary">Paused</Badge>}</TableCell>
                      <TableCell className="text-right whitespace-nowrap">
                        <Button variant="ghost" size="icon" title={t.active ? "Pause" : "Resume"} onClick={() => togglePause(t)}>
                          {t.active ? <Pause className="h-4 w-4" /> : <Play className="h-4 w-4" />}
                        </Button>
                        <Button variant="ghost" size="icon" title="Edit" onClick={() => openEdit(t)}><Pencil className="h-4 w-4" /></Button>
                        <Button variant="ghost" size="icon" title="Delete" onClick={() => remove(t)}><Trash2 className="h-4 w-4" /></Button>
                      </TableCell>
                    </TableRow>
                  );
                })}
              </TableBody>
            </Table>
          )}
        </CardContent>
      </Card>

      <Dialog open={open} onOpenChange={(o) => { setOpen(o); if (!o) resetForm(); }}>
        <DialogContent className="max-w-3xl max-h-[90vh] overflow-y-auto">
          <DialogHeader><DialogTitle>{editingId ? "Edit" : "New"} recurring {kind}</DialogTitle></DialogHeader>
          <div className="space-y-4">
            <div className="grid grid-cols-2 gap-3">
              <div>
                <Label>Type</Label>
                <Select value={kind} onValueChange={(v) => setKind(v as Kind)} disabled={!!editingId}>
                  <SelectTrigger><SelectValue /></SelectTrigger>
                  <SelectContent><SelectItem value="bill">Bill (A/P)</SelectItem><SelectItem value="journal">Journal entry</SelectItem></SelectContent>
                </Select>
              </div>
              <div><Label>Name</Label><Input value={name} onChange={(e) => setName(e.target.value)} placeholder="e.g. Monthly management fee" /></div>
            </div>

            <div className="grid grid-cols-2 md:grid-cols-4 gap-3">
              <div>
                <Label>Frequency</Label>
                <Select value={frequency} onValueChange={(v) => setFrequency(v as Freq)}>
                  <SelectTrigger><SelectValue /></SelectTrigger>
                  <SelectContent>{FREQS.map((f) => <SelectItem key={f.value} value={f.value}>{f.label}</SelectItem>)}</SelectContent>
                </Select>
              </div>
              <div><Label>Every</Label><Input type="number" min="1" value={intervalCount} onChange={(e) => setIntervalCount(e.target.value)} /></div>
              <div><Label>{editingId ? "Next run" : "Start date"}</Label><Input type="date" value={startDate} onChange={(e) => setStartDate(e.target.value)} /></div>
              <div><Label>End date <span className="text-muted-foreground">(optional)</span></Label><Input type="date" value={endDate} onChange={(e) => setEndDate(e.target.value)} /></div>
            </div>
            {frequency !== "weekly" && (
              <div className="w-40"><Label>Day of month <span className="text-muted-foreground">(opt)</span></Label><Input type="number" min="1" max="31" value={dayOfMonth} onChange={(e) => setDayOfMonth(e.target.value)} placeholder="from start" /></div>
            )}

            {kind === "bill" ? (
              <div className="space-y-3 border-t pt-3">
                <div className="grid grid-cols-2 md:grid-cols-3 gap-3">
                  <div className="col-span-2">
                    <Label>Vendor (Pay to)</Label>
                    <Select value={vendorId} onValueChange={setVendorId}>
                      <SelectTrigger><SelectValue placeholder="Select vendor" /></SelectTrigger>
                      <SelectContent>{(vendors as any[]).map((v) => <SelectItem key={v.id} value={v.id}>{v.name}</SelectItem>)}</SelectContent>
                    </Select>
                  </div>
                  <div><Label>Due in (days)</Label><Input type="number" min="0" value={dueDays} onChange={(e) => setDueDays(e.target.value)} /></div>
                </div>
                <div><Label>Memo</Label><Input value={memo} onChange={(e) => setMemo(e.target.value)} placeholder="optional" /></div>
                <div className="space-y-2">
                  <Label>Line items</Label>
                  {items.map((it, idx) => (
                    <div key={idx} className="grid grid-cols-12 gap-2 items-center">
                      <Select value={it.account_id ?? ""} onValueChange={(v) => setItems(items.map((x, i) => i === idx ? { ...x, account_id: v } : x))}>
                        <SelectTrigger className="col-span-4"><SelectValue placeholder="Account" /></SelectTrigger>
                        <SelectContent>{billAccounts.map((a) => <SelectItem key={a.id} value={a.id}>{a.code} · {a.name}</SelectItem>)}</SelectContent>
                      </Select>
                      <Input className="col-span-4" placeholder="Description" value={it.description} onChange={(e) => setItems(items.map((x, i) => i === idx ? { ...x, description: e.target.value } : x))} />
                      <Input className="col-span-1" type="number" title="Qty" value={it.quantity} onChange={(e) => setItems(items.map((x, i) => i === idx ? { ...x, quantity: Number(e.target.value) } : x))} />
                      <Input className="col-span-2" type="number" title="Rate" value={it.rate} onChange={(e) => setItems(items.map((x, i) => i === idx ? { ...x, rate: Number(e.target.value) } : x))} />
                      <Button variant="ghost" size="icon" className="col-span-1" onClick={() => setItems(items.length > 1 ? items.filter((_, i) => i !== idx) : items)}><Trash2 className="h-4 w-4" /></Button>
                    </div>
                  ))}
                  <Button variant="outline" size="sm" onClick={() => setItems([...items, newItem()])}><Plus className="mr-1 h-3 w-3" /> Add line</Button>
                </div>
                <div className="text-right text-sm font-medium">Total per bill: {money(billTotal, cur)}</div>
              </div>
            ) : (
              <div className="space-y-3 border-t pt-3">
                <div className="grid grid-cols-2 gap-3">
                  <div><Label>Description</Label><Input value={jDescription} onChange={(e) => setJDescription(e.target.value)} placeholder={name || "Journal description"} /></div>
                  <div><Label>Reference <span className="text-muted-foreground">(opt)</span></Label><Input value={jReference} onChange={(e) => setJReference(e.target.value)} /></div>
                </div>
                <div className="space-y-2">
                  <Label>Lines <span className="text-muted-foreground">(+ debit, − credit)</span></Label>
                  {lines.map((ln, idx) => (
                    <div key={idx} className="grid grid-cols-12 gap-2 items-center">
                      <Select value={ln.account_id} onValueChange={(v) => setLines(lines.map((x, i) => i === idx ? { ...x, account_id: v } : x))}>
                        <SelectTrigger className="col-span-5"><SelectValue placeholder="Account" /></SelectTrigger>
                        <SelectContent>{(accounts as any[]).map((a) => <SelectItem key={a.id} value={a.id}>{a.code} · {a.name}</SelectItem>)}</SelectContent>
                      </Select>
                      <Input className="col-span-4" placeholder="Description" value={ln.description} onChange={(e) => setLines(lines.map((x, i) => i === idx ? { ...x, description: e.target.value } : x))} />
                      <Input className="col-span-2" type="number" placeholder="+/-" value={ln.amount} onChange={(e) => setLines(lines.map((x, i) => i === idx ? { ...x, amount: e.target.value } : x))} />
                      <Button variant="ghost" size="icon" className="col-span-1" onClick={() => setLines(lines.length > 2 ? lines.filter((_, i) => i !== idx) : lines)}><Trash2 className="h-4 w-4" /></Button>
                    </div>
                  ))}
                  <Button variant="outline" size="sm" onClick={() => setLines([...lines, newLine()])}><Plus className="mr-1 h-3 w-3" /> Add line</Button>
                  <div className={`text-right text-sm font-medium ${jBalanced ? "text-muted-foreground" : "text-destructive"}`}>
                    {jBalanced ? "Balanced" : `Out of balance by ${money(Math.abs(jSigned), cur)}`}
                  </div>
                </div>
              </div>
            )}
          </div>
          <DialogFooter>
            <Button variant="outline" onClick={() => { setOpen(false); resetForm(); }}>Cancel</Button>
            <Button onClick={save} disabled={saving}>{saving ? <Loader2 className="mr-1 h-4 w-4 animate-spin" /> : null} {editingId ? "Save" : "Create"}</Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>
    </div>
  );
}
