import jsPDF from "jspdf";
import autoTable from "jspdf-autotable";
import { money, fmtDate } from "./format";
import { loadBrandedLogo, drawBrandedHeader, drawBrandedFooter } from "./reportHeader";

type RGB = [number, number, number];
const TEXT: RGB = [33, 37, 41];
const MUTED: RGB = [110, 116, 122];
const INCOME: RGB = [0, 137, 123];   // teal
const EXPENSE: RGB = [245, 159, 11]; // amber
const DONUT: RGB[] = [
  [0, 137, 123], [38, 166, 154], [245, 159, 11], [239, 68, 68], [99, 102, 241], [139, 92, 246],
];

export type DashboardPdfData = {
  totalReceivable: number;
  totalPayable: number;
  cash: number;
  counts: { draft: number; sent: number; overdue: number; paid: number };
  months: { label: string; income: number; expense: number }[];
  topExpenses: { name: string; value: number }[];
  recent: { date?: string; description?: string; category?: string | null; reference?: string | null; amount: number; type?: string }[];
};

const kFmt = (n: number) => (Math.abs(n) >= 1000 ? `$${(n / 1000).toFixed(0)}k` : `$${Math.round(n)}`);

/** Native (vector) grouped bar chart: income vs expense per month. */
function drawBarChart(doc: jsPDF, x: number, y: number, w: number, h: number, months: DashboardPdfData["months"], currency: string) {
  const plotTop = y + 8;
  const plotH = h - 24;
  const baseY = plotTop + plotH;
  const max = Math.max(1, ...months.flatMap((m) => [m.income, m.expense]));

  // gridlines + y labels (0, half, max)
  doc.setDrawColor(230); doc.setLineWidth(0.4);
  doc.setFontSize(7); doc.setTextColor(...MUTED);
  [0, 0.5, 1].forEach((f) => {
    const gy = baseY - plotH * f;
    doc.line(x, gy, x + w, gy);
    doc.text(kFmt(max * f), x - 4, gy + 2, { align: "right" });
  });

  const n = Math.max(1, months.length);
  const groupW = w / n;
  const barW = Math.min(16, groupW * 0.3);
  months.forEach((m, i) => {
    const gx = x + i * groupW + groupW / 2;
    const ih = (m.income / max) * plotH;
    const eh = (m.expense / max) * plotH;
    doc.setFillColor(...INCOME); doc.rect(gx - barW - 1.5, baseY - ih, barW, ih, "F");
    doc.setFillColor(...EXPENSE); doc.rect(gx + 1.5, baseY - eh, barW, eh, "F");
    doc.setFontSize(7.5); doc.setTextColor(...MUTED);
    doc.text(m.label, gx, baseY + 11, { align: "center" });
  });

  // legend
  let lx = x;
  const ly = baseY + 24;
  const legend: [string, RGB][] = [["Income", INCOME], ["Expenses", EXPENSE]];
  doc.setFontSize(8);
  legend.forEach(([label, color]) => {
    doc.setFillColor(...color); doc.rect(lx, ly - 6, 8, 8, "F");
    doc.setTextColor(...TEXT); doc.text(label, lx + 12, ly, { baseline: "alphabetic" });
    lx += 14 + doc.getTextWidth(label) + 18;
  });
}

/** Native (vector) donut chart + legend for top expense categories. */
function drawDonut(doc: jsPDF, cx: number, cy: number, r: number, items: DashboardPdfData["topExpenses"], currency: string) {
  const total = items.reduce((s, it) => s + Math.abs(it.value), 0);
  if (total <= 0) {
    doc.setFontSize(9); doc.setTextColor(...MUTED);
    doc.text("No expense data", cx, cy, { align: "center" });
    return;
  }
  let a = -Math.PI / 2; // start at top
  items.forEach((it, idx) => {
    const frac = Math.abs(it.value) / total;
    const a1 = a + frac * Math.PI * 2;
    const seg = Math.max(2, Math.ceil(frac * 80));
    const pts: [number, number][] = [[cx, cy]];
    for (let i = 0; i <= seg; i++) {
      const ang = a + (a1 - a) * (i / seg);
      pts.push([cx + r * Math.cos(ang), cy + r * Math.sin(ang)]);
    }
    const deltas = pts.slice(1).map((p, i) => [p[0] - pts[i][0], p[1] - pts[i][1]] as [number, number]);
    doc.setFillColor(...DONUT[idx % DONUT.length]);
    doc.lines(deltas, pts[0][0], pts[0][1], [1, 1], "F", true);
    a = a1;
  });
  // hollow center → donut
  doc.setFillColor(255, 255, 255);
  doc.circle(cx, cy, r * 0.55, "F");

  // legend below
  let ly = cy + r + 16;
  doc.setFontSize(7.5);
  items.forEach((it, idx) => {
    doc.setFillColor(...DONUT[idx % DONUT.length]); doc.rect(cx - r, ly - 6, 7, 7, "F");
    doc.setTextColor(...TEXT);
    const label = it.name.length > 26 ? it.name.slice(0, 25) + "…" : it.name;
    doc.text(`${label}  ${money(it.value, currency)}`, cx - r + 11, ly);
    ly += 12;
  });
}

