/* global React, Icon, StatusChip, PageHeader, Banner, Drawer, DrawerHead, Meta, etb, useToast */
const { useState: useStateIR } = React;

/* ============================================================
   IRRBB · Behavioral ALM · FTP — model-governance surfaces
   Lighter than the prudential returns: config + evidence + model
   policy + analysis-only impacts. Official export blocked.
   ============================================================ */

/* ---------- shared: model-status banner ---------- */
function ModelBanner({ children }) {
  return <div style={{ marginBottom: 16 }}><Banner kind="amber" icon="lock"><b>Model governance surface.</b> {children} This is internal analysis — official regulatory export is not available here.</Banner></div>;
}

/* ============================================================
   IRRBB — repricing gap, six shocks, ΔNII / ΔEVE
   ============================================================ */
const IRRBB_BUCKETS = ["O/N–1m", "1–3m", "3–6m", "6–12m", "1–2y", "2–5y", ">5y"];
const RSA = [4200, 9800, 14200, 18600, 22400, 16800, 9100];   // rate-sensitive assets
const RSL = [21800, 16400, 12200, 9800, 6400, 3800, 1900];     // rate-sensitive liabilities
const GAP = RSA.map((a, i) => a - RSL[i]);
let cum = 0; const CUMGAP = GAP.map(g => (cum += g));
const TIER1_IR = 11913;
// NBE/Basel six standard interest-rate shocks (bps effect modelled on EVE)
const IR_SHOCKS = [
  { name: "Parallel up", eve: -742, nii: 318 },
  { name: "Parallel down", eve: 689, nii: -284 },
  { name: "Steepener", eve: -281, nii: 96 },
  { name: "Flattener", eve: 174, nii: -88 },
  { name: "Short rate up", eve: -402, nii: 211 },
  { name: "Short rate down", eve: 366, nii: -190 },
];
const worstEVE = Math.min(...IR_SHOCKS.map(s => s.eve));
const evePct = Math.abs(worstEVE) / TIER1_IR * 100;

