// dashboard-v2.jsx
// ─────────────────────────────────────────────────────────────────────────────
// V2 dashboard matching the PerduraCEO layout: KPI grid, revenue/expense trend
// bars, revenue & expense mix, margin trend, top sources / top expense lines.
// Registers window.DashboardV2. Rendered only under the V2 shell (?v2shell=1).
//
// Reads the ACTUAL data shape:
//   • data.plHistory = { labels[], years[], revenue[], cogs[], opex[], gp[], ebitda[] }
//     (no gross_profit / operating_expenses / net_income — gp = gross profit,
//      ebitda = bottom line / "net surplus")
//   • data.txns bucketed via PerduraTaxonomy.sectionForCategory (same mapping as
//     data-live.js), NOT canonical_category substring matching.
// Currency comes from PerduraFormat (R for ZAR, etc.). InsightsPanel is injected
// once at the shell level, so it is intentionally NOT rendered here.
// ─────────────────────────────────────────────────────────────────────────────
(function () {
  const h = React.createElement;
  const { useMemo } = React;

  // canonical_category → P&L bucket (mirrors data-live.js / pages-income-statement-v2).
  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;
    return SECTION_BUCKET[tax.sectionForCategory(category, profile)] || null;
  }

  const DOT = ["#00b894", "#1C4ED8", "#f59e0b", "#e74c3c", "#8b5cf6"];

  function DashboardV2({ data, companyProfile, setPage }) {
    const profile = companyProfile || data?.companyProfile || {};
    const plH = data?.plHistory || data?.pl || {};
    const txns = data?.txns || [];
    const F = window.PerduraFormat;
    const go = (k) => (typeof setPage === "function" ? setPage(k) : (window.__perduraSetPage && window.__perduraSetPage(k)));

    const money = (v) => F ? F.money(Math.abs(v), { compact: true }) : "$" + Math.round(Math.abs(v)).toLocaleString();
    const pctTxt = (v) => (v == null ? "—" : v.toFixed(1) + "%");

    const last = (arr) => (Array.isArray(arr) ? arr[arr.length - 1] : 0) || 0;
    const prev = (arr) => (Array.isArray(arr) ? arr[arr.length - 2] : 0) || 0;

    const rev = last(plH.revenue), prevRev = prev(plH.revenue);
    const revChg = prevRev > 0 ? ((rev - prevRev) / prevRev * 100) : null;
    const cogs = last(plH.cogs);
    const opex = last(plH.opex), prevOpex = prev(plH.opex);
    const opexChg = prevOpex > 0 ? ((opex - prevOpex) / prevOpex * 100) : null;
    const totalExp = cogs + opex;
    const gp = last(plH.gp);
    const ni = last(plH.ebitda), prevNi = prev(plH.ebitda); // NI ≡ EBITDA in this rollup
    const niChg = prevNi !== 0 ? ((ni - prevNi) / Math.abs(prevNi) * 100) : null;

    const gpMargin = rev > 0 ? (gp / rev * 100) : null;
    const niMargin = rev > 0 ? (ni / rev * 100) : null;
    const opexRatio = rev > 0 ? (opex / rev * 100) : null;

    const kpis = [
      { label: "Total Revenue",    value: money(rev),     change: revChg,  color: "#1a2540", nav: "revenue_intelligence" },
      { label: "Total Expenses",   value: money(totalExp), change: opexChg, color: "#e74c3c", invertColor: true, nav: "opex_intelligence" },
      { label: "Gross Profit",     value: money(gp),      change: null,    color: gp >= 0 ? "#00b894" : "#e74c3c", nav: "income_statement" },
      { label: "Net Surplus",      value: money(ni),      change: niChg,   color: ni >= 0 ? "#00b894" : "#e74c3c", nav: "income_statement" },
      { label: "Gross Margin",     value: pctTxt(gpMargin), change: null,  color: (gpMargin || 0) > 30 ? "#00b894" : "#f59e0b", nav: "income_statement" },
      { label: "EBITDA Margin",    value: pctTxt(niMargin), change: null,  color: (niMargin || 0) > 10 ? "#00b894" : "#f59e0b", nav: "income_statement" },
      { label: "Opex Ratio",       value: pctTxt(opexRatio), change: null, color: (opexRatio || 0) < 60 ? "#00b894" : "#e74c3c", nav: "opex_intelligence" },
      { label: "Net Margin",       value: pctTxt(niMargin), change: null,  color: (niMargin || 0) > 10 ? "#00b894" : "#e74c3c", nav: "income_statement" },
    ];

    const months = useMemo(() => {
      const labels = plH.labels || [];
      return labels.map((l, i) => ({
        label: l,
        revenue: (plH.revenue || [])[i] || 0,
        expenses: ((plH.opex || [])[i] || 0) + ((plH.cogs || [])[i] || 0),
        netIncome: (plH.ebitda || [])[i] || 0,
      })).slice(-13);
    }, [plH]);
    const maxVal = Math.max(...months.map(m => Math.max(m.revenue, m.expenses)), 1);

    // Top revenue sources + expense lines — bucketed via the taxonomy.
    const { revSources, topExpenses } = useMemo(() => {
      const revBy = {}, expBy = {};
      txns.forEach(t => {
        const bucket = bucketForCategory(t.canonical_category, profile);
        const acct = t.account_name || "Other";
        const amt = Math.abs(parseFloat(t.amount || 0));
        if (bucket === "revenue") revBy[acct] = (revBy[acct] || 0) + amt;
        else if (bucket === "opex" || bucket === "cogs") expBy[acct] = (expBy[acct] || 0) + amt;
      });
      const top = (by) => {
        const total = Object.values(by).reduce((s, v) => s + v, 0);
        return Object.entries(by).sort((a, b) => b[1] - a[1]).slice(0, 5)
          .map(([name, val]) => ({ name, val, pct: total > 0 ? (val / total * 100).toFixed(1) : "0" }));
      };
      return { revSources: top(revBy), topExpenses: top(expBy) };
    }, [txns, profile]);

    const maxRev = Math.max(...revSources.map(r => r.val), 1);
    const maxExp = Math.max(...topExpenses.map(e => e.val), 1);

    const card = (children, style) => h("div", { style: { background: "white", border: "1px solid #e9ecef", borderRadius: "10px", padding: "16px", ...(style || {}) } }, children);
    const cardTitle = (t, sub) => h("div", null,
      h("div", { style: { fontSize: "11px", fontWeight: "700", color: "#0d2040", marginBottom: sub ? "4px" : "12px" } }, t),
      sub ? h("div", { style: { fontSize: "10px", color: "#6475a0", marginBottom: "12px" } }, sub) : null);

    const mixRows = (rows, dots) => rows.length === 0
      ? h("div", { style: { color: "#6475a0", fontSize: "12px" } }, "No data yet.")
      : rows.map((s, i) => h("div", { key: i, style: { display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: "6px", fontSize: "11px" } },
          h("div", { style: { display: "flex", alignItems: "center", gap: "6px", overflow: "hidden" } },
            h("div", { style: { width: "8px", height: "8px", borderRadius: "50%", background: dots[i % dots.length], flexShrink: 0 } }),
            h("div", { style: { overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", color: "#1a2540" } }, s.name)),
          h("div", { style: { color: "#6475a0", flexShrink: 0, marginLeft: "8px" } }, s.pct + "%")));

    const barList = (rows, maxv, color, cat) => rows.length === 0
      ? h("div", { style: { color: "#6475a0", fontSize: "12px" } }, "No data yet.")
      : rows.map((s, i) => h("div", { key: i, style: { marginBottom: "10px", cursor: "pointer" }, onClick: () => window.openAccountDetail && window.openAccountDetail({ name: s.name, category: cat, page: "overview" }) },
          h("div", { style: { display: "flex", justifyContent: "space-between", fontSize: "11px", color: "#1a2540", marginBottom: "4px" } },
            h("span", { style: { overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" } }, s.name),
            h("span", { style: { color: "#6475a0", flexShrink: 0, marginLeft: 8 } }, money(s.val) + " · " + s.pct + "%")),
          h("div", { style: { height: "5px", background: "#f0f4ff", borderRadius: "3px", overflow: "hidden" } },
            h("div", { style: { width: (s.val / maxv * 100) + "%", height: "100%", background: color, borderRadius: "3px" } }))));

    return h("div", { style: { padding: "16px 24px" } },

      // Drill hint
      h("div", { style: { fontSize: "10px", color: "#6475a0", padding: "0 0 12px", display: "flex", alignItems: "center", gap: "6px" } },
        h("span", null, "💡"), "Click any number, chart, or row to see the monthly breakdown and CFO insights"),

      // KPI grid — 2 rows of 4
      h("div", { style: { display: "grid", gridTemplateColumns: "repeat(4, 1fr)", gap: "12px", marginBottom: "20px" } },
        kpis.map((kpi, i) => h("div", { key: i, onClick: kpi.nav ? () => go(kpi.nav) : undefined, title: kpi.nav ? "View detail" : undefined, style: { background: "white", border: "1px solid #e9ecef", borderRadius: "10px", padding: "16px 18px", cursor: kpi.nav ? "pointer" : undefined } },
          h("div", { style: { fontSize: "9px", fontWeight: "700", color: "#999", textTransform: "uppercase", letterSpacing: ".1em", marginBottom: "8px" } }, kpi.label),
          h("div", { style: { fontSize: "22px", fontWeight: "800", color: kpi.color, fontFamily: "JetBrains Mono, monospace", letterSpacing: "-.02em" } }, kpi.value),
          kpi.change != null && h("div", { style: { fontSize: "10px", color: kpi.change > 0 ? (kpi.invertColor ? "#e74c3c" : "#00b894") : (kpi.invertColor ? "#00b894" : "#e74c3c"), marginTop: "4px", display: "flex", alignItems: "center", gap: "2px" } },
            h("span", null, kpi.change > 0 ? "▲" : "▼"), Math.abs(kpi.change).toFixed(1) + "% vs prior")))),

      // Trend bars + revenue streams
      h("div", { style: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: "16px", marginBottom: "20px" } },
        card([
          cardTitle("Revenue & Expenses Trend", "Click a bar group to open Revenue or Expenses"),
          h("div", { style: { display: "flex", alignItems: "flex-end", gap: "4px", height: "120px" } },
            months.map((m, i) => h("div", { key: i, style: { flex: 1, display: "flex", gap: "2px", alignItems: "flex-end", height: "100%" } },
              h("div", { title: `${m.label}: revenue ${money(m.revenue)}`, style: { flex: 1, background: "#00b894", height: Math.max(2, m.revenue / maxVal * 110) + "px", borderRadius: "2px 2px 0 0", cursor: "pointer" }, onClick: () => go("revenue_intelligence") }),
              h("div", { title: `${m.label}: expenses ${money(m.expenses)}`, style: { flex: 1, background: "#e74c3c", height: Math.max(2, m.expenses / maxVal * 110) + "px", borderRadius: "2px 2px 0 0", cursor: "pointer" }, onClick: () => go("expenses") })))),
          h("div", { style: { display: "flex", gap: "16px", marginTop: "8px", flexWrap: "wrap" } },
            [["#00b894", "Revenue"], ["#e74c3c", "Expenses"]].map(([color, label]) =>
              h("div", { key: label, style: { display: "flex", alignItems: "center", gap: "4px", fontSize: "10px", color: "#6475a0" } },
                h("div", { style: { width: "10px", height: "10px", background: color, borderRadius: "2px" } }), label))),
        ]),
        card([
          cardTitle("Revenue by Stream", "Click a stream for account detail"),
          revSources.length === 0
            ? h("div", { style: { color: "#6475a0", fontSize: "12px", textAlign: "center", padding: "30px" } }, "Connect revenue data to see streams")
            : h("div", null, revSources.map((s, i) =>
                h("div", { key: i, style: { display: "flex", alignItems: "center", gap: "8px", marginBottom: "8px", cursor: "pointer" }, onClick: () => window.openAccountDetail && window.openAccountDetail({ name: s.name, category: "Revenue", page: "overview" }) },
                  h("div", { style: { width: "8px", height: "8px", borderRadius: "50%", background: DOT[i % DOT.length], flexShrink: 0 } }),
                  h("div", { style: { fontSize: "11px", color: "#1a2540", flex: 1, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" } }, s.name),
                  h("div", { style: { fontSize: "11px", color: "#6475a0", flexShrink: 0 } }, s.pct + "%")))),
        ]),
      ),

      // Mixes + margin trend
      h("div", { style: { display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: "16px", marginBottom: "20px" } },
        card([cardTitle("Revenue Mix"), mixRows(revSources, DOT)]),
        card([cardTitle("Expense Mix"), mixRows(topExpenses, ["#e74c3c", "#f59e0b", "#1C4ED8", "#00b894", "#8b5cf6"])]),
        card([
          cardTitle("Net Surplus Margin Trend"),
          h("div", { style: { display: "flex", alignItems: "flex-end", gap: "3px", height: "60px" } },
            months.map((m, i) => {
              const margin = m.revenue > 0 ? (m.netIncome / m.revenue * 100) : 0;
              return h("div", { key: i, title: `${m.label}: ${margin.toFixed(1)}%`, style: { flex: 1, background: margin >= 0 ? "rgba(0,184,148,.45)" : "rgba(231,76,60,.45)", height: Math.max(2, Math.min(55, Math.abs(margin) / 100 * 55)) + "px", borderRadius: "2px 2px 0 0" } });
            })),
        ]),
      ),

      // Top sources / top expenses with progress bars
      h("div", { style: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: "16px" } },
        card([cardTitle("Top Revenue Sources"), barList(revSources, maxRev, "#00b894", "Revenue")]),
        card([cardTitle("Top Expense Lines"), barList(topExpenses, maxExp, "#e74c3c", "Operating Expenses")]),
      ),
    );
  }

  window.DashboardV2 = DashboardV2;
})();
