// FPnABudgetTab — window.FPnABudgetTab — the Budget builder inside FP&A.
//
// Many owners have never built a budget and don't know where to begin, so this
// tab gives them three honest starting points and a plain editable grid:
//
//   • Start from last year's actuals — prefills each cell with that category /
//     month's prior-year actual, with an optional across-the-board growth %.
//     Every cell stays editable afterwards.
//   • Start flat — enter one annual figure per category; it splits ÷ 12.
//   • Start blank — an empty grid.
//
// Rows are the tenant's OWN canonical categories, read from the categories that
// actually appear in their ledger (data.txns → canonical_category, filtered to
// the P&L taxonomy sections). Nothing is hardcoded and nothing is invented — a
// tenant with three expense categories sees three rows.
//
// Saving writes budgets + budget_lines (migration 78). budget_lines is keyed
// category × month, which is exactly how the FP&A variance path prices a budget,
// so the Budget comparison mode lights up across every tab the moment this saves.
//
// This is an OWNER-CREATED PLANNING BUDGET — advisory only. It is not accounting
// data, carries no tax or audit standing, and never posts to the ledger.

(function () {
  const h = React.createElement;
  const { useState, useMemo, useEffect } = React;

  const MONS = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
  // P&L sections a budget is built over. Balance-sheet sections are deliberately
  // excluded — you don't budget a balance.
  const PL_SECTIONS = ["revenue", "cogs", "opex", "interest"];
  const SECTION_LABEL = { revenue: "Revenue", cogs: "Cost of Sales", opex: "Operating Expenses", interest: "Interest" };

  const num = (v) => { const n = Number(String(v).replace(/[^0-9.\-]/g, "")); return isFinite(n) ? n : 0; };

  function Tab(props) {
    const { K, tenantId, txns, companyProfile, budget, onSaved, secOf } = props;
    const MONO = K.MONO, INK = K.INK, MUTE = K.MUTE, LINE = K.LINE;
    const M = (v) => K.moneyStr(v, { compact: true });

    // ── The tenant's own categories, straight from their ledger ───────────────
    // Grouped by taxonomy section so the grid reads like a P&L rather than an
    // alphabetical dump. Zero hardcoding: a category exists here only because the
    // tenant actually posted to it.
    const cats = useMemo(() => {
      const seen = {};
      for (const t of (txns || [])) {
        const c = t.canonical_category;
        if (!c || seen[c]) continue;
        const s = secOf(c);
        if (!s || PL_SECTIONS.indexOf(s) < 0) continue;
        seen[c] = s;
      }
      return Object.keys(seen)
        .map((c) => ({ cat: c, sec: seen[c] }))
        .sort((a, b) => (PL_SECTIONS.indexOf(a.sec) - PL_SECTIONS.indexOf(b.sec)) || a.cat.localeCompare(b.cat));
    }, [txns, companyProfile]);

    // Years the ledger covers, newest first — plus next year, which is what an
    // owner is usually budgeting for.
    const years = useMemo(() => {
      const ys = new Set();
      for (const t of (txns || [])) {
        const d = t.posted_date ? new Date(t.posted_date) : null;
        if (d && !isNaN(d)) ys.add(d.getFullYear());
      }
      const arr = Array.from(ys).sort((a, b) => b - a);
      if (arr.length) arr.unshift(arr[0] + 1);
      return arr;
    }, [txns]);

    const [fy, setFy] = useState(years[0] || new Date().getFullYear());
    const [grid, setGrid] = useState({});          // "cat|0..11" → number
    const [growth, setGrowth] = useState("0");
    const [flat, setFlat] = useState({});          // cat → annual figure
    const [starter, setStarter] = useState(null);  // null | prior | flat | blank
    const [saving, setSaving] = useState(false);
    const [msg, setMsg] = useState(null);

    // Prior-year actuals for the selected fiscal year, category × month.
    const priorActuals = useMemo(() => {
      const out = {};
      for (const t of (txns || [])) {
        const c = t.canonical_category;
        if (!c) continue;
        const s = secOf(c);
        if (!s || PL_SECTIONS.indexOf(s) < 0) continue;
        const d = t.posted_date ? new Date(t.posted_date) : null;
        if (!d || isNaN(d) || d.getFullYear() !== fy - 1) continue;
        const k = c + "|" + d.getMonth();
        out[k] = (out[k] || 0) + Math.abs(Number(t.amount) || 0);
      }
      return out;
    }, [txns, fy, companyProfile]);
    const hasPrior = Object.keys(priorActuals).length > 0;

    // Load an existing saved budget for this year into the grid, so re-opening the
    // tab edits what's there rather than silently starting over.
    useEffect(() => {
      if (!budget || !budget.has) { setGrid({}); setStarter(null); return; }
      const g = {}; let found = false;
      for (const k in budget.lines) {
        const i = k.lastIndexOf("|");
        const cat = k.slice(0, i), mo = k.slice(i + 1);
        const [yy, mm] = mo.split("-");
        if (+yy !== fy) continue;
        g[cat + "|" + (+mm - 1)] = Number(budget.lines[k]) || 0;
        found = true;
      }
      setGrid(g);
      setStarter(found ? "saved" : null);
    }, [budget.has, budget.lines, fy]);

    const setCell = (cat, m, v) => setGrid((g) => Object.assign({}, g, { [cat + "|" + m]: num(v) }));
    const cell = (cat, m) => { const v = grid[cat + "|" + m]; return v == null ? "" : v; };
    const rowTotal = (cat) => { let s = 0; for (let m = 0; m < 12; m++) s += num(grid[cat + "|" + m] || 0); return s; };
    const colTotal = (m, sec) => cats.filter((c) => !sec || c.sec === sec).reduce((s, c) => s + num(grid[c.cat + "|" + m] || 0), 0);

    // ── Starters ─────────────────────────────────────────────────────────────
    const applyPrior = () => {
      const g = Math.max(-100, num(growth)) / 100;
      const next = {};
      cats.forEach((c) => {
        for (let m = 0; m < 12; m++) {
          const base = priorActuals[c.cat + "|" + m] || 0;
          next[c.cat + "|" + m] = Math.round(base * (1 + g));
        }
      });
      setGrid(next); setStarter("prior"); setMsg(null);
    };
    const applyFlat = () => {
      const next = {};
      cats.forEach((c) => {
        const annual = num(flat[c.cat] || 0);
        const per = Math.round(annual / 12);
        for (let m = 0; m < 12; m++) next[c.cat + "|" + m] = per;
      });
      setGrid(next); setStarter("flat"); setMsg(null);
    };
    const applyBlank = () => { setGrid({}); setStarter("blank"); setMsg(null); };

    // ── Save ─────────────────────────────────────────────────────────────────
    const save = async () => {
      const db = window.supabaseClient;
      if (!db || !tenantId) { setMsg({ bad: true, t: "Not connected — can't save." }); return; }
      setSaving(true); setMsg(null);
      try {
        const { data: { user } } = await db.auth.getUser();
        // One budget per company × fiscal year (unique index) — upsert so re-saving
        // a year replaces it instead of stacking a duplicate that double-counts.
        const { data: b, error: e1 } = await db.from("budgets")
          .upsert({ company_id: tenantId, fiscal_year: fy, name: fy + " Operating Budget",
            status: "draft", created_by: user ? user.id : null, updated_at: new Date().toISOString() },
            { onConflict: "company_id,fiscal_year" })
          .select().single();
        if (e1 || !b) throw new Error(e1 ? e1.message : "Could not save the budget.");

        // Replace this year's lines wholesale — simpler and safer than diffing, and
        // the delete is scoped to this budget so no other year is touched.
        const { error: e2 } = await db.from("budget_lines").delete().eq("budget_id", b.id);
        if (e2) throw new Error(e2.message);

        const rows = [];
        cats.forEach((c) => {
          for (let m = 0; m < 12; m++) {
            const amt = num(grid[c.cat + "|" + m] || 0);
            if (!amt) continue; // don't persist empty cells — an unbudgeted cell is absent, not zero
            rows.push({ budget_id: b.id, canonical_category: c.cat,
              period_month: fy + "-" + String(m + 1).padStart(2, "0") + "-01", amount: amt });
          }
        });
        if (rows.length) {
          const { error: e3 } = await db.from("budget_lines").insert(rows);
          if (e3) throw new Error(e3.message);
        }
        setMsg({ bad: false, t: "Saved — " + rows.length + " budget line" + (rows.length === 1 ? "" : "s") + " for " + fy + ". Budget comparison is now live on every FP&A tab." });
        if (onSaved) onSaved();
      } catch (err) {
        // Most likely cause: migration 78 hasn't been applied to this project yet.
        setMsg({ bad: true, t: "Could not save: " + String(err && err.message || err) });
      } finally { setSaving(false); }
    };

    // ── Empty state: no categories ⇒ nothing honest to budget over ────────────
    if (!cats.length) {
      return h(K.Card, { title: "Budget" },
        h("div", { style: { padding: 22, color: MUTE, fontSize: 13, lineHeight: 1.7, fontStyle: "italic" } },
          "Awaiting categorised ledger data — a budget is built over your own income and expense categories, and none are classified yet. Map your chart of accounts and the grid will fill with your real categories."));
    }

    const btn = (label, onClick, primary, disabled) => h("button", { onClick, disabled: !!disabled,
      style: { padding: "8px 14px", borderRadius: 8, fontSize: 12, fontWeight: 700, cursor: disabled ? "not-allowed" : "pointer",
        border: "1px solid " + (primary ? "#1C4ED8" : "#E4E8F0"), background: primary ? "#1C4ED8" : "#F7F8FB",
        color: primary ? "#fff" : "#4B5563", opacity: disabled ? 0.5 : 1, fontFamily: "Inter, system-ui" } }, label);

    // ── Starter chooser ──────────────────────────────────────────────────────
    const starters = h(K.Card, { key: "st", title: "Start your budget",
      sub: "Pick a starting point — every figure stays editable afterwards" },
      h("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fit,minmax(240px,1fr))", gap: 14 } },
        h("div", { style: { border: "1px solid " + LINE, borderRadius: 10, padding: 14 } },
          h("div", { style: { fontSize: 13, fontWeight: 800, color: INK, marginBottom: 4 } }, "Start from last year's actuals"),
          h("div", { style: { fontSize: 11.5, color: MUTE, lineHeight: 1.5, marginBottom: 10 } },
            hasPrior
              ? "Prefills every cell with that category's actual for the same month in " + (fy - 1) + ", optionally grown."
              : "Awaiting " + (fy - 1) + " actuals — there are no postings for that year to build from."),
          h("div", { style: { display: "flex", gap: 8, alignItems: "center" } },
            h("input", { type: "number", value: growth, onChange: (e) => setGrowth(e.target.value), disabled: !hasPrior,
              style: { width: 70, padding: "7px 9px", borderRadius: 7, border: "1px solid " + LINE, fontFamily: MONO, fontSize: 12.5 } }),
            h("span", { style: { fontSize: 11.5, color: MUTE } }, "% growth"),
            btn("Prefill", applyPrior, true, !hasPrior))),
        h("div", { style: { border: "1px solid " + LINE, borderRadius: 10, padding: 14 } },
          h("div", { style: { fontSize: 13, fontWeight: 800, color: INK, marginBottom: 4 } }, "Start flat"),
          h("div", { style: { fontSize: 11.5, color: MUTE, lineHeight: 1.5, marginBottom: 10 } },
            "Enter an annual figure per category below; it splits evenly across the 12 months."),
          btn("Split annual figures ÷ 12", applyFlat, true)),
        h("div", { style: { border: "1px solid " + LINE, borderRadius: 10, padding: 14 } },
          h("div", { style: { fontSize: 13, fontWeight: 800, color: INK, marginBottom: 4 } }, "Start blank"),
          h("div", { style: { fontSize: 11.5, color: MUTE, lineHeight: 1.5, marginBottom: 10 } },
            "An empty grid — type the numbers you want, month by month."),
          btn("Clear the grid", applyBlank))));

    // ── The grid ─────────────────────────────────────────────────────────────
    const edge = { borderLeft: "2px solid rgba(13,32,64,.12)" };
    const rows = [];
    let lastSec = null;
    cats.forEach((c) => {
      if (c.sec !== lastSec) {
        lastSec = c.sec;
        rows.push(h("tr", { key: "sec-" + c.sec, style: { background: "rgba(13,32,64,.04)" } },
          h("td", { style: { fontWeight: 800, fontSize: 11, color: "#6475a0", textTransform: "uppercase", letterSpacing: ".06em" } },
            SECTION_LABEL[c.sec] || c.sec),
          MONS.map((m, i) => h("td", { key: i, className: "num", style: { fontFamily: MONO, fontSize: 11, fontWeight: 700, color: "#6475a0", textAlign: "right" } }, M(colTotal(i, c.sec)))),
          h("td", { className: "num", style: Object.assign({ fontFamily: MONO, fontSize: 11, fontWeight: 800, color: "#6475a0", textAlign: "right" }, edge) },
            M(MONS.reduce((s, _, i) => s + colTotal(i, c.sec), 0))),
          h("td", null)));
      }
      rows.push(h("tr", { key: c.cat },
        h("td", { style: { fontWeight: 600, color: INK, whiteSpace: "nowrap" } }, c.cat),
        MONS.map((m, i) => h("td", { key: i, style: { padding: 2 } },
          h("input", { type: "number", value: cell(c.cat, i),
            onChange: (e) => setCell(c.cat, i, e.target.value),
            placeholder: "0",
            style: { width: 78, padding: "6px 7px", borderRadius: 6, border: "1px solid " + LINE,
              fontFamily: MONO, fontSize: 12, textAlign: "right", background: "#fff" } }))),
        h("td", { className: "num", style: Object.assign({ fontFamily: MONO, fontWeight: 800, textAlign: "right" }, edge) }, M(rowTotal(c.cat))),
        h("td", { style: { padding: 2 } },
          h("input", { type: "number", value: flat[c.cat] == null ? "" : flat[c.cat],
            onChange: (e) => setFlat(Object.assign({}, flat, { [c.cat]: e.target.value })),
            placeholder: "annual",
            title: "Annual figure for the 'Start flat' helper — splits ÷ 12",
            style: { width: 84, padding: "6px 7px", borderRadius: 6, border: "1px dashed " + LINE,
              fontFamily: MONO, fontSize: 11.5, textAlign: "right", background: "#FAFBFF" } }))));
    });

    const grandTotal = cats.reduce((s, c) => s + rowTotal(c.cat), 0);

    const gridCard = h(K.Card, { key: "grid", title: fy + " BUDGET — " + cats.length + " CATEGOR" + (cats.length === 1 ? "Y" : "IES") + " × 12 MONTHS",
      sub: "Your own categories, straight from your ledger · every cell editable · the dashed column is the 'Start flat' annual input",
      padding: 0,
      right: h("div", { style: { display: "flex", gap: 8, alignItems: "center" } },
        h("select", { value: fy, onChange: (e) => setFy(+e.target.value),
          style: { padding: "7px 10px", borderRadius: 7, border: "1px solid " + LINE, fontSize: 12.5, fontWeight: 700 } },
          years.map((y) => h("option", { key: y, value: y }, "FY " + y))),
        btn(saving ? "Saving…" : "Save budget", save, true, saving || !grandTotal)) },
      h("div", { style: { overflowX: "auto" } },
        h("table", { className: "pa-table", style: { width: "100%" } },
          h("thead", null, h("tr", null,
            h("th", null, "Category"),
            MONS.map((m, i) => h("th", { key: i, className: "num" }, m)),
            h("th", { className: "num", style: edge }, "Total"),
            h("th", { className: "num" }, "Annual ÷ 12"))),
          h("tbody", null, rows,
            h("tr", { style: { background: "rgba(24,168,103,.06)" } },
              h("td", { style: { fontWeight: 800, color: INK } }, "All categories"),
              MONS.map((m, i) => h("td", { key: i, className: "num", style: { fontFamily: MONO, fontWeight: 800, textAlign: "right" } }, M(colTotal(i)))),
              h("td", { className: "num", style: Object.assign({ fontFamily: MONO, fontWeight: 800, textAlign: "right" }, edge) }, M(grandTotal)),
              h("td", null))))));

    const banner = msg ? h("div", { key: "msg", style: { marginTop: 14, padding: "11px 15px", borderRadius: 9, fontSize: 12.5, fontWeight: 600,
      background: msg.bad ? "rgba(217,79,71,.08)" : "rgba(24,168,103,.08)",
      border: "1px solid " + (msg.bad ? "rgba(217,79,71,.3)" : "rgba(24,168,103,.3)"),
      color: msg.bad ? "#b03a33" : "#0f7a4b" } }, msg.t) : null;

    const disclaimer = h("div", { key: "disc", style: { marginTop: 16, padding: "14px 16px", borderRadius: 10,
      background: "rgba(13,32,64,.03)", border: "1px solid " + LINE, fontSize: 11.5, color: MUTE, lineHeight: 1.65 } },
      h("b", { style: { color: INK } }, "This is an owner-created planning budget."),
      " It is a plan you set for yourself — advisory only. It is not accounting data, has no tax or audit standing, and never posts to your ledger. Actuals always come from the general ledger; this budget only ever appears as the comparison column in variance.");

    return h("div", null, starters, h("div", { style: { height: 18 } }), gridCard, banner, disclaimer);
  }

  window.FPnABudgetTab = Tab;
})();