function IRRBB({ go, info }) {
  const [drawer, setDrawer] = useStateIR(null);
  return (
    <div className="main-inner">
      <PageHeader eyebrow="Prudential Risk · Banking book" title="IRRBB"
        onInfo={() => info({ title: "IRRBB", purpose: "Interest-rate risk in the banking book — the repricing gap, the six NBE standard rate shocks, and their ΔNII / ΔEVE impact. A model-governance surface: it needs an approved model policy and curve evidence before any figure is official.", first: "Read the cumulative gap and the worst-case ΔEVE against Tier-1. Every shock is analysis-only.", terms: [["Repricing gap", "Rate-sensitive assets − liabilities per time bucket."], ["ΔEVE", "Change in economic value of equity under a shock."], ["ΔNII", "Change in 12-month net interest income."]], next: ["Click a bucket to see its repricing detail.", "Click a shock to see the analysis-only impact.", "Attach curve evidence and submit the model for approval."], connections: ["Curves come from the market-data source.", "Behavioral assumptions feed the bucketing.", "Outputs are internal — no official export."], guardrail: "Needs model policy and curve evidence; official export blocked. ΔEVE/ΔNII are analysis-only." })}
        right={<span className="center gap8"><StatusChip s="NEEDS_BANK_POLICY" lg /><button className="btn btn-ghost btn-sm" onClick={() => setDrawer("curve")}><Icon name="trending" size={14} /> Curve</button></span>} />

      <ModelBanner>Needs an approved <b>model policy</b> and <b>curve evidence</b> before ΔNII / ΔEVE can be relied on.</ModelBanner>

      <div className="grid g4 mb20">
        <Mini label="Worst-case ΔEVE" v={etb(worstEVE)} foot="Parallel up · ETB M" tone="red" />
        <Mini label="ΔEVE / Tier-1" v={evePct.toFixed(1) + "%"} foot="NBE outlier ≤ 15%" tone={evePct > 15 ? "red" : "green"} />
        <Mini label="12-month ΔNII" v={"+" + etb(318)} foot="Parallel up · analysis-only" tone="indigo" />
        <Mini label="Cumulative gap" v={etb(CUMGAP[CUMGAP.length - 1])} foot="Net repricing position" />
      </div>

      {/* repricing gap matrix */}
      <div className="xl-wrap mb16">
        <table className="xl">
          <colgroup><col style={{ minWidth: 220 }} />{IRRBB_BUCKETS.map(b => <col key={b} style={{ width: 100 }} />)}</colgroup>
          <thead><tr><th style={{ textAlign: "left" }}>Repricing gap · ETB millions</th>{IRRBB_BUCKETS.map(b => <th key={b} className="xl-amt">{b}</th>)}</tr></thead>
          <tbody>
            <tr className="xl-item"><td className="xl-label">Rate-sensitive assets</td>{RSA.map((v, i) => <td key={i} className="xl-amt tnum xl-cell hit" onClick={() => setDrawer("bucket" + i)}>{etb(v)}</td>)}</tr>
            <tr className="xl-item"><td className="xl-label">Rate-sensitive liabilities</td>{RSL.map((v, i) => <td key={i} className="xl-amt tnum">{etb(v)}</td>)}</tr>
            <tr className="xl-sub"><td className="xl-label">Period gap</td>{GAP.map((v, i) => <td key={i} className="xl-amt tnum" style={{ color: v < 0 ? "var(--red)" : "var(--green-ink)" }}>{v < 0 ? "(" + etb(-v) + ")" : etb(v)}</td>)}</tr>
            <tr className="xl-orange"><td className="xl-label">Cumulative gap</td>{CUMGAP.map((v, i) => <td key={i} className="xl-amt tnum" style={{ color: v < 0 ? "var(--red)" : undefined }}>{v < 0 ? "(" + etb(-v) + ")" : etb(v)}</td>)}</tr>
          </tbody>
        </table>
      </div>

      {/* six shocks */}
      <div className="panel-h"><h3 style={{ fontSize: 15 }}>The six NBE standard rate shocks</h3><span className="chip chip-indigo" style={{ marginLeft: "auto" }}>Analysis-only</span></div>
      <div className="xl-wrap">
        <table className="xl">
          <colgroup><col style={{ minWidth: 240 }} /><col style={{ width: 160 }} /><col style={{ width: 160 }} /><col style={{ width: 140 }} /></colgroup>
          <thead><tr><th style={{ textAlign: "left" }}>Scenario</th><th className="xl-amt">ΔEVE (ETB M)</th><th className="xl-amt">12-mo ΔNII (ETB M)</th><th className="xl-amt">ΔEVE / Tier-1</th></tr></thead>
          <tbody>
            {IR_SHOCKS.map((s, i) => { const p = Math.abs(s.eve) / TIER1_IR * 100; const worst = s.eve === worstEVE; return (
              <tr key={i} className="xl-item xl-cell hit" onClick={() => setDrawer("shock" + i)}>
                <td className="xl-label">{s.name}{worst && <span className="chip chip-red" style={{ marginLeft: 8, fontSize: 10 }}>worst case</span>}</td>
                <td className="xl-amt tnum" style={{ color: s.eve < 0 ? "var(--red)" : "var(--green-ink)", fontWeight: 600 }}>{s.eve < 0 ? "(" + etb(-s.eve) + ")" : "+" + etb(s.eve)}</td>
                <td className="xl-amt tnum" style={{ color: s.nii < 0 ? "var(--red)" : "var(--green-ink)" }}>{s.nii < 0 ? "(" + etb(-s.nii) + ")" : "+" + etb(s.nii)}</td>
                <td className="xl-amt tnum" style={{ color: p > 15 ? "var(--red)" : undefined }}>{p.toFixed(1)}%</td>
              </tr>
            ); })}
          </tbody>
        </table>
      </div>
      <div className="mt16"><Banner kind="indigo" icon="flask">The six shocks are the NBE/Basel standardised set. The outlier test flags a bank if worst-case ΔEVE exceeds <b>15% of Tier-1</b> — here {evePct.toFixed(1)}%. All figures are analysis-only pending model approval.</Banner></div>

      <div className="mt20">
        <div className="section-label mb8">Model sign-off</div>
        <div className="approval">
          <div className="seg"><div className="lbl">Built by</div><div className="who">Dawit Bekele</div><div className="when">Jun 30</div></div>
          <div className="seg"><div className="lbl">Model policy</div><div className="who" style={{ color: "var(--amber)" }}>Pending</div><div className="when">Not yet approved</div></div>
          <div className="seg"><div className="lbl">Curve evidence</div><div className="who" style={{ color: "var(--amber)" }}>1 of 2</div><div className="when">EVE curve missing</div></div>
          <div className="seg" style={{ display: "grid", placeItems: "center", background: "var(--surface-2)" }}><button className="btn btn-dark btn-sm" onClick={() => setDrawer("approve")}>Submit for approval</button></div>
        </div>
      </div>

      <IRDrawer which={drawer} onClose={() => setDrawer(null)} go={go} />
    </div>
  );
}

