/* ══ OM Group ERP — Analysis Studio · Scenario Simulator ══════════════════
   A sandbox over the live dataset. Every lever recalculates the full P&L,
   working capital, recovery, health and risk from the CURRENT ERP figures —
   nothing is written back, nothing is stored, and the base case re-derives
   itself the moment a transaction changes anywhere in the ERP.           */
const { useState: smSt, useEffect: smEf, useMemo: smMemo } = React;

const SM_KEY = 'omStudioScenarios';
function smLoad() { try { return JSON.parse(localStorage.getItem(SM_KEY) || '[]'); } catch (e) { return []; } }
function smSave(list) { try { localStorage.setItem(SM_KEY, JSON.stringify(list.slice(0, 24))); } catch (e) { } }

/* presets are generated from the live base metrics — never hardcoded */
function smPresets(ctx) {
  const c = ctx.cur, DEf = window.DecisionEngine.fmt;
  const out = [];
  if (c.dieselCost > 0) out.push({ label: 'Diesel +12%', L: { diesel: 12 } });
  if (c.transportCost > 0) out.push({ label: 'Freight −8%', L: { transport: -8 } });
  if (c.asp > 0) { const step = Math.max(5, Math.round(c.asp * 0.05 / 5) * 5); out.push({ label: 'Rate +' + DEf.rate(step) + ' / T', L: { price: +(step / c.asp * 100).toFixed(1) } }); }
  if (c.app > 0) out.push({ label: 'Crusher rate +6%', L: { purchRate: 6 } });
  out.push({ label: 'Volume +25%', L: { volume: 25 } });
  if (c.receivable > 0) out.push({ label: 'Payment slips 20 days', L: { payDelay: 20 } });
  if (c.dieselCost > 0) out.push({ label: 'Recovery +15 pp', L: { recovery: 15 } });
  if (ctx.custRows.length) out.push({ label: 'Largest buyer leaves', L: { topCustLoss: 100 } });
  out.push({ label: 'Monsoon squeeze', L: { volume: -22, price: -3, diesel: 6 } });
  out.push({ label: 'Peak season push', L: { volume: 30, price: 4, transport: 8 } });
  return out;
}

