import { useMemo, useState } from "react";
import { useQuery } from "@tanstack/react-query";
import { accounting } from "@/lib/accountingClient";
import { Card, CardContent } from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Button } from "@/components/ui/button";
import { FileDown, Download } from "lucide-react";
import jsPDF from "jspdf";
import autoTable from "jspdf-autotable";
import { ReportSheet } from "./ReportSheet";
import { loadBrandedLogo, drawBrandedHeader, drawBrandedFooter } from "../lib/reportHeader";

type AcctType = "asset" | "liability" | "equity" | "income" | "expense";
const DEBIT_NATURAL: AcctType[] = ["asset", "expense"];

const TEAL: [number, number, number] = [0, 137, 123];

type ReserveAccount = { id: string; name: string; code: string | null; type: AcctType };

type Row = {
  code: string | null;
  name: string;
  priorBalance: number;
  currMonthAdditions: number;
  additionsThisYear: number;
  currMonthExpenses: number;
  prevExpenseThisYear: number;
  totExpenseThisYear: number;
  currentBalance: number;
};

/** Always two decimals, thousands-separated, negatives in parentheses. */
function num(n: number): string {
  const v = Math.round((n + Number.EPSILON) * 100) / 100 || 0;
  const abs = Math.abs(v).toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 });
  return v < 0 ? `(${abs})` : abs;
}

/** Last day of a YYYY-MM month, as YYYY-MM-DD (no timezone drift). */
function monthEnd(ym: string): string {
  const [y, m] = ym.split("-").map(Number);
  const d = new Date(y, m, 0).getDate();
  return `${y}-${String(m).padStart(2, "0")}-${String(d).padStart(2, "0")}`;
}

function monthStartOf(ym: string): string {
  return `${ym}-01`;
}

/** Fiscal-year start (YYYY-MM-DD) for the FY that contains `asOf`. */
function fiscalYearStartFor(asOf: string, fiscalYearStart: string): string {
  const year = Number(asOf.slice(0, 4));
  const md = (fiscalYearStart || "01-01").trim(); // "MM-DD"
  const candidate = `${year}-${md}`;
  return asOf >= candidate ? candidate : `${year - 1}-${md}`;
}