function IRDrawer({ which, onClose, go }) {
  const [toastNode, showToast] = useToast();
  if (!which) return null;
  let title = "Detail", body = null, chip = null;
  if (which === "curve") { title = "Yield curve source"; chip = <StatusChip s="EVIDENCE_NEEDED" />;
    body = <React.Fragment><Banner kind="amber" icon="alert">The EVE discounting curve has no attached source. NII curve is verified; EVE curve evidence is required.</Banner>
      <Meta rows={[["NII curve", "Interbank + NBE policy rate"], ["EVE curve", <span style={{ color: "var(--red)" }}>Not attached</span>], ["Last refresh", "Jun 30, 08:40"], ["Owner", "Abel Mengist"]]} />
      <button className="btn btn-primary mt16" onClick={() => showToast("EVE curve evidence attached for checker review")}><Icon name="clipboard" size={15} /> Attach EVE curve evidence</button></React.Fragment>; }
  else if (which.startsWith("bucket")) { const i = +which.slice(6); title = "Repricing · " + IRRBB_BUCKETS[i];
    body = <Meta rows={[["Time bucket", IRRBB_BUCKETS[i]], ["Rate-sensitive assets", etb(RSA[i]) + " M"], ["Rate-sensitive liabilities", etb(RSL[i]) + " M"], ["Period gap", etb(GAP[i]) + " M"], ["Source", "Core banking · repricing schedule"]]}/>; }
  else if (which.startsWith("shock")) { const i = +which.slice(5); const s = IR_SHOCKS[i]; title = s.name; chip = <StatusChip s="STRESS_ONLY" />;
    body = <React.Fragment><Banner kind="indigo" icon="flask">Analysis-only. This shock never overwrites the baseline banking-book value.</Banner>
      <Meta rows={[["Scenario", s.name], ["ΔEVE", etb(s.eve) + " M"], ["12-month ΔNII", etb(s.nii) + " M"], ["ΔEVE / Tier-1", (Math.abs(s.eve) / TIER1_IR * 100).toFixed(1) + "%"], ["Model status", "Pending approval"]]} />
      <div className="cl mt16"><span className="cl-ic" style={{ background: "var(--amber-soft)", color: "var(--amber)" }}><Icon name="clipboard" size={15} /></span><div className="grow"><div style={{ fontWeight: 600 }}>Blocker: model policy not approved</div><div className="muted" style={{ fontSize: 12 }}>Owner: Dawit Bekele</div></div><button className="btn btn-ghost btn-sm" onClick={() => go("evidence")}>Open</button></div></React.Fragment>; }
  else if (which === "approve") { title = "Submit IRRBB model for approval"; chip = <StatusChip s="REVIEW_PENDING" />;
    body = <React.Fragment><Banner kind="amber" icon="lock">Submitting snapshots the model configuration (curves, shocks, assumptions) and routes it to the model-risk checker.</Banner>
      <Meta rows={[["Maker", "Dawit Bekele"], ["Checker", "Meron Haile"], ["Curve evidence", "1 of 2 attached"], ["Model policy", "Draft v0.9"]]} /></React.Fragment>; }
  return (
    <Drawer open={!!which} onClose={onClose}>
      <DrawerHead title={title} chip={chip} onClose={onClose} />
      <div className="drawer-body">{body}</div>
      <div className="drawer-foot"><span className="muted center gap6" style={{ fontSize: 12 }}><Icon name="info" size={14} /> Analysis-only · model governance</span><button className="btn btn-dark" style={{ marginLeft: "auto" }} onClick={onClose}>Done</button></div>
      {toastNode}
    </Drawer>
  );
}