function StudioSimulator({ ctx }) {
  const DEng = window.DecisionEngine;
  const levers = smMemo(() => DEng.levers(ctx), [ctx]);
  const [L, setL] = smSt(() => Object.assign({}, DEng.ZERO_LEVERS));
  const [saved, setSaved] = smSt(smLoad);
  const [name, setName] = smSt('');
  const set = (id, v) => setL(p => Object.assign({}, p, { [id]: v }));
  const reset = () => setL(Object.assign({}, DEng.ZERO_LEVERS));
  const dirty = Object.keys(L).some(k => Number(L[k]) !== 0);

  const base = smMemo(() => DEng.baseline(ctx), [ctx]);
  const sim = smMemo(() => DEng.simulate(ctx, L), [ctx, JSON.stringify(L)]);
  const presets = smMemo(() => smPresets(ctx), [ctx]);
  const groups = smMemo(() => {
    const g = {}; levers.forEach(l => (g[l.group] = g[l.group] || []).push(l)); return g;
  }, [levers]);

  /* what each active lever contributed to net profit, isolated */
  const attribution = smMemo(() => {
    const active = Object.keys(L).filter(k => Number(L[k]) !== 0);
    if (!active.length) return [];
    return active.map(k => {
      const only = Object.assign({}, DEng.ZERO_LEVERS); only[k] = L[k];
      const r = DEng.simulate(ctx, only);
      const def = levers.find(l => l.id === k);
      return { id: k, label: def ? def.label : k, value: r.netProfit - base.netProfit, set: L[k], unit: def ? def.unit : '' };
    }).sort((a, b) => Math.abs(b.value) - Math.abs(a.value));
  }, [ctx, JSON.stringify(L), base]);

  const wf = smMemo(() => [
    { label: 'Revenue', short: 'Revenue', value: sim.revenue, color: '#16A34A' },
    { label: 'Purchase', short: 'Purchase', value: -sim.purchaseValue, color: '#DC2626' },
    { label: 'Transport', short: 'Transport', value: -sim.transportCost, color: '#DC2626' },
    { label: 'Diesel Margin', short: 'Diesel', value: sim.dieselMargin, color: '#F97316' },
    { label: 'Net Profit', short: 'Net', value: sim.netProfit, color: sim.netProfit >= 0 ? '#15803D' : '#DC2626', total: true },
  ], [sim]);

  function saveScenario() {
    const nm = (name || '').trim() || 'Scenario ' + (saved.length + 1);
    const next = [{ name: nm, L: Object.assign({}, L), at: Date.now() }].concat(saved.filter(s => s.name !== nm));
    setSaved(next); smSave(next); setName('');
    window.toast && window.toast('Scenario “' + nm + '” saved', 'ok');
  }
  function delScenario(nm) { const next = saved.filter(s => s.name !== nm); setSaved(next); smSave(next); }

  return (
    <div>
      <p className="st-lede">
        Every slider re-runs the whole P&amp;L against the <b>{ctx.ds.sales.length + ctx.ds.purchases.length} live records</b> currently in scope
        for {ctx.period.label}. Nothing is written back to the ERP — this is a sandbox, and closing it leaves your data exactly as it was.
      </p>

      <div className="st-2col">
        {/* ── levers ─────────────────────────────────────────────── */}
        <div className="i-card" style={{ padding: '14px 15px' }}>
          <div className="i-card-hd">
            <div><div className="i-card-t">Assumptions</div><div className="i-card-s">{levers.length} levers derived from live figures</div></div>
            {dirty && <button className="i-crumb" onClick={reset}>Reset</button>}
          </div>
          <div style={{ display: 'flex', gap: 5, flexWrap: 'wrap', marginBottom: 12 }}>
            {presets.map(p => (
              <button key={p.label} className="i-ctl sm"
                onClick={() => setL(Object.assign({}, window.DecisionEngine.ZERO_LEVERS, p.L))}>{p.label}</button>
            ))}
          </div>
          {Object.keys(groups).map(g => (
            <div key={g}>
              <div className="st-lev-grp">{g}</div>
              <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
                {groups[g].map(def => <StLever key={def.id} def={def} value={L[def.id]} onChange={set} />)}
              </div>
            </div>
          ))}
          <div style={{ marginTop: 14, paddingTop: 12, borderTop: '1px solid var(--iLine)' }}>
            <div className="st-lev-grp" style={{ marginTop: 0 }}>Saved scenarios</div>
            <div style={{ display: 'flex', gap: 6 }}>
              <input className="st-tool-input" style={{ flex: 1 }}
                placeholder="Name this scenario…" value={name} onChange={e => setName(e.target.value)} onKeyDown={e => { if (e.key === 'Enter') saveScenario(); }} />
              <button className="i-ctl" onClick={saveScenario} disabled={!dirty}>Save</button>
            </div>
            {saved.length > 0 && (
              <div className="st-ws-list" style={{ marginTop: 8 }}>
                {saved.map(s => (
                  <span key={s.name} className="st-ws-item" onClick={() => setL(Object.assign({}, window.DecisionEngine.ZERO_LEVERS, s.L))}>
                    {s.name}<button onClick={e => { e.stopPropagation(); delScenario(s.name); }} aria-label="Delete">×</button>
                  </span>
                ))}
              </div>
            )}
          </div>
        </div>

        {/* ── outcome ────────────────────────────────────────────── */}
        <div style={{ display: 'flex', flexDirection: 'column', gap: 10, minWidth: 0 }}>
          <div className="st-res">
            <StRes label="Revenue" value={sim.revenue} base={base.revenue} color="#16A34A" good="up" />
            <StRes label="Gross Profit" value={sim.grossProfit} base={base.grossProfit} color="#F97316" good="up" />
            <StRes label="Net Profit" value={sim.netProfit} base={base.netProfit} color={sim.netProfit >= 0 ? '#15803D' : '#DC2626'} good="up" />
            <StRes label="Net Margin" value={sim.netMargin} base={base.netMargin} kind="pct" color="#7C3AED" good="up" />
            <StRes label="Cash Flow" value={sim.cashFlow} base={base.cashFlow} color="#0891B2" good="up" />
            <StRes label="Working Capital" value={sim.workingCapital} base={base.workingCapital} color="#CA8A04" good="down" />
            <StRes label="Receivable" value={sim.receivable} base={base.receivable} color="#DC2626" good="down" note={sim.dso.toFixed(0) + ' days outstanding'} />
            <StRes label="Profit / Tonne" value={sim.profitPerTon} base={base.profitPerTon} kind="rate" color="#2563EB" good="up" />
            <StRes label="Annualised Profit" value={sim.annualisedNetProfit} base={base.annualisedNetProfit} color="#15803D" good="up" note="at this run rate" />
            <StRes label="Health Score" value={sim.healthScore} base={base.healthScore} kind="int" color="#0D9488" good="up" note="composite / 100" />
            <StRes label="Risk Score" value={sim.riskScore} base={base.riskScore} kind="int" color="#DC2626" good="down" note="lower is better" />
            <StRes label="Recovery Rate" value={sim.recoveryRate} base={base.recoveryRate} kind="pct" color="#16A34A" good="up" />
          </div>

          <div className="i-grid i-g23">
            <div className="i-card">
              <div className="i-card-hd"><div><div className="i-card-t">Simulated profit build-up</div><div className="i-card-s">Same waterfall the Profit Engine uses — recalculated under your assumptions</div></div></div>
              <window.IC.Waterfall height={248} steps={wf} />
            </div>
            <div className="i-card">
              <div className="i-card-hd"><div><div className="i-card-t">What each lever did</div><div className="i-card-s">Net profit effect of each assumption in isolation</div></div></div>
              {attribution.length === 0
                ? <StEmpty title="Base case" msg="Move any assumption and its isolated contribution to net profit appears here, so you can see which lever is actually doing the work." />
                : <div className="ic-rank">
                  {attribution.map((a, i) => {
                    const max = Math.max.apply(null, attribution.map(z => Math.abs(z.value))) || 1;
                    const col = a.value >= 0 ? '#16A34A' : '#DC2626';
                    return (
                      <div className="ic-rank-row" key={a.id} style={{ animationDelay: (i * 50) + 'ms' }}>
                        <div className="ic-rank-i">{i + 1}</div>
                        <div className="ic-rank-main">
                          <div className="ic-rank-top">
                            <span className="ic-rank-lbl">{a.label} <em style={{ fontStyle: 'normal', color: 'var(--iInk3)', fontWeight: 600 }}>{(a.set > 0 ? '+' : '') + a.set}{a.unit === '%' ? '%' : a.unit === 'pp' ? 'pp' : 'd'}</em></span>
                            <span className="ic-rank-val" style={{ color: col }}>{(a.value >= 0 ? '+' : '−') + window.IC.short(Math.abs(a.value))}</span>
                          </div>
                          <div className="ic-rank-track"><div className="ic-rank-fill" style={{ width: (Math.abs(a.value) / max * 100) + '%', background: col }}></div></div>
                        </div>
                      </div>
                    );
                  })}
                  <div style={{ marginTop: 10, paddingTop: 9, borderTop: '1px dashed var(--iLine)', fontSize: 10.5, color: 'var(--iInk2)', lineHeight: 1.55 }}>
                    Individual effects sum to {window.IC.short(attribution.reduce((s, a) => s + a.value, 0))}; the combined scenario delivers{' '}
                    {window.IC.short(sim.netProfit - base.netProfit)}. The difference is interaction — levers that multiply each other rather than add.
                  </div>
                </div>}
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

Object.assign(window, { StudioSimulator });
