import jsPDF from "jspdf";
import autoTable, { RowInput } from "jspdf-autotable";

type Metrics = {
  operatingBalance: number;
  reserveBalance: number;
  accountsReceivable: number;
  accountsPayable: number;
  arAccounts?: number;
  apPending?: number;
};

type MonthlyRow = { month: string; income: number; expenses: number };
type CategoryRow = { name: string; value: number };
type DelinquencyRow = { month: string; accounts: number; amount: number };
type TransactionRow = {
  date?: string | null;
  description?: string | null;
  transaction_type?: string | null;
  credit?: number | null;
  debit?: number | null;
  is_cleared?: boolean | null;
};

type Association = { id?: string; name: string; logo_url?: string | null };

const fmt = (n: number) =>
  (n < 0 ? "-" : "") +
  "$" +
  Math.abs(n).toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 });

const fmtDate = (d: string | null | undefined) => {
  if (!d) return "—";
  try {
    return new Date(d + (d.length === 10 ? "T12:00:00" : "")).toLocaleDateString("en-US", {
      month: "short",
      day: "numeric",
      year: "numeric",
    });
  } catch {
    return d as string;
  }
};

async function loadImageAsDataURL(url: string): Promise<{ data: string; format: string } | null> {
  try {
    const res = await fetch(url, { mode: "cors" });
    const blob = await res.blob();
    const format = blob.type.includes("png")
      ? "PNG"
      : blob.type.includes("jpeg") || blob.type.includes("jpg")
        ? "JPEG"
        : "PNG";
    const data: string = await new Promise((resolve, reject) => {
      const reader = new FileReader();
      reader.onload = () => resolve(reader.result as string);
      reader.onerror = reject;
      reader.readAsDataURL(blob);
    });
    return { data, format };
  } catch {
    return null;
  }
}

