// pages-income-statement-v2.jsx
// ─────────────────────────────────────────────────────────────────────────────
// Rebuilt Income Statement — multi-column financial statement matching the
// reference-dashboard design language. Reads 100% from data.txns (already
// loaded by data-live.js); the backend is untouched.
//
// Registers window.IncomeStatementV2Page. NOT yet wired into app.html — built
// alongside the existing window.IncomeStatementPage (pages-finance.jsx) so it
// can be verified before swapping in.
//
// Design checklist covered here (page-level pieces):
//   • Period selector: Monthly | Quarter | YTD | LTM | Full Year + year buttons
//   • Excel (CSV) + PDF (print) export, AI Analyse button — top right
//   • KPI strip: Revenue | COGS | Gross Profit | Gross Margin % | OpEx | EBITDA | Net Income
//   • Multi-column table: Code | Description | <13 months> | YTD | PY | Variance | Var %
//   • Collapsible section headers (Revenue / COGS / Operating Expenses)
//   • Computed rows: Total Revenue, Total COGS, Gross Profit (+margin),
//     Total OpEx, EBITDA (+margin), Net Income (+margin)
//   • Account codes from account_code (or generated e001, e002… sequentially)
//   • Inline SVG sparkline per account row
//   • Every value row clickable → window.openAccountDetail({ name, category })
//   • Health badges (Healthy / Watch / Critical) on margin KPI tiles
//   • Negatives in red, positive margins in teal
//
// The "dark top tab nav" is a shell-level concern (src/shell.jsx) and is left
// untouched here.
// ─────────────────────────────────────────────────────────────────────────────
(function () {
  const h = React.createElement;
  const { useState, useMemo } = React;

  // ── Palette (matches reference look; independent of the app theme tokens) ──
  const C = {
    navy:      "#0d2040",
    navySoft:  "#16315c",
    teal:      "#0f9b8e",
    red:       "#c0392b",
    text:      "#1c2b45",
    text2:     "#5b6b83",
    border:    "#e4e9f2",
    rowAlt:    "#f7f9fc",
    rowHover:  "#eef4ff",
    highlight: "#eef6f5",   // gross profit / ebitda / net income rows
    white:     "#ffffff",
    chipBg:    "#1c4ed8",
  };

  const HEALTH = {
    Healthy:  { bg: "#e6f7f0", fg: "#0f8a52" },
    Watch:    { bg: "#fff5e0", fg: "#b9770a" },
    Critical: { bg: "#fdecea", fg: "#c0392b" },
  };

  // ── canonical_category → P&L bucket. Mirrors data-live.js so section totals
  // reconcile exactly to data.pl / the KPI strip. ──────────────────────────
  const LEGACY_BUCKET = {
    Revenue: "revenue", COGS: "cogs", Opex: "opex", AR: "ar", AP: "ap", Cash: "cash",
    "Contra-revenue": "revenue", "Interest Expense": "opex", "Interest Income": "revenue",
    "Tax Expense": "opex", "Other Income/Expense": "opex",
  };
  const SECTION_BUCKET = {
    revenue: "revenue", contra_revenue: "revenue", other_income: "revenue",
    cogs: "cogs",
    opex: "opex", da: "opex", other_op_exp: "opex", interest: "opex", tax: "opex", other_expense: "opex",
  };
  function bucketForCategory(category, profile) {
    if (!category) return null;
    if (LEGACY_BUCKET[category]) return LEGACY_BUCKET[category];
    const tax = window.PerduraTaxonomy;
    if (!tax || !tax.sectionForCategory) return null;
    const sec = tax.sectionForCategory(category, profile);
    return SECTION_BUCKET[sec] || null; // current_assets / liabilities / equity → null (not P&L)
  }

  // ── Section definitions, in statement order ───────────────────────────────
  const SECTIONS = [
    { key: "revenue", title: "REVENUE",            totalLabel: "TOTAL REVENUE" },
    { key: "cogs",    title: "COST OF GOODS SOLD", totalLabel: "TOTAL COGS" },
    { key: "opex",    title: "OPERATING EXPENSES", totalLabel: "TOTAL OPEX" },
  ];

  const MONTH_ABBR = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];

  // ── Fiscal-year helper. Reads profile.fiscal_year_start_month (1–12); default
  // January. fyStartIdx is 0-based. A month belongs to FY{Y} where Y is the
  // calendar year in which that fiscal year ENDS. ───────────────────────────
  function makeFiscalFns(profile) {
    const fyStart = Number(profile?.fiscal_year_start_month) || 1; // 1–12
    const fyStartIdx = fyStart - 1;
    const fyOf = (year, monthIdx) => {
      if (fyStartIdx === 0) return year;             // Jan-start → FY == calendar year
      return monthIdx >= fyStartIdx ? year + 1 : year;
    };
    return { fyStart, fyStartIdx, fyOf };
  }

  // ── Small inline sparkline ─────────────────────────────────────────────────
  function Sparkline({ series, color }) {
    const vals = (series || []).map(v => Math.abs(Number(v) || 0));
    if (vals.length < 2 || Math.max(...vals) === 0) {
      return h("span", { style: { color: C.border, fontSize: 10 } }, "—");
    }
    const w = 64, ht = 18, max = Math.max(...vals), min = Math.min(...vals);
    const span = max - min || 1;
    const pts = vals.map((v, i) => {
      const x = (i / (vals.length - 1)) * (w - 2) + 1;
      const y = ht - 2 - ((v - min) / span) * (ht - 4);
      return `${x.toFixed(1)},${y.toFixed(1)}`;
    }).join(" ");
    return h("svg", { width: w, height: ht, style: { display: "block" } },
      h("polyline", { points: pts, fill: "none", stroke: color || C.teal, strokeWidth: 1.5,
        strokeLinejoin: "round", strokeLinecap: "round" })
    );
  }

  // ── Main page ──────────────────────────────────────────────────────────────
  function IncomeStatementV2Page({ data, companyProfile }) {
    const F = window.PerduraFormat || { money: (v) => "R" + Math.round(v).toLocaleString(), pct: (v) => v.toFixed(1) + "%" };
    const profile = companyProfile || data?.companyProfile || null;
    const { fyOf } = makeFiscalFns(profile);

    const [collapsed, setCollapsed] = useState({});       // { sectionKey: true }
    const [periodMode, setPeriodMode] = useState("Monthly"); // Monthly|Quarter|YTD|LTM|Full Year
    const [yearFilter, setYearFilter] = useState(null);    // calendar year or null

    // ── Aggregate txns → per-account monthly series (unbounded by window so
    // YTD/PY are accurate). Keyed by bucket → account. ───────────────────────
    const model = useMemo(() => {
      const txns = data?.txns || [];
      const tax = window.PerduraTaxonomy;
      const inferCache = new Map();
      const inferCat = (tx) => {
        const k = (tx.account_code || "") + "|" + (tx.account_name || "");
        if (inferCache.has(k)) return inferCache.get(k);
        let cat = null;
        if (tax && tax.classifyByName) {
          const amt = Number(tx.amount) || 0;
          cat = tax.classifyByName(tx.account_name, { code: tx.account_code, hint: amt < 0 ? "expense" : "revenue", profile });
        }
        inferCache.set(k, cat);
        return cat;
      };

      // bucket -> accountKey -> { code, name, cat, byYM: Map(yyyymm -> signedSum) }
      const buckets = { revenue: {}, cogs: {}, opex: {} };
      const allYM = new Set();

      txns.forEach(tx => {
        let cat = tx.canonical_category;
        if (!cat || cat === "Unclassified / Suspense") {
          const inf = inferCat(tx);
          if (inf && inf !== "Unclassified / Suspense") cat = inf;
        }
        const bucket = bucketForCategory(cat, profile);
        if (!bucket || !buckets[bucket]) return;

        const d = new Date(tx.posted_date);
        if (isNaN(d.getTime())) return;
        const yyyymm = d.getFullYear() * 100 + (d.getMonth() + 1);
        allYM.add(yyyymm);

        const name = tx.account_name || tx.account_code || "(unnamed)";
        const key = (tx.account_code || "") + "|" + name;
        const acct = buckets[bucket][key] || (buckets[bucket][key] = {
          code: tx.account_code || null, name, cat: cat || null, byYM: new Map(),
        });
        acct.byYM.set(yyyymm, (acct.byYM.get(yyyymm) || 0) + (Number(tx.amount) || 0));
      });

      // Sorted month list (yyyymm) across all data.
      const months = Array.from(allYM).sort((a, b) => a - b).map(ym => ({
        yyyymm: ym,
        year: Math.floor(ym / 100),
        monthIdx: (ym % 100) - 1,
        label: MONTH_ABBR[(ym % 100) - 1],
      }));

      // Assign display codes: real account_code wins; otherwise generate eNNN
      // sequentially in statement order.
      let gen = 0;
      const sections = SECTIONS.map(sec => {
        const accts = Object.values(buckets[sec.key])
          .map(a => {
            const total = Array.from(a.byYM.values()).reduce((s, v) => s + v, 0);
            return { ...a, totalSigned: total };
          })
          .sort((a, b) => Math.abs(b.totalSigned) - Math.abs(a.totalSigned));
        accts.forEach(a => {
          if (!a.code) a.code = "e" + String(++gen).padStart(3, "0");
          else gen++; // keep the sequence advancing so generated codes stay unique-ish
        });
        return { ...sec, accounts: accts };
      });

      return { months, sections };
    }, [data, profile]);

    if (!data?.txns?.length) {
      return h("div", { style: { padding: 40, color: C.text2, fontSize: 14 } },
        "No transactions loaded yet — connect a data source under Settings → Configuration.");
    }

    // ── Resolve the visible month columns from the period selector ────────────
    const allMonths = model.months;
    const latest = allMonths[allMonths.length - 1];
    const currentFY = latest ? fyOf(latest.year, latest.monthIdx) : null;

    let visMonths = allMonths;
    if (yearFilter != null) {
      visMonths = allMonths.filter(m => fyOf(m.year, m.monthIdx) === yearFilter);
    } else if (periodMode === "Monthly") {
      visMonths = allMonths.slice(-13);
    } else if (periodMode === "Quarter") {
      visMonths = allMonths.slice(-3);
    } else if (periodMode === "LTM" || periodMode === "Full Year") {
      visMonths = allMonths.slice(-12);
    } else if (periodMode === "YTD") {
      visMonths = allMonths.filter(m => fyOf(m.year, m.monthIdx) === currentFY);
    }
    if (!visMonths.length) visMonths = allMonths.slice(-13);

    const fyLabel = currentFY != null ? `FY${currentFY}` : "";
    const pyLabel = currentFY != null ? `FY${currentFY - 1}` : "";

    // YTD = current fiscal year months; PY = prior fiscal year months.
    const ytdMonths = new Set(allMonths.filter(m => fyOf(m.year, m.monthIdx) === currentFY).map(m => m.yyyymm));
    const pyMonths  = new Set(allMonths.filter(m => fyOf(m.year, m.monthIdx) === currentFY - 1).map(m => m.yyyymm));

    // ── Per-row value helpers ─────────────────────────────────────────────────
    const valAt = (acct, yyyymm) => Math.abs(acct.byYM.get(yyyymm) || 0);
    const sumOver = (acct, ymSet) => {
      let s = 0; acct.byYM.forEach((v, ym) => { if (ymSet.has(ym)) s += v; }); return Math.abs(s);
    };
    const sparkSeries = (acct) => allMonths.slice(-13).map(m => valAt(acct, m.yyyymm));

    // Section totals across the visible months + YTD/PY.
    const sectionTotals = {};
    model.sections.forEach(sec => {
      const monthly = visMonths.map(m => sec.accounts.reduce((s, a) => s + valAt(a, m.yyyymm), 0));
      const ytd = sec.accounts.reduce((s, a) => s + sumOver(a, ytdMonths), 0);
      const py  = sec.accounts.reduce((s, a) => s + sumOver(a, pyMonths), 0);
      sectionTotals[sec.key] = { monthly, ytd, py };
    });

    const rev = sectionTotals.revenue, cogs = sectionTotals.cogs, opex = sectionTotals.opex;
    const seriesDiff = (a, b) => a.map((v, i) => v - (b[i] || 0));
    const gpMonthly  = seriesDiff(rev.monthly, cogs.monthly);
    const ebitMonthly = gpMonthly.map((v, i) => v - (opex.monthly[i] || 0));
    const gpYtd = rev.ytd - cogs.ytd, gpPy = rev.py - cogs.py;
    const ebitYtd = gpYtd - opex.ytd, ebitPy = gpPy - opex.py;
    // Net Income ≡ EBITDA in the live rollup (interest/tax/D&A fold into opex).
    const niYtd = ebitYtd, niPy = ebitPy, niMonthly = ebitMonthly;

    const pctOf = (n, d) => (!d ? 0 : (n / d) * 100);

    // ── Formatting ─────────────────────────────────────────────────────────────
    const money = (v, compact) => F.money(Math.abs(v), { compact: !!compact }) ;
    const cell = (v, { bold, compact, allowNeg } = {}) => {
      const neg = v < 0;
      return h("td", {
        style: {
          padding: "7px 12px", textAlign: "right", whiteSpace: "nowrap",
          fontVariantNumeric: "tabular-nums", fontSize: 12.5,
          fontWeight: bold ? 700 : 500,
          color: (allowNeg && neg) ? C.red : C.text,
        },
      }, (v < 0 ? "(" : "") + money(v, compact) + (v < 0 ? ")" : ""));
    };
    const pctCell = (p, { bold } = {}) => h("td", {
      style: { padding: "7px 12px", textAlign: "right", fontVariantNumeric: "tabular-nums",
        fontSize: 12.5, fontWeight: bold ? 700 : 600, color: p < 0 ? C.red : C.teal },
    }, F.pct(p));

    // ── Export: CSV (Excel) ────────────────────────────────────────────────────
    const exportCSV = () => {
      const head = ["Code", "Description", ...visMonths.map(m => `${m.label} ${String(m.year).slice(2)}`),
        `YTD ${fyLabel}`, `PY ${pyLabel}`, "Variance", "Var %"];
      const rows = [head];
      const pushAcct = (a) => rows.push([
        a.code, a.name,
        ...visMonths.map(m => valAt(a, m.yyyymm)),
        sumOver(a, ytdMonths), sumOver(a, pyMonths),
        sumOver(a, ytdMonths) - sumOver(a, pyMonths),
        pctOf(sumOver(a, ytdMonths) - sumOver(a, pyMonths), sumOver(a, pyMonths)).toFixed(1),
      ]);
      const pushTotal = (label, monthly, ytd, py) => rows.push([
        "", label, ...monthly, ytd, py, ytd - py, pctOf(ytd - py, py).toFixed(1),
      ]);
      model.sections.forEach(sec => {
        rows.push(["", sec.title]);
        sec.accounts.forEach(pushAcct);
        const t = sectionTotals[sec.key];
        pushTotal(sec.totalLabel, t.monthly, t.ytd, t.py);
        if (sec.key === "cogs") pushTotal("GROSS PROFIT", gpMonthly, gpYtd, gpPy);
        if (sec.key === "opex") {
          pushTotal("EBITDA", ebitMonthly, ebitYtd, ebitPy);
          pushTotal("NET INCOME", niMonthly, niYtd, niPy);
        }
      });
      const csv = rows.map(r => r.map(c => {
        const s = String(c == null ? "" : c);
        return /[",\n]/.test(s) ? '"' + s.replace(/"/g, '""') + '"' : s;
      }).join(",")).join("\n");
      const blob = new Blob([csv], { type: "text/csv;charset=utf-8;" });
      const url = URL.createObjectURL(blob);
      const a = document.createElement("a");
      a.href = url; a.download = `income-statement-${fyLabel || "export"}.csv`;
      document.body.appendChild(a); a.click(); document.body.removeChild(a);
      URL.revokeObjectURL(url);
    };

    const exportPDF = () => window.print();

    const runAI = () => {
      // Hook into whatever AI entry point exists; degrade gracefully otherwise.
      if (typeof window.openAIAnalyse === "function") {
        window.openAIAnalyse({ page: "income_statement", title: "Income Statement" });
      } else if (typeof window.__perduraSetPage === "function") {
        window.__perduraSetPage("cfo_briefings");
      } else {
        alert("AI analysis is available when an ANTHROPIC_API_KEY is configured for this workspace.");
      }
    };

    // ── Drill-through ───────────────────────────────────────────────────────────
    const drill = (acct) => window.openAccountDetail &&
      window.openAccountDetail({ name: acct.name, category: acct.cat || undefined, page: "income-statement" });

    // ── Render helpers ──────────────────────────────────────────────────────────
    const th = (label, opts = {}) => h("th", {
      style: {
        padding: "9px 12px", textAlign: opts.left ? "left" : "right", whiteSpace: "nowrap",
        fontSize: 10.5, fontWeight: 700, letterSpacing: ".04em", textTransform: "uppercase",
        color: "rgba(255,255,255,.82)", position: "sticky", top: 0, background: C.navy,
        ...(opts.style || {}),
      },
    }, label);

    const variance = (ytd, py) => {
      const v = ytd - py, p = pctOf(v, py);
      return [
        h("td", { key: "v", style: { padding: "7px 12px", textAlign: "right", fontVariantNumeric: "tabular-nums",
          fontSize: 12.5, fontWeight: 600, color: v < 0 ? C.red : C.teal } },
          (v < 0 ? "(" : "") + money(v) + (v < 0 ? ")" : "")),
        h("td", { key: "p", style: { padding: "7px 12px", textAlign: "right", fontVariantNumeric: "tabular-nums",
          fontSize: 12.5, fontWeight: 600, color: p < 0 ? C.red : C.teal } }, F.pct(p)),
      ];
    };

    const totalRow = (label, monthly, ytd, py, { highlight, isPct, denom } = {}) => {
      if (isPct) {
        const monthsRev = sectionTotals.revenue.monthly;
        return h("tr", { key: label, style: { background: C.highlight } },
          h("td", { style: { padding: "6px 12px", fontSize: 11.5, fontWeight: 700, color: C.teal, letterSpacing: ".02em" }, colSpan: 2 }, label),
          h("td", { style: { padding: 0 } }),
          ...monthly.map((v, i) => pctCell(pctOf(v, monthsRev[i]))),
          pctCell(pctOf(ytd, denom.ytd), { bold: true }),
          pctCell(pctOf(py, denom.py), { bold: true }),
          h("td", null), h("td", null),
        );
      }
      return h("tr", { key: label, style: { background: highlight ? C.highlight : "#eef1f6", borderTop: `1px solid ${C.border}` } },
        h("td", { style: { padding: "8px 12px", fontSize: 12, fontWeight: 800, color: C.navy, letterSpacing: ".02em" }, colSpan: 2 }, label),
        h("td", { style: { padding: 0 } }),
        ...monthly.map((v, i) => cell(v, { bold: true, compact: true, allowNeg: true, key: i })),
        cell(ytd, { bold: true }),
        cell(py, { bold: true }),
        ...variance(ytd, py),
      );
    };

    const colCount = 3 + visMonths.length + 4;

    const sectionRows = model.sections.flatMap(sec => {
      const isCollapsed = !!collapsed[sec.key];
      const t = sectionTotals[sec.key];
      const rows = [];
      // Section header (collapsible)
      rows.push(h("tr", { key: "h-" + sec.key, onClick: () => setCollapsed(c => ({ ...c, [sec.key]: !c[sec.key] })),
        style: { cursor: "pointer", background: C.navy } },
        h("td", { colSpan: colCount, style: { padding: "8px 12px", color: C.white, fontWeight: 700,
          fontSize: 11.5, letterSpacing: ".06em" } },
          h("span", { style: { display: "inline-block", width: 14, color: "rgba(255,255,255,.7)" } }, isCollapsed ? "▸" : "▾"),
          sec.title)));
      // Account rows
      if (!isCollapsed) {
        sec.accounts.forEach((a, i) => {
          const ytd = sumOver(a, ytdMonths), py = sumOver(a, pyMonths);
          rows.push(h("tr", {
            key: "a-" + sec.key + "-" + i,
            onClick: () => drill(a),
            title: "View account detail",
            style: { cursor: "pointer", background: i % 2 ? C.rowAlt : C.white },
            onMouseEnter: (e) => { e.currentTarget.style.background = C.rowHover; },
            onMouseLeave: (e) => { e.currentTarget.style.background = i % 2 ? C.rowAlt : C.white; },
          },
            h("td", { style: { padding: "7px 12px", fontSize: 11.5, color: C.text2, fontFamily: "ui-monospace,Menlo,monospace", whiteSpace: "nowrap" } }, a.code),
            h("td", { style: { padding: "7px 12px", fontSize: 12.5, color: C.text, fontWeight: 500, whiteSpace: "nowrap", maxWidth: 280, overflow: "hidden", textOverflow: "ellipsis" } }, a.name),
            h("td", { style: { padding: "4px 8px" } }, h(Sparkline, { series: sparkSeries(a), color: sec.key === "revenue" ? C.teal : C.navySoft })),
            ...visMonths.map((m, mi) => cell(valAt(a, m.yyyymm), { compact: true, key: mi })),
            cell(ytd),
            cell(py),
            ...variance(ytd, py),
          ));
        });
        // Section total
        rows.push(totalRow(sec.totalLabel, t.monthly, t.ytd, t.py));
      }
      // Computed rows after their section
      if (sec.key === "cogs") {
        rows.push(totalRow("GROSS PROFIT", gpMonthly, gpYtd, gpPy, { highlight: true }));
        rows.push(totalRow("GROSS MARGIN %", gpMonthly, gpYtd, gpPy, { isPct: true, denom: { ytd: rev.ytd, py: rev.py } }));
      }
      if (sec.key === "opex") {
        rows.push(totalRow("EBITDA", ebitMonthly, ebitYtd, ebitPy, { highlight: true }));
        rows.push(totalRow("EBITDA MARGIN %", ebitMonthly, ebitYtd, ebitPy, { isPct: true, denom: { ytd: rev.ytd, py: rev.py } }));
        rows.push(totalRow("NET INCOME", niMonthly, niYtd, niPy, { highlight: true }));
        rows.push(totalRow("NET MARGIN %", niMonthly, niYtd, niPy, { isPct: true, denom: { ytd: rev.ytd, py: rev.py } }));
      }
      return rows;
    });

    // ── KPI strip ───────────────────────────────────────────────────────────────
    const gmPct = pctOf(gpYtd, rev.ytd), emPct = pctOf(ebitYtd, rev.ytd), nmPct = pctOf(niYtd, rev.ytd);
    const marginHealth = (p, watch, crit) => p >= watch ? "Healthy" : p >= crit ? "Watch" : "Critical";
    const nav = (key) => () => window.__perduraSetPage && window.__perduraSetPage(key);
    const kpis = [
      { label: "Total Revenue", value: money(rev.ytd, true), onClick: () => drill({ name: "Revenue", cat: "Revenue" }) },
      { label: "Total COGS", value: money(cogs.ytd, true), onClick: () => drill({ name: "Cost of Goods Sold", cat: "COGS" }) },
      { label: "Gross Profit", value: money(gpYtd, true), onClick: () => drill({ name: "Gross Profit" }) },
      { label: "Gross Margin %", value: F.pct(gmPct), teal: true, health: marginHealth(gmPct, 25, 12), onClick: nav("margin") },
      { label: "Total OpEx", value: money(opex.ytd, true), onClick: nav("opex_intelligence") },
      { label: "EBITDA", value: money(ebitYtd, true), onClick: nav("margin") },
      { label: "Net Income", value: money(niYtd, true), teal: niYtd >= 0, health: marginHealth(nmPct, 8, 0), onClick: () => drill({ name: "Net Income" }) },
    ];

    const kpiTile = (k, i) => h("div", { key: i, onClick: k.onClick || undefined, title: k.onClick ? "Click to drill in" : undefined, style: {
      flex: "1 1 140px", minWidth: 130, background: C.white, border: `1px solid ${C.border}`,
      borderRadius: 10, padding: "12px 14px", boxShadow: "0 1px 2px rgba(13,32,64,.04)", cursor: k.onClick ? "pointer" : "default",
    } },
      h("div", { style: { fontSize: 10.5, fontWeight: 700, letterSpacing: ".05em", textTransform: "uppercase", color: C.text2, marginBottom: 6 } }, k.label),
      h("div", { style: { fontSize: 19, fontWeight: 800, color: k.teal ? C.teal : C.navy, fontVariantNumeric: "tabular-nums" } }, k.value),
      k.health ? h("div", { style: { marginTop: 6, display: "inline-block", fontSize: 10, fontWeight: 700,
        padding: "2px 8px", borderRadius: 99, background: HEALTH[k.health].bg, color: HEALTH[k.health].fg } }, k.health) : null,
    );

    // ── Period selector ───────────────────────────────────────────────────────
    const modes = ["Monthly", "Quarter", "YTD", "LTM", "Full Year"];
    const years = Array.from(new Set(allMonths.map(m => fyOf(m.year, m.monthIdx)))).sort();
    const segBtn = (label, active, onClick) => h("button", {
      key: label, onClick,
      style: {
        padding: "5px 12px", fontSize: 12, fontWeight: 600, cursor: "pointer",
        border: `1px solid ${active ? C.navy : C.border}`, borderRadius: 7,
        background: active ? C.navy : C.white, color: active ? C.white : C.text2,
      },
    }, label);

    const topBtn = (label, onClick, primary) => h("button", {
      key: label, onClick,
      style: {
        padding: "7px 14px", fontSize: 12.5, fontWeight: 700, cursor: "pointer",
        border: `1px solid ${primary ? C.chipBg : C.border}`, borderRadius: 8,
        background: primary ? C.chipBg : C.white, color: primary ? C.white : C.text,
      },
    }, label);

    return h("div", { style: { padding: "20px 24px", background: "#fbfcfe", minHeight: "100%" } },
      // Title row + export / AI buttons
      h("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "flex-start", flexWrap: "wrap", gap: 12, marginBottom: 14 } },
        h("div", null,
          h("div", { style: { fontSize: 22, fontWeight: 800, color: C.navy } }, "Income Statement"),
          h("div", { style: { fontSize: 13, color: C.text2, marginTop: 3 } }, `YTD ${fyLabel} · Click any row to drill down`),
        ),
        h("div", { style: { display: "flex", gap: 8 } },
          topBtn("Excel", exportCSV),
          topBtn("PDF", exportPDF),
          topBtn("AI Analyse", runAI, true),
        ),
      ),

      // Period selector
      h("div", { style: { display: "flex", gap: 14, alignItems: "center", flexWrap: "wrap", marginBottom: 16 } },
        h("div", { style: { display: "flex", gap: 6 } }, modes.map(m => segBtn(m, periodMode === m && yearFilter == null, () => { setPeriodMode(m); setYearFilter(null); }))),
        h("div", { style: { width: 1, height: 22, background: C.border } }),
        h("div", { style: { display: "flex", gap: 6 } }, years.map(y => segBtn(String(y), yearFilter === y, () => setYearFilter(yearFilter === y ? null : y)))),
      ),

      // KPI strip
      h("div", { style: { display: "flex", gap: 10, flexWrap: "wrap", marginBottom: 18 } }, kpis.map(kpiTile)),

      // Statement table
      h("div", { style: { background: C.white, border: `1px solid ${C.border}`, borderRadius: 12, overflow: "hidden" } },
        h("div", { style: { overflowX: "auto" } },
          h("table", { style: { width: "100%", borderCollapse: "collapse", minWidth: 720 } },
            h("thead", null,
              h("tr", null,
                th("Code", { left: true }),
                th("Description", { left: true }),
                th("Trend", { left: true }),
                ...visMonths.map(m => th(`${m.label} ${String(m.year).slice(2)}`)),
                th(`YTD ${fyLabel}`),
                th(`PY ${pyLabel}`),
                th("Variance"),
                th("Var %"),
              ),
            ),
            h("tbody", null, sectionRows),
          ),
        ),
      ),

      h("div", { style: { marginTop: 10, fontSize: 11, color: C.text2 } },
        "Net Income equals EBITDA in this view — interest, tax and depreciation roll into operating expenses in the live ledger rollup. Section totals reconcile to the KPI strip and the Financial Overview."),
    );
  }

  // Primary name + alias. The rebuild plan references window.IncomeStatementV2;
  // app.jsx wiring may reference either, so expose both to the same component.
  Object.assign(window, { IncomeStatementV2Page, IncomeStatementV2: IncomeStatementV2Page });
})();
