/* global React, Icon, StatusChip, PageHeader, Banner, Drawer, DrawerHead, Meta, BANK, etb */
const { useState: useStateBasel, useEffect: useEffectBasel } = React;

const BASEL_HELP = {
  title: "Basel Command",
  purpose: "A Basel-aligned control view that brings capital buffers, leverage, liquidity, ICAAP stress headroom, disclosure coverage, and gaps into one executive workpaper.",
  first: "Start with the total capital ratio and worst ICAAP stress surplus. Then scan Pillar 3 pack readiness to see which disclosure tables have source lineage and which remain blocked.",
  terms: [
    ["Capital stack", "CET1, Tier 1, total capital, buffers, and management headroom."],
    ["Leverage ratio", "Tier 1 capital divided by a draft exposure measure; derivatives and SFT inputs are explicit gaps until connected."],
    ["ICAAP / Pillar 2", "Internal capital planning view over live capital, RWA, liquidity, and stress assumptions."],
    ["Pillar 3", "A governed disclosure-style pack assembled from workpapers, evidence coverage, owners, and checker status."],
  ],
  next: [
    "Open Capital Adequacy to inspect CET1/Tier 1/Tier 2 source rows.",
    "Open Credit Risk to inspect RWA composition.",
    "Open Rule Evidence before treating any disclosure row as final.",
  ],
  connections: [
    "Capital ratios pull from the capital and credit workpapers.",
    "Liquidity metrics pull from the LCR/NSFR workpaper.",
    "Disclosure readiness links to Export Gate and Rule Evidence.",
  ],
  guardrail: "This is an internal Basel-aligned workpaper. It is not a full Basel compliance opinion, Pillar 3 publication, or regulator submission.",
};

const BASEL_FALLBACK = {
  cet1: 11750,
  tier1: 12050,
  tier2: 820,
  eligibleCapital: 12870,
  totalRwa: 80661.36,
  creditRwa: 72458.34,
  marketRwa: 1934.32,
  opRwa: 6268.72,
  assets: 96816.8,
  lcr: 261.52,
  nsfr: 143,
};

const BASEL_GAPS = [
  ["SA-CCR / CVA", "Derivative counterparty exposure feeds not connected", "counterparty"],
  ["FRTB market risk", "Trading-book sensitivities and default-risk charge not loaded", "market"],
  ["Securitization", "No securitization exposure class in the demo pack", "credit"],
  ["Formal ICAAP workflow", "Capital planning view is computed, but board workflow and policy sign-off are roadmap", "governance"],
];