export async function generateFinancialOverviewPdf(opts: {
  association: Association | null;
  scopeLabel: string; // e.g. "All Associations" or association name
  metrics: Metrics;
  monthly: MonthlyRow[];
  categories: CategoryRow[];
  delinquency: DelinquencyRow[];
  transactions: TransactionRow[];
}) {
  const { association, scopeLabel, metrics, monthly, categories, delinquency, transactions } = opts;
  const doc = new jsPDF({ unit: "pt", format: "letter" });
  const pageWidth = doc.internal.pageSize.getWidth();
  const pageHeight = doc.internal.pageSize.getHeight();
  const marginX = 40;

  // Header — logo (top left) + title block (centered)
  if (association?.logo_url) {
    const img = await loadImageAsDataURL(association.logo_url);
    if (img) {
      try {
        doc.addImage(img.data, img.format, marginX, 30, 60, 60, undefined, "FAST");
      } catch {
        /* ignore */
      }
    }
  }
  doc.setFont("helvetica", "bold");
  doc.setFontSize(15);
  doc.text("Financial Overview", pageWidth / 2, 55, { align: "center" });
  doc.setFont("helvetica", "normal");
  doc.setFontSize(11);
  doc.text(scopeLabel, pageWidth / 2, 73, { align: "center" });
  doc.setFontSize(9);
  doc.setTextColor(120);
  doc.text(
    `As of ${new Date().toLocaleDateString("en-US", {
      month: "long",
      day: "numeric",
      year: "numeric",
    })}`,
    pageWidth / 2,
    88,
    { align: "center" },
  );
  doc.setTextColor(0);

  // Key Metrics — 2x2 grid table
  let cursorY = 110;
  const metricBody: RowInput[] = [
    [
      { content: "Operating Balance", styles: { fontStyle: "bold", fillColor: [245, 247, 250] } },
      { content: fmt(metrics.operatingBalance), styles: { halign: "right", fontStyle: "bold" } },
      { content: "Reserve Balance", styles: { fontStyle: "bold", fillColor: [245, 247, 250] } },
      { content: fmt(metrics.reserveBalance), styles: { halign: "right", fontStyle: "bold" } },
    ],
    [
      { content: "Accounts Receivable", styles: { fontStyle: "bold", fillColor: [245, 247, 250] } },
      {
        content:
          fmt(metrics.accountsReceivable) +
          (metrics.arAccounts != null ? `\n(${metrics.arAccounts} accounts)` : ""),
        styles: { halign: "right", fontStyle: "bold" },
      },
      { content: "Accounts Payable", styles: { fontStyle: "bold", fillColor: [245, 247, 250] } },
      {
        content:
          fmt(metrics.accountsPayable) +
          (metrics.apPending != null ? `\n(${metrics.apPending} pending)` : ""),
        styles: { halign: "right", fontStyle: "bold" },
      },
    ],
  ];
  autoTable(doc, {
    startY: cursorY,
    body: metricBody,
    theme: "grid",
    styles: { font: "helvetica", fontSize: 10, cellPadding: 8, lineColor: [220, 220, 220], lineWidth: 0.5 },
    columnStyles: {
      0: { cellWidth: 130 },
      1: { cellWidth: 145 },
      2: { cellWidth: 130 },
      3: { cellWidth: 130 },
    },
    margin: { left: marginX, right: marginX },
  });
  cursorY = (doc as any).lastAutoTable.finalY + 24;

  // Section: Monthly Income vs Expenses
  doc.setFont("helvetica", "bold");
  doc.setFontSize(11);
  doc.setTextColor(0);
  doc.text("Monthly Income vs. Expenses", marginX, cursorY);
  cursorY += 6;
  const monthlyTotals = monthly.reduce(
    (acc, r) => ({ income: acc.income + r.income, expenses: acc.expenses + r.expenses }),
    { income: 0, expenses: 0 },
  );
  autoTable(doc, {
    startY: cursorY + 6,
    head: [
      [
        { content: "Month", styles: { halign: "left" } },
        { content: "Income", styles: { halign: "right" } },
        { content: "Expenses", styles: { halign: "right" } },
        { content: "Net", styles: { halign: "right" } },
      ],
    ],
    body: [
      ...monthly.map((r) => [
        r.month,
        { content: fmt(r.income), styles: { halign: "right" as const } },
        { content: fmt(r.expenses), styles: { halign: "right" as const } },
        {
          content: fmt(r.income - r.expenses),
          styles: { halign: "right" as const, textColor: r.income - r.expenses >= 0 ? [16, 122, 70] : [180, 35, 35] },
        },
      ]),
      [
        { content: "Total", styles: { fontStyle: "bold" } },
        { content: fmt(monthlyTotals.income), styles: { halign: "right", fontStyle: "bold" } },
        { content: fmt(monthlyTotals.expenses), styles: { halign: "right", fontStyle: "bold" } },
        {
          content: fmt(monthlyTotals.income - monthlyTotals.expenses),
          styles: {
            halign: "right",
            fontStyle: "bold",
            textColor: monthlyTotals.income - monthlyTotals.expenses >= 0 ? [16, 122, 70] : [180, 35, 35],
          },
        },
      ],
    ] as RowInput[],
    theme: "striped",
    styles: { font: "helvetica", fontSize: 9, cellPadding: 5 },
    headStyles: { fillColor: [235, 238, 244], textColor: [0, 0, 0], fontStyle: "bold" },
    margin: { left: marginX, right: marginX },
  });
  cursorY = (doc as any).lastAutoTable.finalY + 20;

  // Section: Expense Categories
  if (categories.length > 0) {
    doc.setFont("helvetica", "bold");
    doc.setFontSize(11);
    doc.text("Top Expense Categories", marginX, cursorY);
    const totalCat = categories.reduce((s, c) => s + c.value, 0) || 1;
    autoTable(doc, {
      startY: cursorY + 6,
      head: [
        [
          { content: "Category", styles: { halign: "left" } },
          { content: "Amount", styles: { halign: "right" } },
          { content: "% of Total", styles: { halign: "right" } },
        ],
      ],
      body: categories.map((c) => [
        c.name,
        { content: fmt(c.value), styles: { halign: "right" as const } },
        { content: ((c.value / totalCat) * 100).toFixed(1) + "%", styles: { halign: "right" as const } },
      ]) as RowInput[],
      theme: "striped",
      styles: { font: "helvetica", fontSize: 9, cellPadding: 5 },
      headStyles: { fillColor: [235, 238, 244], textColor: [0, 0, 0], fontStyle: "bold" },
      margin: { left: marginX, right: marginX },
    });
    cursorY = (doc as any).lastAutoTable.finalY + 20;
  }

  // Section: Delinquency Trend
  if (delinquency.length > 0) {
    doc.setFont("helvetica", "bold");
    doc.setFontSize(11);
    doc.text("Delinquency Trend (6 Months)", marginX, cursorY);
    autoTable(doc, {
      startY: cursorY + 6,
      head: [
        [
          { content: "Month", styles: { halign: "left" } },
          { content: "Active Accounts", styles: { halign: "right" } },
          { content: "Total Owed", styles: { halign: "right" } },
        ],
      ],
      body: delinquency.map((r) => [
        r.month,
        { content: r.accounts.toString(), styles: { halign: "right" as const } },
        { content: fmt(r.amount), styles: { halign: "right" as const } },
      ]) as RowInput[],
      theme: "striped",
      styles: { font: "helvetica", fontSize: 9, cellPadding: 5 },
      headStyles: { fillColor: [235, 238, 244], textColor: [0, 0, 0], fontStyle: "bold" },
      margin: { left: marginX, right: marginX },
    });
    cursorY = (doc as any).lastAutoTable.finalY + 20;
  }

  // Section: Recent Transactions
  if (transactions.length > 0) {
    doc.setFont("helvetica", "bold");
    doc.setFontSize(11);
    doc.text("Recent Transactions", marginX, cursorY);
    autoTable(doc, {
      startY: cursorY + 6,
      head: [
        [
          { content: "Date", styles: { halign: "left" } },
          { content: "Description", styles: { halign: "left" } },
          { content: "Type", styles: { halign: "left" } },
          { content: "Amount", styles: { halign: "right" } },
          { content: "Status", styles: { halign: "center" } },
        ],
      ],
      body: transactions.map((t) => {
        const isCredit = (t.credit || 0) > 0;
        const amount = isCredit ? t.credit || 0 : t.debit || 0;
        return [
          fmtDate(t.date || null),
          t.description || "Transaction",
          (t.transaction_type || "other").replace(/_/g, " "),
          {
            content: (isCredit ? "+" : "-") + fmt(amount),
            styles: { halign: "right" as const, textColor: isCredit ? [16, 122, 70] : [40, 40, 40] },
          },
          { content: t.is_cleared ? "Cleared" : "Pending", styles: { halign: "center" as const } },
        ];
      }) as RowInput[],
      theme: "striped",
      styles: { font: "helvetica", fontSize: 9, cellPadding: 5 },
      headStyles: { fillColor: [235, 238, 244], textColor: [0, 0, 0], fontStyle: "bold" },
      columnStyles: {
        0: { cellWidth: 70 },
        1: { cellWidth: "auto" },
        2: { cellWidth: 80 },
        3: { cellWidth: 80 },
        4: { cellWidth: 60 },
      },
      margin: { left: marginX, right: marginX },
    });
  }

  // Footer (every page)
  const pageCount = doc.getNumberOfPages();
  for (let i = 1; i <= pageCount; i++) {
    doc.setPage(i);
    doc.setFontSize(8);
    doc.setTextColor(120);
    doc.text(`Generated ${new Date().toLocaleDateString("en-US")}`, marginX, pageHeight - 20);
    doc.text(`Page ${i} of ${pageCount}`, pageWidth - marginX, pageHeight - 20, { align: "right" });
    doc.setTextColor(0);
  }

  const fileName = `${(association?.name || scopeLabel).replace(/[^a-z0-9]+/gi, "_")}_Financial_Overview_${new Date()
    .toISOString()
    .slice(0, 10)}.pdf`;
  doc.save(fileName);
}