/* ============================================================
   Behavioral ALM — assumptions + backtesting + model approval
   ============================================================ */
const BEHAV = [
  { no: "1", name: "NMD core / non-core split", val: "68% core", basis: "5-yr deposit stability", state: "REVIEW_PENDING", bt: "ok" },
  { no: "2", name: "Deposit decay rate (non-core)", val: "22% / yr", basis: "Observed runoff", state: "RECONCILED", bt: "ok" },
  { no: "3", name: "Deposit beta (rate pass-through)", val: "0.45", basis: "Regression on policy rate", state: "EVIDENCE_NEEDED", bt: "warn" },
  { no: "4", name: "Loan prepayment (CPR)", val: "9% / yr", basis: "Historical prepayment", state: "REVIEW_PENDING", bt: "ok" },
  { no: "5", name: "Term-deposit rollover", val: "74%", basis: "Maturity-bucket behaviour", state: "NEEDS_BANK_POLICY", bt: "fail" },
];

function BehavioralALM({ go, info }) {
  const [drawer, setDrawer] = useStateIR(null);
  const [toastNode, showToast] = useToast();
  return (
    <div className="main-inner">
      <PageHeader eyebrow="Prudential Risk · Modelling" title="Behavioral ALM"
        onInfo={() => info({ title: "Behavioral ALM", purpose: "The behavioral assumption set that feeds ALM and IRRBB — non-maturity-deposit core/non-core, decay, beta, loan prepayment, term-deposit rollover — each backtested and governed by model approval.", first: "Scan the backtest column: green passes, amber drifts, red fails. A failed backtest blocks the assumption from feeding ALM.", terms: [["Core deposits", "The stable share of non-maturity deposits."], ["Deposit beta", "How much of a rate move passes to deposit rates."], ["Backtest", "Model prediction vs observed outcome."]], next: ["Click an assumption to see its detail and policy basis.", "Click a backtest to see the error explanation.", "Submit the assumption set for model approval."], connections: ["Feeds the ALM maturity ladder and IRRBB bucketing.", "Needs historical behaviour data and bank policy."], guardrail: "Needs historical behaviour data, bank policy, and model approval before feeding official workpapers." })}
        right={<span className="center gap8"><StatusChip s="REVIEW_PENDING" lg /><button className="btn btn-dark btn-sm" onClick={() => setDrawer("approve")}>Submit for approval</button></span>} />

      <ModelBanner>Needs <b>historical behaviour data</b>, <b>bank policy</b>, and <b>model approval</b> before these assumptions can feed ALM / IRRBB.</ModelBanner>

      <div className="xl-wrap mb16">
        <table className="xl">
          <colgroup><col style={{ width: 40 }} /><col style={{ minWidth: 240 }} /><col style={{ width: 130 }} /><col style={{ minWidth: 200 }} /><col style={{ width: 120 }} /><col style={{ width: 130 }} /></colgroup>
          <thead><tr><th className="xl-no"></th><th style={{ textAlign: "left" }}>Behavioral assumption</th><th className="xl-amt">Value</th><th style={{ textAlign: "left" }}>Basis</th><th className="xl-amt">Backtest</th><th className="xl-amt">State</th></tr></thead>
          <tbody>
            {BEHAV.map(b => { const btc = { ok: ["chip-green", "Passing"], warn: ["chip-amber", "Drift"], fail: ["chip-red", "Failed"] }[b.bt]; return (
              <tr key={b.no} className="xl-item xl-cell hit" onClick={() => setDrawer(b.no)}>
                <td className="xl-no">{b.no}</td><td className="xl-label">{b.name}</td>
                <td className="xl-amt tnum" style={{ fontWeight: 600 }}>{b.val}</td>
                <td className="xl-label muted" style={{ fontSize: 12 }}>{b.basis}</td>
                <td className="xl-amt"><span className={"chip " + btc[0]}><span className="dot" />{btc[1]}</span></td>
                <td className="xl-amt"><StatusChip s={b.state} /></td>
              </tr>
            ); })}
          </tbody>
        </table>
      </div>
      <Banner kind="red" icon="alert"><b>1 backtest failed</b> (term-deposit rollover) and 1 is drifting (deposit beta). A failed backtest blocks that assumption from feeding the official ALM ladder until re-estimated and re-approved.</Banner>

      {drawer && <Drawer open={!!drawer} onClose={() => setDrawer(null)}>
        {drawer === "approve"
          ? <React.Fragment><DrawerHead title="Submit assumption set for approval" chip={<StatusChip s="REVIEW_PENDING" />} onClose={() => setDrawer(null)} />
              <div className="drawer-body"><Banner kind="amber" icon="lock">Submitting snapshots all five assumptions and routes them to the model-risk checker. Failed backtests must be resolved or waived with justification first.</Banner>
              <Meta rows={[["Maker", "Dawit Bekele"], ["Checker", "Meron Haile"], ["Failing backtests", "1 (must waive or fix)"], ["Drifting", "1"]]} /></div>
              <div className="drawer-foot"><button className="btn btn-ghost" onClick={() => setDrawer(null)}>Cancel</button><button className="btn btn-primary" style={{ marginLeft: "auto" }} onClick={() => setDrawer(null)}>Submit</button></div>
            </React.Fragment>
          : (() => { const b = BEHAV.find(x => x.no === drawer); return <React.Fragment>
              <DrawerHead title={b.name} sub={"Value " + b.val} chip={<StatusChip s={b.state} />} onClose={() => setDrawer(null)} />
              <div className="drawer-body">
                {b.bt === "fail" && <Banner kind="red" icon="alert"><b>Backtest failed.</b> Predicted rollover 74% vs observed 61% over the last 4 quarters — error exceeds the ±8% tolerance. Re-estimate before this feeds ALM.</Banner>}
                {b.bt === "warn" && <Banner kind="amber" icon="alert"><b>Backtest drifting.</b> Deposit beta 0.45 vs recent observed 0.53 — within tolerance but trending; monitor.</Banner>}
                <div className="mt16"><Meta rows={[["Assumption", b.name], ["Current value", b.val], ["Policy basis", b.basis], ["Backtest", b.bt === "ok" ? "Passing" : b.bt === "warn" ? "Drift" : "Failed"], ["Feeds", "ALM ladder · IRRBB bucketing"]]} /></div>
                <button className="btn btn-ghost btn-sm mt16" onClick={() => go("workpaper")}><Icon name="arrowR" size={14} /> See dependency in ALM</button>
                {(b.bt === "fail" || b.bt === "warn") && <div className="card card-pad mt16" style={{ background: "var(--surface-2)" }}>
                  <div className="section-label mb8">Re-estimate assumption</div>
                  <div className="meta" style={{ gridTemplateColumns: "130px 1fr" }}>
                    <dt className="muted">Current value</dt><dd className="tnum">{b.val}</dd>
                    <dt className="muted">Observed (recent)</dt><dd className="tnum" style={{ color: "var(--indigo)" }}>{b.bt === "fail" ? "61%" : "0.53"}</dd>
                    <dt className="muted">Proposed value</dt><dd><input defaultValue={b.bt === "fail" ? "62%" : "0.52"} style={{ width: 90, padding: "5px 8px", border: "1px solid var(--border-strong)", borderRadius: 6, fontSize: 13 }} /></dd>
                  </div>
                  <div className="section-label mt12 mb8">Backtest history</div>
                  <div className="center gap6" style={{ alignItems: "flex-end", height: 40 }}>
                    {[88, 84, 79, 72, 61].map((v, i) => <div key={i} style={{ flex: 1, height: v + "%", background: i === 4 ? "var(--red)" : "var(--indigo-line)", borderRadius: "3px 3px 0 0" }} title={"Q" + (i + 1) + ": " + v + "%"} />)}
                  </div>
                  <div className="muted" style={{ fontSize: 11, marginTop: 4 }}>Predicted vs observed, last 5 quarters — divergence widening.</div>
                  <button className="btn btn-primary btn-sm mt12" onClick={() => showToast("Re-estimation sent to model checker")}><Icon name="refresh" size={14} /> Re-estimate &amp; send to model checker</button>
                </div>}
              </div>
              <div className="drawer-foot"><span className="muted center gap6" style={{ fontSize: 12 }}><Icon name="info" size={14} /> Model assumption · re-approval required</span></div>
            </React.Fragment>; })()}
          </Drawer>}
      {toastNode}
    </div>
  );
}