function BaselCommand({ go, info }) {
  const [records, setRecords] = useStateBasel({});
  const [selected, setSelected] = useStateBasel(null);

  useEffectBasel(() => {
    if (!window.TOS_API) return;
    ["capital", "credit", "lcr", "alm", "nop"].forEach(kind => {
      window.TOS_API.latest(kind)
        .then(rec => { if (rec) setRecords(prev => ({ ...prev, [kind]: rec })); })
        .catch(() => {});
    });
  }, []);

  const capital = records.capital && records.capital.payload && records.capital.payload.totals;
  const credit = records.credit && records.credit.payload;
  const lcr = records.lcr && records.lcr.payload && records.lcr.payload.totals;
  const alm = records.alm && records.alm.payload && records.alm.payload.totals;

  const cet1 = capital ? capital.cet1AfterDeductions : BASEL_FALLBACK.cet1;
  const tier1 = capital ? capital.tier1Capital : BASEL_FALLBACK.tier1;
  const eligibleCapital = capital ? capital.eligibleCapitalBase : BASEL_FALLBACK.eligibleCapital;
  const creditRwa = credit ? (credit.onBalance.leafTotalRwa + credit.offBalance.leafTotalRwa) : BASEL_FALLBACK.creditRwa;
  const marketRwa = credit && credit.marketRisk ? credit.marketRisk.rwaEquivalent : BASEL_FALLBACK.marketRwa;
  const opRwa = credit && credit.operationalRisk ? credit.operationalRisk.metrics.rwaEquivalent : BASEL_FALLBACK.opRwa;
  const totalRwa = credit ? creditRwa + marketRwa + opRwa : BASEL_FALLBACK.totalRwa;
  const assets = alm ? alm.assets : BASEL_FALLBACK.assets;
  const lcrRatio = lcr ? lcr.lcrRatioPct : BASEL_FALLBACK.lcr;
  const offBalanceDraft = credit ? Math.max(2500, credit.offBalance.leafTotalRwa * 1.35) : 7600;
  const exposureMeasure = assets + offBalanceDraft + 1250;

  const ratios = {
    cet1: cet1 / totalRwa * 100,
    tier1: tier1 / totalRwa * 100,
    total: eligibleCapital / totalRwa * 100,
    leverage: tier1 / exposureMeasure * 100,
  };
  const capitalHeadroom = ratios.total - 11;
  const bufferTarget = 11 + 2.5 + 0.75;
  const disclosure = disclosureRows({ totalRwa, creditRwa, marketRwa, opRwa, lcrRatio, ratios, records, go });
  const icaapPlan = icaapScenarios({ cet1, tier1, eligibleCapital, totalRwa, lcrRatio, ratios, target: bufferTarget });
  const worstScenario = icaapPlan.reduce((worst, row) => row.surplus < worst.surplus ? row : worst, icaapPlan[0]);
  const pack = pillarPackSummary(disclosure);
  const sourceTrace = baselSourceTraceRows({
    records, cet1, tier1, eligibleCapital, totalRwa, creditRwa, marketRwa, opRwa, lcrRatio,
    ratios, assets, offBalanceDraft, exposureMeasure, worstScenario
  });
  window.BASEL_CONTEXT = {
    bankName: BANK.name,
    sourceMode: capital || credit || lcr || alm ? "latest persisted submissions and seeded fallbacks" : "seeded Basel demo pack",
    totals: {
      cet1,
      tier1,
      eligibleCapital,
      creditRwa,
      marketRwa,
      operationalRwa: opRwa,
      totalRwa,
      lcrRatio,
      assets,
      offBalanceDraft,
      exposureMeasure
    },
    ratios: {
      cet1: ratios.cet1,
      tier1: ratios.tier1,
      total: ratios.total,
      leverage: ratios.leverage
    },
    floors: { cet1: 7, tier1: 9, total: 11, leverage: 3, lcr: 100 },
    capitalHeadroom,
    bufferTarget,
    worstScenario: {
      name: worstScenario.name,
      driver: worstScenario.driver,
      car: worstScenario.car,
      cet1Ratio: worstScenario.cet1Ratio,
      lcr: worstScenario.lcr,
      stressedRwa: worstScenario.stressedRwa,
      stressedCapital: worstScenario.stressedCapital,
      target: worstScenario.target,
      surplus: worstScenario.surplus,
      state: worstScenario.state
    },
    gaps: BASEL_GAPS.map(g => ({ name: g[0], detail: g[1], type: g[2] })),
    disclosure: disclosure.map(row => ({
      code: row.code,
      title: row.title,
      source: row.source,
      evidence: row.evidence,
      coverage: row.coverage,
      state: row.state,
      route: row.route
    })),
    sourceTrace: sourceTrace.map(row => ({
      metric: row.metric,
      value: row.value,
      formula: row.formula,
      source: row.source,
      check: row.check,
      state: row.state
    }))
  };

  return (
    <div className="main-inner">
      <PageHeader
        eyebrow={"Basel-aligned control · " + BANK.cycleShort}
        title="Basel Command"
        onInfo={() => info(BASEL_HELP)}
        right={<React.Fragment>
          <button className="btn btn-ghost btn-sm" onClick={() => setSelected(icaapDrawer(icaapPlan, worstScenario))}>
            <Icon name="scale" size={15} /> ICAAP board pack
          </button>
          <button className="btn btn-ghost btn-sm" onClick={() => setSelected(pillarPackDrawer(disclosure, pack))}>
            <Icon name="fileText" size={15} /> Pillar 3 pack
          </button>
          <button className="btn btn-dark btn-sm" onClick={() => go("export")}><Icon name="lock" size={15} /> Export Gate</button>
        </React.Fragment>}
      />

      <div className="banner banner-indigo" style={{ marginBottom: 20 }}>
        <Icon name="layers" size={18} className="ic" />
        <div><b>Basel-aligned internal view.</b> Capital, leverage, liquidity, and disclosure readiness are assembled from existing workpapers. Missing Basel engines are shown as explicit gaps, not hidden assumptions.</div>
      </div>

      <div className="grid g4 mb16">
        <BaselKpi label="Total capital ratio" value={pct(ratios.total)} foot={"Headroom " + pct(capitalHeadroom, 2) + " vs 11% floor"} tone={capitalHeadroom >= 2 ? "green" : "amber"} />
        <BaselKpi label="ICAAP severe surplus" value={moneyM(worstScenario.surplus)} foot={worstScenario.name + " · target " + pct(worstScenario.target)} tone={worstScenario.surplus >= 0 ? "green" : "red"} />
        <BaselKpi label="Leverage ratio" value={pct(ratios.leverage)} foot={"Tier 1 / draft exposure · min 3% view"} tone={ratios.leverage >= 5 ? "green" : "amber"} />
        <BaselKpi label="Pillar 3 pack" value={pack.ready + " / " + pack.total} foot={pack.openGates + " open evidence or approval gates"} tone={pack.openGates ? "amber" : "green"} />
      </div>

      <div className="card card-pad mb20">
        <div className="panel-h">
          <h3>Basel source traceability</h3>
          <span className="sub">Headline ratios, formulas, source snapshots, and limits in one review table</span>
        </div>
        <div className="wp-scroll">
          <table className="tbl">
            <thead><tr><th>Metric</th><th className="num">Value</th><th>Formula</th><th>Source snapshot</th><th>Status</th><th></th></tr></thead>
            <tbody>
              {sourceTrace.map(row => (
                <tr key={row.metric} className="click" onClick={() => setSelected(sourceTraceDrawer(row))}>
                  <td><div style={{ fontWeight: 700 }}>{row.metric}</div><div className="muted" style={{ fontSize: 12 }}>{row.check}</div></td>
                  <td className="num tnum" style={{ fontWeight: 800 }}>{row.value}</td>
                  <td>{row.formula}</td>
                  <td><div style={{ fontWeight: 600 }}>{row.source}</div><div className="muted" style={{ fontSize: 12 }}>{row.owner}</div></td>
                  <td><StatusChip s={row.state} /></td>
                  <td className="num"><button className="btn btn-ghost btn-sm" aria-label={"Trace " + row.metric} onClick={(e) => { e.stopPropagation(); setSelected(sourceTraceDrawer(row)); }}>Trace <Icon name="arrowR" size={13} /></button></td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      </div>

      <div className="grid" style={{ gridTemplateColumns: "1.2fr .8fr", gap: 18, alignItems: "start" }}>
        <div className="card card-pad">
          <div className="panel-h">
            <h3>Capital stack and buffers</h3>
            <span className="sub">CET1, Tier 1, total capital, and Basel-style overlays</span>
          </div>
          <div className="grid g3 mb16">
            <RatioBlock label="CET1" ratio={ratios.cet1} floor={7} go={() => go("capital")} />
            <RatioBlock label="Tier 1" ratio={ratios.tier1} floor={9} go={() => go("capital")} />
            <RatioBlock label="Total capital" ratio={ratios.total} floor={11} go={() => go("capital")} />
          </div>
          <table className="tbl">
            <thead><tr><th>Layer</th><th className="num">Target</th><th className="num">Actual basis</th><th className="num">Headroom</th><th>Status</th></tr></thead>
            <tbody>
              {[
                ["CET1 minimum", 7, ratios.cet1, "RECONCILED"],
                ["Tier 1 minimum", 9, ratios.tier1, "RECONCILED"],
                ["Total capital minimum", 11, ratios.total, "RECONCILED"],
                ["Capital conservation buffer overlay", 13.5, ratios.total, ratios.total >= 13.5 ? "REVIEW_PENDING" : "EXPORT_BLOCKED"],
                ["Pillar 2 add-on placeholder", bufferTarget, ratios.total, "EVIDENCE_NEEDED"],
                ["Countercyclical buffer placeholder", bufferTarget, ratios.total, "NEEDS_BANK_POLICY"],
              ].map(row => (
                <tr key={row[0]}>
                  <td style={{ fontWeight: 600 }}>{row[0]}</td>
                  <td className="num tnum">{pct(row[1])}</td>
                  <td className="num tnum">{pct(row[2])}</td>
                  <td className="num tnum" style={{ color: row[2] - row[1] >= 0 ? "var(--green-ink)" : "var(--red)", fontWeight: 700 }}>{pct(row[2] - row[1], 2)}</td>
                  <td><StatusChip s={row[3]} /></td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>

        <div className="col" style={{ gap: 18 }}>
          <div className="card card-pad">
            <div className="panel-h"><h3>Leverage ratio</h3><span className="sub">Basel III exposure-measure preview</span></div>
            <div className="big-num tnum" style={{ color: ratios.leverage >= 3 ? "var(--green-ink)" : "var(--red)" }}>{pct(ratios.leverage)}</div>
            <div className="bar" style={{ margin: "10px 0 14px" }}><span style={{ width: Math.min(100, ratios.leverage / 12 * 100) + "%" }} /></div>
            <Meta rows={[
              ["Tier 1 numerator", etb(Math.round(tier1)) + "m"],
              ["Exposure measure", etb(Math.round(exposureMeasure)) + "m"],
              ["On-balance source", etb(Math.round(assets)) + "m"],
              ["Off-balance draft", etb(Math.round(offBalanceDraft)) + "m"],
              ["Minimum view", "3.00% Basel-style monitoring floor"],
            ]} />
            <div className="mt16"><Banner kind="amber" icon="alert"><b>Draft denominator.</b> Derivatives and SFT connectors are not loaded in this demo, so leverage remains an internal monitoring view.</Banner></div>
          </div>

          <div className="card card-pad">
            <div className="panel-h"><h3>Basel gaps</h3><span className="sub">Roadmap, not hidden assumptions</span></div>
            {BASEL_GAPS.map(g => (
              <div key={g[0]} className="evi-row">
                <span className="ic-wrap"><Icon name={g[2] === "market" ? "trending" : g[2] === "credit" ? "shield" : g[2] === "governance" ? "clipboard" : "layers"} size={15} /></span>
                <div className="grow"><div className="t">{g[0]}</div><div className="d">{g[1]}</div></div>
                <StatusChip s="CONFIG_REQUIRED" />
              </div>
            ))}
          </div>
        </div>
      </div>

      <div className="card card-pad mt20">
        <div className="panel-h">
          <h3>ICAAP / Pillar 2 capital plan</h3>
          <span className="sub">Internal capital adequacy assessment over live capital, RWA, and liquidity metrics</span>
        </div>
        <div className="banner banner-amber" style={{ marginBottom: 14 }}>
          <Icon name="lock" size={18} className="ic" />
          <div><b>Internal ICAAP draft.</b> Scenarios are deterministic overlays on the current workpapers. Board approval, bank policy limits, and formal capital plan workflow are not yet persisted.</div>
        </div>
        <table className="tbl">
          <thead><tr><th>Scenario</th><th>Driver</th><th className="num">CAR</th><th className="num">CET1</th><th className="num">LCR</th><th className="num">Surplus / shortfall</th><th>Status</th></tr></thead>
          <tbody>
            {icaapPlan.map(row => (
              <tr key={row.name} className="click" onClick={() => setSelected(icaapScenarioDrawer(row))}>
                <td><div style={{ fontWeight: 700 }}>{row.name}</div><div className="muted" style={{ fontSize: 12 }}>Target {pct(row.target)} total capital</div></td>
                <td>{row.driver}</td>
                <td className="num tnum" style={{ fontWeight: 700, color: row.car >= row.target ? "var(--green-ink)" : "var(--red)" }}>{pct(row.car)}</td>
                <td className="num tnum">{pct(row.cet1Ratio)}</td>
                <td className="num tnum" style={{ color: row.lcr >= 100 ? "var(--green-ink)" : "var(--red)" }}>{pct(row.lcr)}</td>
                <td className="num tnum" style={{ fontWeight: 700, color: row.surplus >= 0 ? "var(--green-ink)" : "var(--red)" }}>{moneyM(row.surplus)}</td>
                <td><StatusChip s={row.state} /></td>
              </tr>
            ))}
          </tbody>
        </table>
        <div className="grid g3 mt16">
          {[
            ["Capital target", pct(bufferTarget), "11% minimum + 2.5% conservation + 0.75% internal Pillar 2 placeholder"],
            ["Management action trigger", pct(Math.max(11, worstScenario.target - 1.25)), "Escalate to ALCO before the formal minimum is reached"],
            ["Liquidity floor", "100.0%", "LCR remains a hard recovery trigger in every ICAAP scenario"],
          ].map(item => (
            <div key={item[0]} className="evi-row" style={{ alignItems: "flex-start" }}>
              <span className="ic-wrap"><Icon name="clipboard" size={15} /></span>
              <div className="grow"><div className="t">{item[0]}</div><div className="d"><b className="tnum">{item[1]}</b> · {item[2]}</div></div>
            </div>
          ))}
        </div>
      </div>

      <div className="card card-pad mt20">
        <div className="panel-h">
          <h3>Pillar 3 pack builder</h3>
          <span className="sub">Disclosure registry with source coverage, evidence gaps, owners, and checker state</span>
        </div>
        <div className="grid g4 mb16">
          <BaselKpi label="Tables ready" value={pack.ready + " / " + pack.total} foot="Reconciled or internally approved" tone={pack.ready === pack.total ? "green" : "amber"} />
          <BaselKpi label="Average coverage" value={pack.avgCoverage + "%"} foot="Source and lineage coverage" tone={pack.avgCoverage >= 80 ? "green" : "amber"} />
          <BaselKpi label="Evidence gaps" value={String(pack.evidenceGaps)} foot="Rows need rule evidence or bank policy" tone={pack.evidenceGaps ? "amber" : "green"} />
          <BaselKpi label="Checker queue" value={String(pack.checkerQueue)} foot="Rows awaiting internal review" tone={pack.checkerQueue ? "amber" : "green"} />
        </div>
        <div className="between mb16" style={{ gap: 12, alignItems: "center" }}>
          <div className="muted" style={{ fontSize: 13 }}>Pack compiles a controlled internal preview only. Export remains governed by the Reg Reporting gate.</div>
          <button className="btn btn-dark btn-sm" onClick={() => setSelected(pillarPackDrawer(disclosure, pack))}><Icon name="fileText" size={15} /> Build Pillar 3 pack</button>
        </div>
        <table className="tbl">
          <thead><tr><th>Table</th><th>Source</th><th>Owner / evidence</th><th className="num">Coverage</th><th>Status</th><th></th></tr></thead>
          <tbody>
            {disclosure.map(row => (
              <tr key={row.code} className="click" onClick={() => setSelected(row)}>
                <td><div style={{ fontWeight: 700 }}>{row.code}</div><div className="muted" style={{ fontSize: 12 }}>{row.title}</div></td>
                <td>{row.source}</td>
                <td><div style={{ fontWeight: 600 }}>{row.owner}</div><div className="muted" style={{ fontSize: 12 }}>{row.evidence}</div></td>
                <td className="num"><Coverage pct={row.coverage} /></td>
                <td><StatusChip s={row.state} /></td>
                <td className="num"><button className="btn btn-ghost btn-sm" aria-label={"Preview " + row.code + " disclosure table"} onClick={(e) => { e.stopPropagation(); setSelected(row); }}>Preview <Icon name="arrowR" size={13} /></button></td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>

      {selected && <BaselDrawer row={selected} onClose={() => setSelected(null)} go={go} />}
    </div>
  );
}

function disclosureRows(ctx) {
  return [
    { code: "KM1", title: "Key metrics", source: "Capital, RWA, leverage, LCR", owner: "Meron Haile", evidence: "Capital and liquidity metrics mapped; checker review pending", coverage: 86, state: "REVIEW_PENDING", route: "capital", rows: [["Total capital ratio", pct(ctx.ratios.total)], ["Leverage ratio", pct(ctx.ratios.leverage)], ["LCR", pct(ctx.lcrRatio)]] },
    { code: "OV1", title: "RWA overview", source: "Credit Risk + Market FX + Operational SMA", owner: "Yonas Alemu", evidence: "RWA components tie to workpapers", coverage: 82, state: "RECONCILED", route: "credit", rows: [["Credit RWA", etb(Math.round(ctx.creditRwa)) + "m"], ["Market RWA", etb(Math.round(ctx.marketRwa)) + "m"], ["Operational RWA", etb(Math.round(ctx.opRwa)) + "m"], ["Total RWA", etb(Math.round(ctx.totalRwa)) + "m"]] },
    { code: "CR1", title: "Credit risk exposure classes", source: "Credit Risk workpaper", owner: "Yonas Alemu", evidence: "CRM and CCF references need checker review", coverage: 74, state: "EVIDENCE_NEEDED", route: "credit", rows: [["Source", ctx.records.credit ? ctx.records.credit.fileName : "Seeded credit workbook"], ["Evidence", "CRM and CCF references need checker review"]] },
    { code: "MR1", title: "Market risk summary", source: "Market / FX NOP", owner: "Abel Mengist", evidence: "FX open-position workpaper reconciled", coverage: 78, state: "RECONCILED", route: "market", rows: [["Market RWA", etb(Math.round(ctx.marketRwa)) + "m"], ["Source", "FX open-position workpaper"]] },
    { code: "OR1", title: "Operational risk SMA", source: "Operational Risk workpaper", owner: "Robel Kassa", evidence: "Loss-event register still pending", coverage: 72, state: "REVIEW_PENDING", route: "oprisk", rows: [["Operational RWA", etb(Math.round(ctx.opRwa)) + "m"], ["Loss data", "Loss-event register pending"]] },
    { code: "LIQ1", title: "LCR / NSFR summary", source: "Liquidity workpaper", owner: "Sara Tesfaye", evidence: "Outflow factors awaiting checker review", coverage: 80, state: "EVIDENCE_NEEDED", route: "workpaper", rows: [["LCR", pct(ctx.lcrRatio)], ["NSFR", pct(BASEL_FALLBACK.nsfr)], ["Rule evidence", "Outflow factors awaiting checker review"]] },
    { code: "LR1", title: "Leverage ratio", source: "Capital + exposure measure draft", owner: "Meron Haile", evidence: "Derivatives/SFT exposure feeds not loaded", coverage: 58, state: "NEEDS_BANK_POLICY", route: "basel", rows: [["Leverage ratio", pct(ctx.ratios.leverage)], ["Gap", "Derivatives/SFT exposure feeds not loaded"]] },
    { code: "CCA", title: "Capital buffers and constraints", source: "Capital stack overlay", owner: "Hana Girma", evidence: "Pillar 2 and countercyclical buffers need policy sign-off", coverage: 62, state: "EVIDENCE_NEEDED", route: "evidence", rows: [["Capital conservation overlay", "2.50%"], ["Pillar 2 placeholder", "0.75%"], ["Countercyclical buffer", "Requires bank policy"]] },
  ];
}

function baselSourceTraceRows(ctx) {
  const capitalFile = sourceFile(ctx.records, "capital", "04_bestbank_capital-adequacy-car.xlsx");
  const creditFile = sourceFile(ctx.records, "credit", "01_bestbank_credit-risk.xlsx");
  const lcrFile = sourceFile(ctx.records, "lcr", "05_bestbank_lcr.xlsx");
  const almFile = sourceFile(ctx.records, "alm", "03_bestbank_maturity-ladder-alm.xlsx");
  return [
    {
      metric: "Total capital ratio",
      value: pct(ctx.ratios.total),
      formula: "Eligible capital base / total RWA",
      source: capitalFile + " + " + creditFile,
      owner: "Capital Adequacy and Credit Risk workpapers",
      check: "CAR minimum monitoring floor: 11.0%",
      state: "RECONCILED",
      route: "capital",
      rows: [
        ["Eligible capital base", moneyM(ctx.eligibleCapital)],
        ["Total RWA", moneyM(ctx.totalRwa)],
        ["Credit RWA", moneyM(ctx.creditRwa)],
        ["Market RWA add-on", moneyM(ctx.marketRwa)],
        ["Operational RWA add-on", moneyM(ctx.opRwa)],
      ],
    },
    {
      metric: "CET1 ratio",
      value: pct(ctx.ratios.cet1),
      formula: "CET1 after deductions / total RWA",
      source: capitalFile + " + " + creditFile,
      owner: "Capital instruments and RWA source rows",
      check: "CET1 minimum monitoring floor: 7.0%",
      state: "RECONCILED",
      route: "capital",
      rows: [
        ["CET1 after deductions", moneyM(ctx.cet1)],
        ["Total RWA", moneyM(ctx.totalRwa)],
        ["Source workbook", capitalFile],
        ["RWA workbook", creditFile],
      ],
    },
    {
      metric: "Leverage ratio",
      value: pct(ctx.ratios.leverage),
      formula: "Tier 1 capital / draft exposure measure",
      source: capitalFile + " + " + almFile + " + off-balance draft",
      owner: "Basel Command exposure preview",
      check: "Derivative and SFT exposure feeds remain explicit gaps",
      state: "NEEDS_BANK_POLICY",
      route: "basel",
      rows: [
        ["Tier 1 capital", moneyM(ctx.tier1)],
        ["On-balance exposure", moneyM(ctx.assets)],
        ["Off-balance draft", moneyM(ctx.offBalanceDraft)],
        ["Other exposure placeholder", moneyM(1250)],
        ["Draft exposure measure", moneyM(ctx.exposureMeasure)],
      ],
    },
    {
      metric: "LCR",
      value: pct(ctx.lcrRatio),
      formula: "HQLA / net cash outflows",
      source: lcrFile,
      owner: "LCR / NSFR workpaper",
      check: "Liquidity floor: 100.0%",
      state: "EVIDENCE_NEEDED",
      route: "workpaper",
      rows: [
        ["LCR ratio", pct(ctx.lcrRatio)],
        ["Source workbook", lcrFile],
        ["Rule evidence", "Outflow-factor checker review still required"],
      ],
    },
    {
      metric: "RWA add-ons",
      value: moneyM(ctx.marketRwa + ctx.opRwa),
      formula: "Market RWA equivalent + operational SMA RWA equivalent",
      source: creditFile,
      owner: "Credit Risk parser add-on section",
      check: "Add-ons are included in total RWA before capital ratios",
      state: "RECONCILED",
      route: "credit",
      rows: [
        ["Market RWA equivalent", moneyM(ctx.marketRwa)],
        ["Operational RWA equivalent", moneyM(ctx.opRwa)],
        ["Total add-ons", moneyM(ctx.marketRwa + ctx.opRwa)],
        ["Credit-only RWA", moneyM(ctx.creditRwa)],
      ],
    },
    {
      metric: "ICAAP severe surplus",
      value: moneyM(ctx.worstScenario.surplus),
      formula: "Stressed capital - stressed RWA × internal target",
      source: capitalFile + " + " + creditFile + " + ICAAP overlay",
      owner: "Pillar 2 scenario workpaper",
      check: ctx.worstScenario.name + " scenario",
      state: ctx.worstScenario.state,
      route: "stress",
      rows: [
        ["Scenario", ctx.worstScenario.name],
        ["Stressed RWA", moneyM(ctx.worstScenario.stressedRwa)],
        ["Stressed capital", moneyM(ctx.worstScenario.stressedCapital)],
        ["Internal target", pct(ctx.worstScenario.target)],
        ["Surplus / shortfall", moneyM(ctx.worstScenario.surplus)],
      ],
    },
  ];
}

function sourceFile(records, kind, fallback) {
  const rec = records && records[kind];
  return rec && rec.fileName ? rec.fileName : fallback;
}

function sourceTraceDrawer(row) {
  return {
    code: "TRACE",
    title: row.metric + " source trace",
    state: row.state,
    source: row.source,
    route: row.route,
    guardrail: "Internal source trace only. The trace proves the displayed calculation path inside this workspace; it is not an official submission or external assurance opinion.",
    rows: [
      ["Metric value", row.value],
      ["Formula", row.formula],
      ["Control check", row.check],
      ["Owner", row.owner],
      ...row.rows,
    ],
  };
}

function icaapScenarios(ctx) {
  return [
    { name: "Base case", driver: "Current approved workpapers", rwaShock: 0, capitalLoss: 0, lcrShock: 0, target: ctx.target, state: "RECONCILED", action: "Maintain capital plan and dividend controls" },
    { name: "Moderate macro stress", driver: "Credit migration + deposit runoff", rwaShock: 0.08, capitalLoss: 350, lcrShock: 52, target: ctx.target, state: "REVIEW_PENDING", action: "ALCO watch; retain earnings and slow RWA growth" },
    { name: "Severe combined stress", driver: "Credit migration, FX shock, high outflows", rwaShock: 0.16, capitalLoss: 900, lcrShock: 112, target: ctx.target, state: "EVIDENCE_NEEDED", action: "Capital preservation, contingency funding, recovery options" },
  ].map(row => {
    const stressedRwa = ctx.totalRwa * (1 + row.rwaShock);
    const stressedCapital = Math.max(0, ctx.eligibleCapital - row.capitalLoss);
    const stressedCet1 = Math.max(0, ctx.cet1 - row.capitalLoss * 0.78);
    const stressedTier1 = Math.max(0, ctx.tier1 - row.capitalLoss * 0.86);
    const requiredCapital = stressedRwa * row.target / 100;
    return {
      ...row,
      stressedRwa,
      stressedCapital,
      stressedCet1,
      stressedTier1,
      car: stressedCapital / stressedRwa * 100,
      cet1Ratio: stressedCet1 / stressedRwa * 100,
      tier1Ratio: stressedTier1 / stressedRwa * 100,
      lcr: Math.max(0, ctx.lcrRatio - row.lcrShock),
      requiredCapital,
      surplus: stressedCapital - requiredCapital,
    };
  });
}

function pillarPackSummary(rows) {
  const ready = rows.filter(row => row.state === "RECONCILED" || row.state === "APPROVED_INTERNAL").length;
  const evidenceGaps = rows.filter(row => row.state === "EVIDENCE_NEEDED" || row.state === "NEEDS_BANK_POLICY").length;
  const checkerQueue = rows.filter(row => row.state === "REVIEW_PENDING").length;
  const avgCoverage = Math.round(rows.reduce((sum, row) => sum + row.coverage, 0) / Math.max(1, rows.length));
  return { ready, total: rows.length, evidenceGaps, checkerQueue, avgCoverage, openGates: rows.length - ready };
}

function icaapDrawer(plan, worst) {
  return {
    code: "ICAAP",
    title: "ICAAP board pack",
    state: worst.surplus >= 0 ? "REVIEW_PENDING" : "EXPORT_BLOCKED",
    source: "Capital, RWA, stress, and liquidity workpapers",
    route: "stress",
    guardrail: "Internal ICAAP draft. Not a formal Pillar 2 submission or board-approved capital plan.",
    rows: [
      ["Worst scenario", worst.name],
      ["Worst CAR", pct(worst.car) + " vs target " + pct(worst.target)],
      ["Worst surplus / shortfall", moneyM(worst.surplus)],
      ["Management action", worst.action],
      ...plan.map(row => [row.name, pct(row.car) + " CAR · " + moneyM(row.surplus) + " surplus"])
    ]
  };
}

function icaapScenarioDrawer(row) {
  return {
    code: "ICAAP",
    title: row.name,
    state: row.state,
    source: "Pillar 2 capital scenario selector",
    route: "stress",
    guardrail: "Scenario output is analysis-only until bank policy, checker review, and board approval are recorded.",
    rows: [
      ["Driver", row.driver],
      ["Total capital ratio", pct(row.car)],
      ["CET1 ratio", pct(row.cet1Ratio)],
      ["Tier 1 ratio", pct(row.tier1Ratio)],
      ["LCR", pct(row.lcr)],
      ["Stressed RWA", moneyM(row.stressedRwa)],
      ["Required capital", moneyM(row.requiredCapital)],
      ["Surplus / shortfall", moneyM(row.surplus)],
      ["Management action", row.action],
    ]
  };
}

function pillarPackDrawer(disclosure, pack) {
  return {
    code: "P3",
    title: "Pillar 3 pack builder",
    state: pack.openGates ? "REVIEW_PENDING" : "APPROVED_INTERNAL",
    source: "Disclosure table registry",
    route: "export",
    guardrail: "Internal Pillar 3 preview only. Publication, external disclosure, and regulator submission remain outside this workspace.",
    rows: [
      ["Tables ready", pack.ready + " / " + pack.total],
      ["Average source coverage", pack.avgCoverage + "%"],
      ["Evidence gaps", String(pack.evidenceGaps)],
      ["Checker queue", String(pack.checkerQueue)],
      ...disclosure.map(row => [row.code + " · " + row.title, row.coverage + "% coverage · " + row.state + " · " + row.owner])
    ]
  };
}

function BaselDrawer({ row, onClose, go }) {
  const route = row.route || "export";
  return (
    <Drawer open={!!row} onClose={onClose} wide>
      <DrawerHead title={row.title} sub={(row.code || "P3") + " · internal disclosure preview"} chip={<StatusChip s={row.state || "REVIEW_PENDING"} />} onClose={onClose} />
      <div className="drawer-body">
        <Banner kind={row.state === "RECONCILED" || row.state === "APPROVED_INTERNAL" ? "green" : "amber"} icon="fileText">
          <b>Internal preview only.</b> {row.guardrail || "This table shows source coverage and calculation lineage; it is not a Pillar 3 publication or official submission."}
        </Banner>
        <div className="mt16"><Meta rows={[
          ["Table", row.code || "Pillar 3 pack"],
          ["Source", row.source || "Disclosure table registry"],
          ["Coverage", row.coverage != null ? row.coverage + "%" : "staged"],
          ["Route", route],
        ]} /></div>
        {row.rows && <div className="mt16">
          <div className="section-label mb8">Preview values</div>
          {row.rows.map((r, i) => (
            <div key={i} className="evi-row"><span className="ic-wrap"><Icon name="check" size={15} /></span><div className="grow"><div className="t">{r[0]}</div><div className="d">{r[1]}</div></div></div>
          ))}
        </div>}
      </div>
      <div className="drawer-foot">
        <button className="btn btn-ghost" onClick={() => go(route)}><Icon name="arrowR" size={14} /> Open source</button>
        <button className="btn btn-dark" style={{ marginLeft: "auto" }} onClick={() => go("export")}>Export Gate</button>
      </div>
    </Drawer>
  );
}

function RatioBlock({ label, ratio, floor, go }) {
  const headroom = ratio - floor;
  return (
    <button type="button" aria-label={"Open Capital Adequacy for " + label} className="card card-pad" style={{ textAlign: "left", borderColor: "var(--border)", background: "var(--surface)" }} onClick={go}>
      <div className="section-label">{label}</div>
      <div className="big-num tnum" style={{ color: headroom >= 0 ? "var(--green-ink)" : "var(--red)", fontSize: 28 }}>{pct(ratio)}</div>
      <div className="bar" style={{ margin: "8px 0" }}><span style={{ width: Math.min(100, ratio / 18 * 100) + "%" }} /></div>
      <div className="muted" style={{ fontSize: 11.5 }}>Floor {pct(floor)} · headroom {pct(headroom, 2)}</div>
    </button>
  );
}

function Coverage({ pct }) {
  const tone = pct >= 80 ? "var(--green)" : pct >= 60 ? "var(--amber)" : "var(--red)";
  return <span className="center gap8" style={{ justifyContent: "flex-end" }}><span className="bar" style={{ width: 48 }}><span style={{ width: pct + "%", background: tone }} /></span><b className="tnum">{pct}%</b></span>;
}

function BaselKpi({ label, value, foot, tone }) {
  const c = { green: "var(--green-ink)", amber: "var(--amber)", red: "var(--red)" }[tone] || "var(--ink)";
  return <div className="card card-pad" style={{ padding: "15px 18px" }}><div className="section-label">{label}</div><div className="big-num tnum" style={{ marginTop: 6, color: c, fontSize: 26 }}>{value}</div><div className="muted" style={{ fontSize: 11.5, marginTop: 4 }}>{foot}</div></div>;
}

function pct(v, dp = 1) {
  return Number(v).toFixed(dp) + "%";
}

function moneyM(v) {
  const sign = v < 0 ? "-" : "";
  return sign + etb(Math.round(Math.abs(v))) + "m";
}

window.BaselCommand = BaselCommand;