export function ReserveFundReport({
  companyId,
  companyName,
  fiscalYearStart = "01-01",
  logoUrl,
}: {
  companyId: string;
  companyName: string;
  fiscalYearStart?: string;
  logoUrl?: string | null;
}) {
  const [asOfMonth, setAsOfMonth] = useState(() => new Date().toISOString().slice(0, 7));

  const asOf = monthEnd(asOfMonth);
  const monthStart = monthStartOf(asOfMonth);
  const fyStart = fiscalYearStartFor(asOf, fiscalYearStart);

  const { data: reserveAccounts = [], isLoading: acctLoading } = useQuery({
    queryKey: ["reserve-accounts", companyId],
    enabled: !!companyId,
    queryFn: async () => {
      const { data } = await accounting
        .from("accounts")
        .select("id,name,code,type,is_reserve")
        .eq("company_id", companyId)
        .eq("is_reserve", true)
        .order("code", { ascending: true });
      return (data ?? []) as ReserveAccount[];
    },
  });

  const reserveIds = useMemo(() => reserveAccounts.map((a) => a.id), [reserveAccounts]);

  // Only pull ledger lines for the (few) reserve accounts — never the whole
  // company ledger, which can run into millions of rows.
  const { data: glLines = [], isLoading: glLoading } = useQuery({
    queryKey: ["reserve-gl", companyId, asOf, reserveIds.join(",")],
    enabled: !!companyId && reserveIds.length > 0,
    queryFn: async () => {
      const { data } = await accounting
        .from("journal_entry_lines")
        .select("debit,credit,account_id,journal_entries!inner(company_id,date)")
        .eq("journal_entries.company_id", companyId)
        .in("account_id", reserveIds)
        .lte("journal_entries.date", asOf)
        .limit(50000);
      return (data ?? []) as any[];
    },
  });

  const rows = useMemo<Row[]>(() => {
    const byAcct = new Map<string, ReserveAccount>();
    for (const a of reserveAccounts) byAcct.set(a.id, a);

    const acc = new Map<string, Row>();
    for (const a of reserveAccounts) {
      acc.set(a.id, {
        code: a.code,
        name: a.name,
        priorBalance: 0,
        currMonthAdditions: 0,
        additionsThisYear: 0,
        currMonthExpenses: 0,
        prevExpenseThisYear: 0,
        totExpenseThisYear: 0,
        currentBalance: 0,
      });
    }

    for (const l of glLines) {
      const a = byAcct.get(l.account_id);
      if (!a) continue; // only reserve accounts
      const r = acc.get(l.account_id)!;
      const d: string = l.journal_entries?.date ?? "";
      if (!d) continue;
      const debit = Number(l.debit || 0);
      const credit = Number(l.credit || 0);
      const naturalDebit = DEBIT_NATURAL.includes(a.type);
      // Additions move the balance up (natural side); expenses move it down.
      const addition = naturalDebit ? debit : credit;
      const expense = naturalDebit ? credit : debit;
      const naturalDelta = naturalDebit ? debit - credit : credit - debit;

      if (d < fyStart) {
        r.priorBalance += naturalDelta;
      } else if (d <= asOf) {
        r.additionsThisYear += addition;
        r.totExpenseThisYear += expense;
        if (d >= monthStart) {
          r.currMonthAdditions += addition;
          r.currMonthExpenses += expense;
        }
      }
    }

    const out: Row[] = [];
    for (const a of reserveAccounts) {
      const r = acc.get(a.id)!;
      r.prevExpenseThisYear = r.totExpenseThisYear - r.currMonthExpenses;
      r.currentBalance = r.priorBalance + r.additionsThisYear - r.totExpenseThisYear;
      out.push(r);
    }
    return out;
  }, [reserveAccounts, glLines, fyStart, monthStart, asOf]);

  const totals = useMemo(() => {
    return rows.reduce(
      (t, r) => ({
        priorBalance: t.priorBalance + r.priorBalance,
        currMonthAdditions: t.currMonthAdditions + r.currMonthAdditions,
        additionsThisYear: t.additionsThisYear + r.additionsThisYear,
        currMonthExpenses: t.currMonthExpenses + r.currMonthExpenses,
        prevExpenseThisYear: t.prevExpenseThisYear + r.prevExpenseThisYear,
        totExpenseThisYear: t.totExpenseThisYear + r.totExpenseThisYear,
        currentBalance: t.currentBalance + r.currentBalance,
      }),
      { priorBalance: 0, currMonthAdditions: 0, additionsThisYear: 0, currMonthExpenses: 0, prevExpenseThisYear: 0, totExpenseThisYear: 0, currentBalance: 0 },
    );
  }, [rows]);

  const asOfLabel = new Date(asOf + "T00:00:00").toLocaleDateString("en-US", { month: "long", day: "numeric", year: "numeric" });
  const isLoading = acctLoading || glLoading;

  // Expenses display as negatives (draws against the reserve), matching the schedule convention.
  const exp = (n: number) => num(n === 0 ? 0 : -n);

  const exportPDF = async () => {
    const doc = new jsPDF({ unit: "pt", format: "letter", orientation: "landscape" });
    const ML = 40;
    const logo = await loadBrandedLogo(logoUrl);
    const startY = drawBrandedHeader(doc, {
      logo, title: "Allocated Reserve Fund Schedule", subtitle: asOfLabel,
      metaLines: [{ label: "Properties:", value: companyName || "" }],
    });

    const body = rows.map((r) => [
      `${r.code ? r.code + "  " : ""}${r.name}`,
      num(r.priorBalance),
      num(r.currMonthAdditions),
      num(r.additionsThisYear),
      exp(r.currMonthExpenses),
      exp(r.prevExpenseThisYear),
      exp(r.totExpenseThisYear),
      num(r.currentBalance),
    ]);
    body.push([
      { content: "TOTAL RESERVE FUNDS", styles: { fontStyle: "bold" } } as any,
      { content: num(totals.priorBalance), styles: { fontStyle: "bold", halign: "right" } } as any,
      { content: num(totals.currMonthAdditions), styles: { fontStyle: "bold", halign: "right" } } as any,
      { content: num(totals.additionsThisYear), styles: { fontStyle: "bold", halign: "right" } } as any,
      { content: exp(totals.currMonthExpenses), styles: { fontStyle: "bold", halign: "right" } } as any,
      { content: exp(totals.prevExpenseThisYear), styles: { fontStyle: "bold", halign: "right" } } as any,
      { content: exp(totals.totExpenseThisYear), styles: { fontStyle: "bold", halign: "right" } } as any,
      { content: num(totals.currentBalance), styles: { fontStyle: "bold", halign: "right" } } as any,
    ]);

    autoTable(doc, {
      startY,
      head: [[
        "Account",
        "Prior Year\nBalance Forward",
        "Curr Month\nAdditions",
        "Additions\nThis Year",
        "Curr Month\nExpenses",
        "Prev Expense\nThis Year",
        "Tot Expense\nThis Year",
        "Current\nBalance",
      ]],
      body,
      styles: { fontSize: 8, cellPadding: 3 },
      headStyles: { fillColor: TEAL, textColor: 255, halign: "right", fontSize: 8 },
      columnStyles: {
        0: { halign: "left", cellWidth: 150 },
        1: { halign: "right" }, 2: { halign: "right" }, 3: { halign: "right" },
        4: { halign: "right" }, 5: { halign: "right" }, 6: { halign: "right" }, 7: { halign: "right" },
      },
      margin: { left: ML, right: ML },
    });

    drawBrandedFooter(doc);
    doc.save(`reserve-fund-schedule-${asOf}.pdf`);
  };

  const exportCSV = () => {
    const header = ["Code", "Account", "Prior Year Balance Forward", "Curr Month Additions", "Additions This Year", "Curr Month Expenses", "Prev Expense This Year", "Tot Expense This Year", "Current Balance"];
    const lines = [header.join(",")];
    const f = (n: number) => (Math.round((n + Number.EPSILON) * 100) / 100 || 0).toFixed(2);
    for (const r of rows) {
      lines.push([
        r.code ?? "", `"${r.name.replace(/"/g, '""')}"`,
        f(r.priorBalance), f(r.currMonthAdditions), f(r.additionsThisYear),
        f(-r.currMonthExpenses), f(-r.prevExpenseThisYear), f(-r.totExpenseThisYear), f(r.currentBalance),
      ].join(","));
    }
    lines.push([
      "", '"TOTAL RESERVE FUNDS"',
      f(totals.priorBalance), f(totals.currMonthAdditions), f(totals.additionsThisYear),
      f(-totals.currMonthExpenses), f(-totals.prevExpenseThisYear), f(-totals.totExpenseThisYear), f(totals.currentBalance),
    ].join(","));
    const blob = new Blob([lines.join("\n")], { type: "text/csv" });
    const a = document.createElement("a");
    a.href = URL.createObjectURL(blob);
    a.download = `reserve-fund-schedule-${asOf}.csv`;
    a.click();
    URL.revokeObjectURL(a.href);
  };

  return (
    <div className="space-y-4">
      <Card>
        <CardContent className="flex flex-wrap items-end gap-4 py-4">
          <div>
            <Label className="text-xs text-muted-foreground">As of Month</Label>
            <Input type="month" value={asOfMonth} onChange={(e) => setAsOfMonth(e.target.value || asOfMonth)} className="w-44 mt-1" />
          </div>
          <div className="text-xs text-muted-foreground pb-1">
            Fiscal year from {new Date(fyStart + "T00:00:00").toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" })}
          </div>
          {rows.length > 0 && (
            <div className="ml-auto flex gap-2">
              <Button variant="outline" onClick={exportCSV}><Download className="mr-1 h-4 w-4" /> CSV</Button>
              <Button onClick={exportPDF}><FileDown className="mr-1 h-4 w-4" /> PDF</Button>
            </div>
          )}
        </CardContent>
      </Card>

      {isLoading ? (
        <Card><CardContent className="p-8 text-center text-sm text-muted-foreground">Loading…</CardContent></Card>
      ) : rows.length === 0 ? (
        <Card><CardContent className="p-8 text-center text-sm text-muted-foreground">
          No reserve accounts yet. Mark accounts as a <span className="font-medium">Reserve fund account</span> in the
          Chart of Accounts to include them on this schedule.
        </CardContent></Card>
      ) : (
        <ReportSheet title="Allocated Reserve Fund Schedule" subtitle={asOfLabel} companyName={companyName} logoUrl={logoUrl}>
            <div className="overflow-x-auto">
              <table className="w-full text-sm">
                <thead>
                  <tr className="border-y text-[11px] uppercase tracking-wide text-muted-foreground">
                    <th className="px-3 py-2 text-left font-semibold">Account</th>
                    <th className="px-3 py-2 text-right font-semibold">Prior Year<br />Balance Forward</th>
                    <th className="px-3 py-2 text-right font-semibold">Curr Month<br />Additions</th>
                    <th className="px-3 py-2 text-right font-semibold">Additions<br />This Year</th>
                    <th className="px-3 py-2 text-right font-semibold">Curr Month<br />Expenses</th>
                    <th className="px-3 py-2 text-right font-semibold">Prev Expense<br />This Year</th>
                    <th className="px-3 py-2 text-right font-semibold">Tot Expense<br />This Year</th>
                    <th className="px-3 py-2 text-right font-semibold">Current<br />Balance</th>
                  </tr>
                </thead>
                <tbody>
                  {rows.map((r, i) => (
                    <tr key={i} className="border-b">
                      <td className="px-3 py-1.5">
                        {r.code && <span className="font-mono text-xs text-muted-foreground mr-2">{r.code}</span>}
                        {r.name}
                      </td>
                      <td className="px-3 py-1.5 text-right tabular-nums">{num(r.priorBalance)}</td>
                      <td className="px-3 py-1.5 text-right tabular-nums">{num(r.currMonthAdditions)}</td>
                      <td className="px-3 py-1.5 text-right tabular-nums">{num(r.additionsThisYear)}</td>
                      <td className="px-3 py-1.5 text-right tabular-nums">{exp(r.currMonthExpenses)}</td>
                      <td className="px-3 py-1.5 text-right tabular-nums">{exp(r.prevExpenseThisYear)}</td>
                      <td className="px-3 py-1.5 text-right tabular-nums">{exp(r.totExpenseThisYear)}</td>
                      <td className="px-3 py-1.5 text-right tabular-nums font-medium">{num(r.currentBalance)}</td>
                    </tr>
                  ))}
                </tbody>
                <tfoot>
                  <tr className="border-t-2 border-b-2 border-primary font-bold">
                    <td className="px-3 py-3">TOTAL RESERVE FUNDS</td>
                    <td className="px-3 py-3 text-right tabular-nums">{num(totals.priorBalance)}</td>
                    <td className="px-3 py-3 text-right tabular-nums">{num(totals.currMonthAdditions)}</td>
                    <td className="px-3 py-3 text-right tabular-nums">{num(totals.additionsThisYear)}</td>
                    <td className="px-3 py-3 text-right tabular-nums">{exp(totals.currMonthExpenses)}</td>
                    <td className="px-3 py-3 text-right tabular-nums">{exp(totals.prevExpenseThisYear)}</td>
                    <td className="px-3 py-3 text-right tabular-nums">{exp(totals.totExpenseThisYear)}</td>
                    <td className="px-3 py-3 text-right tabular-nums">{num(totals.currentBalance)}</td>
                  </tr>
                </tfoot>
              </table>
            </div>
        </ReportSheet>
      )}
    </div>
  );
}