export async function generateDashboardPdf(opts: {
  companyName: string;
  logoUrl?: string | null;
  currency?: string;
  data: DashboardPdfData;
  rangeLabel?: string;
}) {
  const { companyName, data } = opts;
  const currency = opts.currency || "USD";
  const doc = new jsPDF({ unit: "pt", format: "letter" });
  const W = doc.internal.pageSize.getWidth();
  const ML = 40;
  const contentW = W - ML * 2;

  const logo = await loadBrandedLogo(opts.logoUrl);
  let y = drawBrandedHeader(doc, {
    logo,
    title: "Financial Overview",
    metaLines: [
      { label: "Properties:", value: companyName },
      ...(opts.rangeLabel ? [{ label: "Period:", value: opts.rangeLabel }] : []),
    ],
  });

  // ── Summary cards ──
  const cards: [string, number][] = [
    ["Total Receivables", data.totalReceivable],
    ["Total Payables", data.totalPayable],
    ["Bank Balance", data.cash],
  ];
  const gap = 12;
  const cardW = (contentW - gap * 2) / 3;
  const cardH = 48;
  cards.forEach(([label, val], i) => {
    const cx = ML + i * (cardW + gap);
    doc.setDrawColor(220); doc.setFillColor(249, 250, 251); doc.setLineWidth(0.5);
    doc.roundedRect(cx, y, cardW, cardH, 4, 4, "FD");
    doc.setFont("helvetica", "normal"); doc.setFontSize(8.5); doc.setTextColor(...MUTED);
    doc.text(label.toUpperCase(), cx + 10, y + 16);
    doc.setFont("helvetica", "bold"); doc.setFontSize(14); doc.setTextColor(...TEXT);
    doc.text(money(val, currency), cx + 10, y + 36);
  });
  y += cardH + 28;

  // ── Charts row: bar chart (left) + donut (right) ──
  doc.setFont("helvetica", "bold"); doc.setFontSize(11); doc.setTextColor(...TEXT);
  doc.text("Income & Expenses", ML, y);
  doc.text("Top Expenses", ML + contentW * 0.62 + 10, y);
  doc.setFont("helvetica", "normal"); doc.setFontSize(8); doc.setTextColor(...MUTED);
  doc.text("Last 6 months", ML, y + 12);
  doc.text("By category", ML + contentW * 0.62 + 10, y + 12);
  y += 24;

  const barW = contentW * 0.55;
  drawBarChart(doc, ML + 26, y, barW, 150, data.months, currency);
  const donutCx = ML + contentW * 0.62 + 10 + (contentW * 0.34) / 2;
  drawDonut(doc, donutCx, y + 60, 52, data.topExpenses, currency);

  // advance past the taller of the two blocks (chart ~150 + legend, donut + legend)
  y += 150 + 30 + Math.max(0, (data.topExpenses.length - 3)) * 12;

  // ── Invoices overview ──
  doc.setFont("helvetica", "bold"); doc.setFontSize(11); doc.setTextColor(...TEXT);
  doc.text("Invoices Overview", ML, y);
  y += 12;
  const tiles: [string, number][] = [
    ["Draft", data.counts.draft], ["Sent", data.counts.sent],
    ["Overdue", data.counts.overdue], ["Paid", data.counts.paid],
  ];
  const tileW = (contentW - gap * 3) / 4;
  tiles.forEach(([label, val], i) => {
    const tx = ML + i * (tileW + gap);
    doc.setDrawColor(220); doc.setFillColor(255, 255, 255); doc.setLineWidth(0.5);
    doc.roundedRect(tx, y, tileW, 34, 4, 4, "FD");
    doc.setFont("helvetica", "normal"); doc.setFontSize(8); doc.setTextColor(...MUTED);
    doc.text(label, tx + 8, y + 14);
    doc.setFont("helvetica", "bold"); doc.setFontSize(13); doc.setTextColor(...TEXT);
    doc.text(String(val), tx + 8, y + 28);
  });
  y += 34 + 24;

  // ── Recent transactions ──
  doc.setFont("helvetica", "bold"); doc.setFontSize(11); doc.setTextColor(...TEXT);
  doc.text("Recent Transactions", ML, y);
  y += 6;
  autoTable(doc, {
    startY: y + 4,
    margin: { left: ML, right: ML },
    head: [["Date", "Description", "Category", "Reference", "Amount"]],
    body: (data.recent ?? []).map((t) => [
      t.date ? fmtDate(t.date) : "",
      t.description ?? "",
      t.category ?? "—",
      t.reference ?? "—",
      `${t.type === "credit" ? "+" : "-"}${money(Math.abs(Number(t.amount || 0)), currency)}`,
    ]),
    styles: { font: "helvetica", fontSize: 8, textColor: TEXT, lineColor: [225, 228, 232], lineWidth: 0.1 },
    headStyles: { fillColor: [237, 239, 242], textColor: TEXT, fontStyle: "bold" },
    columnStyles: { 4: { halign: "right" } },
  });

  drawBrandedFooter(doc);
  doc.save(`accounting-dashboard-${new Date().toISOString().slice(0, 10)}.pdf`);
}