/* ============================================================
   FTP / Profitability — internal management analytics
   ============================================================ */
const FTP_PROD = [
  { no: "1", name: "Retail mortgages", side: "Asset", contractual: "13.5%", ftp: "9.2%", spread: "4.3%", nim: "Br 184", contrib: 184 },
  { no: "2", name: "Corporate term loans", side: "Asset", contractual: "15.8%", ftp: "10.1%", spread: "5.7%", nim: "Br 412", contrib: 412 },
  { no: "3", name: "SME working capital", side: "Asset", contractual: "17.2%", ftp: "10.4%", spread: "6.8%", nim: "Br 256", contrib: 256 },
  { no: "4", name: "Savings deposits", side: "Liability", contractual: "7.0%", ftp: "9.6%", spread: "2.6%", nim: "Br 148", contrib: 148 },
  { no: "5", name: "Current accounts", side: "Liability", contractual: "0.0%", ftp: "8.8%", spread: "8.8%", nim: "Br 392", contrib: 392 },
  { no: "6", name: "Term deposits", side: "Liability", contractual: "11.2%", ftp: "9.9%", spread: "-1.3%", nim: "(Br 64)", contrib: -64 },
];

function FTP({ go, info }) {
  const [drawer, setDrawer] = useStateIR(null);
  const [toastNode, showToast] = useToast();
  const total = FTP_PROD.reduce((a, p) => a + p.contrib, 0);
  return (
    <div className="main-inner">
      <PageHeader eyebrow="Treasury · Management analytics" title="FTP / Profitability"
        onInfo={() => info({ title: "FTP / Profitability", purpose: "Funds transfer pricing — a matched-term FTP curve charges each product its true cost of funds, revealing risk-adjusted contribution by product, branch, customer and RM. Internal management analytics, not a regulatory return.", first: "Read the spread and contribution columns. Negative spread (term deposits here) means the product is priced below its FTP cost.", terms: [["FTP rate", "Internal transfer price of funds, matched to term."], ["Spread", "Contractual rate − FTP rate."], ["Contribution", "Spread × balance, net of liquidity add-ons."]], next: ["Click a product to see its profitability waterfall.", "Click the curve to see its source and approval.", "Open allocation policy for branch/RM splits."], connections: ["FTP curve derives from the market-data source.", "Needs FTP policy and curve approval."], guardrail: "Internal management analytics — not a regulatory export. Needs FTP policy and curve approval." })}
        right={<span className="center gap8"><StatusChip s="INTERNAL_WP" lg /><button className="btn btn-ghost btn-sm" onClick={() => setDrawer("curve")}><Icon name="trending" size={14} /> FTP curve</button></span>} />

      <ModelBanner>Internal management analytics — <b>not</b> a regulatory return. Needs an approved <b>FTP policy</b> and <b>curve</b>.</ModelBanner>

      <div className="grid g4 mb20">
        <Mini label="Net interest contribution" v={etb(total)} foot="ETB M · all products" tone="green" />
        <Mini label="Highest contributor" v="Corporate" foot="Br 412 M" />
        <Mini label="Negative-spread products" v="1" foot="Term deposits" tone="red" />
        <Mini label="Avg matched-term spread" v="4.5%" foot="Weighted" />
      </div>

      <div className="xl-wrap mb16">
        <table className="xl">
          <colgroup><col style={{ width: 40 }} /><col style={{ minWidth: 220 }} /><col style={{ width: 130 }} /><col style={{ width: 110 }} /><col style={{ width: 110 }} /><col style={{ width: 130 }} /></colgroup>
          <thead><tr><th className="xl-no"></th><th style={{ textAlign: "left" }}>Product · matched-term FTP · ETB millions</th><th className="xl-amt">Contractual</th><th className="xl-amt">FTP rate</th><th className="xl-amt">Spread</th><th className="xl-amt">Contribution</th></tr></thead>
          <tbody>
            {FTP_PROD.map(p => (
              <tr key={p.no} className="xl-item xl-cell hit" onClick={() => setDrawer(p.no)}>
                <td className="xl-no">{p.no}</td><td className="xl-label">{p.name} <span className="chip chip-neutral" style={{ fontSize: 10, padding: "1px 6px", marginLeft: 4 }}>{p.side}</span></td>
                <td className="xl-amt tnum">{p.contractual}</td><td className="xl-amt tnum">{p.ftp}</td>
                <td className="xl-amt tnum" style={{ color: p.contrib < 0 ? "var(--red)" : undefined, fontWeight: 600 }}>{p.spread}</td>
                <td className="xl-amt tnum" style={{ color: p.contrib < 0 ? "var(--red)" : "var(--green-ink)", fontWeight: 700 }}>{p.nim}</td>
              </tr>
            ))}
            <tr className="xl-orange"><td className="xl-no"></td><td className="xl-label">Total net interest contribution</td><td className="xl-amt"></td><td className="xl-amt"></td><td className="xl-amt"></td><td className="xl-amt tnum">{etb(total)}</td></tr>
          </tbody>
        </table>
      </div>
      <Banner kind="indigo" icon="info">Term deposits show a <b>negative matched-term spread</b> (priced 1.3% below FTP cost) — a management signal to reprice, not a regulatory breach. Branch / customer / RM profitability roll up from these product economics.</Banner>

      {drawer && <Drawer open={!!drawer} onClose={() => setDrawer(null)} wide={drawer !== "curve"}>
        {drawer === "curve"
          ? <React.Fragment><DrawerHead title="FTP curve source" chip={<StatusChip s="REVIEW_PENDING" />} onClose={() => setDrawer(null)} />
              <div className="drawer-body"><Banner kind="amber" icon="alert">The matched-term FTP curve is built from the interbank curve + liquidity add-ons. Curve approval is pending the Treasury Head.</Banner>
              <Meta rows={[["Base curve", "Interbank + NBE policy rate"], ["Liquidity add-on", "Term-dependent (0–180 bps)"], ["Method", "Matched-term (cashflow-weighted)"], ["Approval", "Pending — Hana Girma"]]} /></div>
              <div className="drawer-foot"><button className="btn btn-dark" style={{ marginLeft: "auto" }} onClick={() => setDrawer(null)}>Done</button></div>
            </React.Fragment>
          : (() => { const p = FTP_PROD.find(x => x.no === drawer); return <React.Fragment>
              <DrawerHead title={p.name + " · profitability"} sub={"Contribution " + p.nim + " M"} chip={<StatusChip s="INTERNAL_WP" />} onClose={() => setDrawer(null)} />
              <div className="drawer-body">
                <div className="section-label mb8">Contribution waterfall</div>
                {[[p.side === "Liability" ? "FTP credit (transfer price)" : "Contractual rate", p.side === "Liability" ? p.ftp : p.contractual], [p.side === "Liability" ? "less: rate paid to customer" : "less: FTP charge", "−" + (p.side === "Liability" ? p.contractual : p.ftp)], ["= Matched-term spread", p.spread], ["less: liquidity add-on", "−0.4%"], ["less: expected loss", "−0.6%"], ["= Risk-adjusted contribution", p.nim + " M"]].map((r, i) => (
                  <div key={i} className="between" style={{ padding: "8px 0", borderBottom: "1px solid var(--border)", fontWeight: i === 5 ? 700 : 400 }}><span style={{ fontSize: 13, color: i === 5 ? "var(--ink)" : "var(--ink-2)" }}>{r[0]}</span><span className="tnum" style={{ fontSize: 13 }}>{r[1]}</span></div>
                ))}
                {p.contrib < 0 && <div className="mt16"><Banner kind="red" icon="alert">Negative contribution — this product is funded below its matched-term cost. Management action: reprice or reduce tenor.</Banner></div>}
              </div>
              <div className="drawer-foot"><span className="muted center gap6" style={{ fontSize: 12 }}><Icon name="info" size={14} /> Internal analytics</span><button className="btn btn-dark" style={{ marginLeft: "auto" }} onClick={() => showToast("Allocation policy opened for internal review")}>Allocation policy</button></div>
            </React.Fragment>; })()}
      </Drawer>}
      {toastNode}
    </div>
  );
}

function Mini({ label, v, foot, tone }) {
  const c = { green: "var(--green-ink)", red: "var(--red)", indigo: "var(--indigo)" }[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 }}>{v}</div><div className="muted" style={{ fontSize: 11.5, marginTop: 4 }}>{foot}</div></div>;
}

Object.assign(window, { IRRBB, BehavioralALM, FTP });
