/* ============================================================
   OIL DEMAND — Sector × region demand simulation
   A faithful, interactive port of session_02_oil_demand_model.xlsx.
   A simple, transparent oil demand model by sector × region: build
   a defensible 2030 view, stress-test against scenarios, and compare
   to the IEA WEO 2024 scenarios.

   Model (per the Excel "Demand Model" sheet):
     2030 = 2023 × (1 + GDP_cagr × gdpMult × elasticity)^7
            × (1 − EV_reduction × evMult)   ← road transport only
   Reuses the .ep-* shell from the Energy Primer; adds .od-* classes
   (oil-demand.css) for the model surfaces.
   ============================================================ */
const { useState: odUse, useMemo: odMemo } = React;

/* ---------- structural constants (BLACK cells — do not edit) ---------- */
const OD_REGIONS = [
  { id: "oecd",  label: "OECD",           short: "OECD"  },
  { id: "china", label: "China",          short: "China" },
  { id: "india", label: "India",          short: "India" },
  { id: "other", label: "Other Non-OECD", short: "Other" },
];

const OD_SECTORS = [
  { id: "transport", label: "Transport (road)", road: true,  note: "EM motorization; DM saturated" },
  { id: "aviation",  label: "Aviation",         road: false, note: "EM aviation grows fast" },
  { id: "marine",    label: "Marine",           road: false, note: "Tracks trade growth" },
  { id: "petchem",   label: "Petrochemicals",   road: false, note: "Plastics demand; less substitutable" },
  { id: "industry",  label: "Industry",         road: false, note: "Efficiency gains offset growth" },
  { id: "buildings", label: "Buildings",        road: false, note: "DM heating decline; EM mostly LPG" },
  { id: "other",     label: "Other",            road: false, note: "Lubes, asphalt, misc" },
];

/* 2023 baseline demand, mb/d [sector][region] */
const OD_BASE = {
  transport: { oecd: 22.00, china: 6.00, india: 2.50, other: 16.00 },
  aviation:  { oecd: 3.80,  china: 1.70, india: 0.50, other: 1.50  },
  marine:    { oecd: 1.80,  china: 1.00, india: 0.30, other: 1.90  },
  petchem:   { oecd: 6.00,  china: 4.50, india: 2.00, other: 4.00  },
  industry:  { oecd: 3.50,  china: 1.70, india: 0.70, other: 2.60  },
  buildings: { oecd: 2.60,  china: 0.60, india: 0.30, other: 1.10  },
  other:     { oecd: 4.50,  china: 1.50, india: 0.60, other: 2.50  },
};

/* ---------- default inputs (BLUE cells — you change these) ---------- */
const OD_GDP_DEFAULT = { oecd: 0.018, china: 0.040, india: 0.062, other: 0.038 };

const OD_ELAST_DEFAULT = {
  transport: { oecd: 0.20,  china: 0.70, india: 1.00, other: 0.80 },
  aviation:  { oecd: 0.90,  china: 1.40, india: 1.50, other: 1.20 },
  marine:    { oecd: 0.50,  china: 0.60, india: 0.70, other: 0.60 },
  petchem:   { oecd: 0.60,  china: 1.20, india: 1.30, other: 1.00 },
  industry:  { oecd: 0.20,  china: 0.40, india: 0.60, other: 0.40 },
  buildings: { oecd: -0.30, china: 0.10, india: 0.20, other: 0.10 },
  other:     { oecd: 0.30,  china: 0.50, india: 0.60, other: 0.50 },
};

/* EV share of new sales 2030 → implied 2030 road-demand reduction */
const OD_EV_DEFAULT   = { oecd: 0.120, china: 0.193, india: 0.023, other: 0.010 };
const OD_EV_SHARE     = { oecd: 0.40,  china: 0.55,  india: 0.15,  other: 0.10  };

/* ---------- scenario overrides (do not edit unless redefining) ---------- */
const OD_SCENARIOS = [
  { id: "BASE",      label: "Base",          gdpMult: 1.00, evMult: 1.00, note: "Consensus view" },
  { id: "EV_AGG",    label: "EV Aggressive", gdpMult: 1.00, evMult: 1.50, note: "Faster fleet electrification" },
  { id: "EV_SLOW",   label: "EV Slow",       gdpMult: 1.00, evMult: 0.60, note: "Stalled EV adoption" },
  { id: "RECESSION", label: "Recession",     gdpMult: 0.85, evMult: 1.00, note: "GDP shock, ×0.85" },
];
const OD_SCEN_BY_ID = OD_SCENARIOS.reduce((m, s) => (m[s.id] = s, m), {});

const OD_HORIZON = 7; // 2023 → 2030

/* IEA WEO 2024 scenario benchmarks for 2030 world oil demand (mb/d) */
const OD_IEA = [
  { id: "steps", label: "IEA STEPS", value: 105.0, note: "Stated Policies" },
  { id: "aps",   label: "IEA APS",   value: 99.0,  note: "Announced Pledges" },
  { id: "nze",   label: "IEA NZE",   value: 87.0,  note: "Net Zero by 2050" },
];

/* ---------- model ---------- */
function odCloneInputs(src) {
  return {
    gdp: { ...src.gdp },
    ev: { ...src.ev },
    elast: OD_SECTORS.reduce((m, s) => (m[s.id] = { ...src.elast[s.id] }, m), {}),
  };
}
const OD_DEFAULT_INPUTS = {
  gdp: OD_GDP_DEFAULT,
  ev: OD_EV_DEFAULT,
  elast: OD_ELAST_DEFAULT,
};

/* Project a single sector × region cell to 2030. */
function odCell(sector, regionId, inputs, scen) {
  const base = OD_BASE[sector.id][regionId];
  const g = inputs.gdp[regionId] * scen.gdpMult;
  const e = inputs.elast[sector.id][regionId];
  let v = base * Math.pow(1 + g * e, OD_HORIZON);
  if (sector.road) v = v * (1 - inputs.ev[regionId] * scen.evMult);
  return v;
}

/* Full projection → { rows, regionTot23, regionTot30, world23, world30 } */
function odProject(inputs, scen) {
  const rows = OD_SECTORS.map((s) => {
    const c23 = {}, c30 = {};
    let w23 = 0, w30 = 0;
    OD_REGIONS.forEach((r) => {
      const b = OD_BASE[s.id][r.id];
      const v = odCell(s, r.id, inputs, scen);
      c23[r.id] = b; c30[r.id] = v;
      w23 += b; w30 += v;
    });
    return { sector: s, c23, c30, world23: w23, world30: w30 };
  });
  const regionTot23 = {}, regionTot30 = {};
  let world23 = 0, world30 = 0;
  OD_REGIONS.forEach((r) => {
    let a = 0, b = 0;
    rows.forEach((row) => { a += row.c23[r.id]; b += row.c30[r.id]; });
    regionTot23[r.id] = a; regionTot30[r.id] = b;
    world23 += a; world30 += b;
  });
  return { rows, regionTot23, regionTot30, world23, world30 };
}

const odWorld30 = (inputs, scen) => odProject(inputs, scen).world30;

/* ---------- sensitivity (tornado) ----------
   Perturb each driver ±25% relative and measure the swing in 2030
   world demand, holding the active scenario fixed. */
const OD_TORNADO_SWING = 0.25;
const OD_TORNADO_DRIVERS = [
  { id: "gdp_china",   label: "China GDP growth",        get: (i) => i.gdp.china,           set: (i, v) => (i.gdp.china = v) },
  { id: "gdp_india",   label: "India GDP growth",        get: (i) => i.gdp.india,           set: (i, v) => (i.gdp.india = v) },
  { id: "gdp_other",   label: "Other GDP growth",        get: (i) => i.gdp.other,           set: (i, v) => (i.gdp.other = v) },
  { id: "gdp_oecd",    label: "OECD GDP growth",         get: (i) => i.gdp.oecd,            set: (i, v) => (i.gdp.oecd = v) },
  { id: "ev_china",    label: "China EV reduction",      get: (i) => i.ev.china,            set: (i, v) => (i.ev.china = v) },
  { id: "ev_oecd",     label: "OECD EV reduction",       get: (i) => i.ev.oecd,             set: (i, v) => (i.ev.oecd = v) },
  { id: "el_petch_cn", label: "Petchem elasticity · CN", get: (i) => i.elast.petchem.china, set: (i, v) => (i.elast.petchem.china = v) },
  { id: "el_trans_ot", label: "Transport elast. · Other",get: (i) => i.elast.transport.other,set: (i, v) => (i.elast.transport.other = v) },
  { id: "el_avi_in",   label: "Aviation elasticity · IN",get: (i) => i.elast.aviation.india,set: (i, v) => (i.elast.aviation.india = v) },
];

function odTornado(inputs, scen, baseWorld30) {
  const bars = OD_TORNADO_DRIVERS.map((d) => {
    const lo = odCloneInputs(inputs); d.set(lo, d.get(lo) * (1 - OD_TORNADO_SWING));
    const hi = odCloneInputs(inputs); d.set(hi, d.get(hi) * (1 + OD_TORNADO_SWING));
    const loW = odWorld30(lo, scen);
    const hiW = odWorld30(hi, scen);
    return {
      label: d.label,
      low: loW - baseWorld30,
      high: hiW - baseWorld30,
      range: Math.abs(hiW - loW),
    };
  });
  bars.sort((a, b) => b.range - a.range);
  return bars;
}

/* ---------- format helpers ---------- */
const odF = (v, d = 2) => v.toFixed(d);
const odSigned = (v, d = 2) => (v >= 0 ? "+" : "−") + Math.abs(v).toFixed(d);
const odPct = (v, d = 1) => (v * 100).toFixed(d) + "%";

/* ============================================================
   SUB-COMPONENTS
   ============================================================ */
function OdResultTile({ label, value, unit, sub, tone }) {
  return (
    <div className={"od-tile " + (tone ? "od-tile--" + tone : "")}>
      <div className="od-tile-label">{label}</div>
      <div className="od-tile-value">{value}{unit && <span className="od-tile-unit">{unit}</span>}</div>
      {sub && <div className="od-tile-sub">{sub}</div>}
    </div>
  );
}

function OdSlider({ label, value, onChange, min, max, step, fmt, note }) {
  const pct = ((value - min) / (max - min)) * 100;
  return (
    <div className="od-slider">
      <div className="od-slider-head">
        <span className="od-slider-label">{label}</span>
        <span className="od-slider-val">{fmt(value)}</span>
      </div>
      <input
        type="range" className="od-range"
        min={min} max={max} step={step} value={value}
        style={{ "--od-fill": pct + "%" }}
        onChange={(e) => onChange(Number(e.target.value))}
      />
      {note && <div className="od-slider-note">{note}</div>}
    </div>
  );
}

/* ============================================================
   VIEW
   ============================================================ */
function OilDemandView() {
  const [scenarioId, setScenarioId] = odUse("BASE");
  const [inputs, setInputs] = odUse(() => odCloneInputs(OD_DEFAULT_INPUTS));

  const scen = OD_SCEN_BY_ID[scenarioId];

  const proj    = odMemo(() => odProject(inputs, scen), [inputs, scen]);
  const tornado = odMemo(() => odTornado(inputs, scen, proj.world30), [inputs, scen, proj.world30]);

  const change = proj.world30 - proj.world23;
  const cagr = Math.pow(proj.world30 / proj.world23, 1 / OD_HORIZON) - 1;

  const dirty =
    JSON.stringify(inputs) !== JSON.stringify(odCloneInputs(OD_DEFAULT_INPUTS)) ||
    scenarioId !== "BASE";

  /* input setters */
  const setGdp = (rid, v) => setInputs((s) => ({ ...odCloneInputs(s), gdp: { ...s.gdp, [rid]: v } }));
  const setEv  = (rid, v) => setInputs((s) => ({ ...odCloneInputs(s), ev:  { ...s.ev,  [rid]: v } }));
  const setElast = (sid, rid, v) => setInputs((s) => {
    const n = odCloneInputs(s);
    n.elast[sid][rid] = v;
    return n;
  });
  const reset = () => { setInputs(odCloneInputs(OD_DEFAULT_INPUTS)); setScenarioId("BASE"); };

  /* tornado scaling */
  const tMax = Math.max(0.01, ...tornado.map((b) => Math.max(Math.abs(b.low), Math.abs(b.high))));

  /* IEA comparison scaling */
  const cmpVals = [proj.world30, ...OD_IEA.map((s) => s.value)];
  const cmpMax = Math.max(...cmpVals) * 1.08;

  return (
    <div className="ep od">
      {/* ---- header bar ---- */}
      <div className="ep-bar">
        <div className="ep-bar-left">
          <span className="ep-bar-brand"><span className="ep-bar-dot" />Oil Demand</span>
          <span className="ep-bar-crumb"><span className="ep-bar-sep">·</span><span>Sector × region simulation · 2023 → 2030</span></span>
        </div>
        <div className="ep-bar-right">
          <span className="ep-bar-prog"><span>{scen.label} scenario</span></span>
        </div>
      </div>

      {/* ---- hero ---- */}
      <header className="ep-home-hero">
        <div>
          <div className="ep-home-eyebrow">A transparent demand model</div>
          <h1 className="ep-home-title">
            Build a defensible <em>2030 oil view</em>.
          </h1>
          <p className="ep-home-lede">
            A simple, transparent oil demand model by sector and region. Adjust GDP
            growth, GDP elasticities and EV penetration to reflect your view, toggle a
            scenario, and compare your 2030 estimate to the IEA WEO 2024 pathways.
            Demand is projected as <span className="od-formula">2030 = 2023 ×
            (1 + GDP × elasticity)<sup>7</sup> × EV<sub>reduction</sub></span>.
          </p>
        </div>
        <div className="ep-home-meta">
          <div className="ep-home-meta-row">
            <span className="ep-home-meta-lbl">Base year</span>
            <span className="ep-home-meta-val">{odF(proj.world23, 1)}<small>mb/d · world 2023</small></span>
          </div>
          <div className="ep-home-meta-row">
            <span className="ep-home-meta-lbl">Sectors</span>
            <span className="ep-home-meta-val">{OD_SECTORS.length} × {OD_REGIONS.length}<small>sectors × regions</small></span>
          </div>
          <div className="ep-home-meta-row">
            <span className="ep-home-meta-lbl">Horizon</span>
            <span className="ep-home-meta-val">7 yrs<small>2023 → 2030</small></span>
          </div>
        </div>
      </header>

      {/* ---- scenario toggle + key results ---- */}
      <section className="od-section">
        <div className="od-section-head">
          <h2 className="od-h2"><span className="od-h2-num">01</span>Scenario &amp; headline result</h2>
          <button className={"od-reset " + (dirty ? "is-active" : "")} onClick={reset} disabled={!dirty}>
            ↺ Reset to defaults
          </button>
        </div>

        <div className="od-scen-row" role="tablist" aria-label="Scenario">
          {OD_SCENARIOS.map((s) => (
            <button
              key={s.id} role="tab" aria-selected={s.id === scenarioId}
              className={"od-scen " + (s.id === scenarioId ? "is-active" : "")}
              onClick={() => setScenarioId(s.id)}>
              <span className="od-scen-label">{s.label}</span>
              <span className="od-scen-mult">GDP ×{odF(s.gdpMult)} · EV ×{odF(s.evMult)}</span>
              <span className="od-scen-note">{s.note}</span>
            </button>
          ))}
        </div>

        <div className="od-tiles">
          <OdResultTile label="World 2030 demand" value={odF(proj.world30, 1)} unit="mb/d" tone="key"
            sub={scen.label + " scenario"} />
          <OdResultTile label="Change 2023 → 2030" value={odSigned(change, 1)} unit="mb/d"
            tone={change >= 0 ? "up" : "down"} sub={"from " + odF(proj.world23, 1) + " mb/d"} />
          <OdResultTile label="CAGR 2023 → 2030" value={odSigned(cagr * 100, 2)} unit="%"
            tone={cagr >= 0 ? "up" : "down"} sub="annualized" />
          <OdResultTile label="vs IEA STEPS" value={odSigned(proj.world30 - OD_IEA[0].value, 1)} unit="mb/d"
            sub={"STEPS = " + odF(OD_IEA[0].value, 1) + " mb/d"} />
        </div>
      </section>

      {/* ---- assumptions (editable inputs) ---- */}
      <section className="od-section">
        <div className="od-section-head">
          <h2 className="od-h2"><span className="od-h2-num">02</span>Assumptions</h2>
          <span className="od-legend">
            <span className="od-legend-chip od-legend-chip--input" /> input you change
            <span className="od-legend-chip od-legend-chip--calc" /> calculated
          </span>
        </div>

        <div className="od-assume-grid">
          {/* GDP growth */}
          <div className="od-panel">
            <div className="od-panel-head">Annual GDP growth · 2023→2030 CAGR</div>
            {OD_REGIONS.map((r) => (
              <OdSlider key={r.id} label={r.label}
                value={inputs.gdp[r.id]} onChange={(v) => setGdp(r.id, v)}
                min={0} max={0.1} step={0.001} fmt={(v) => odPct(v, 1)} />
            ))}
          </div>

          {/* EV reduction */}
          <div className="od-panel">
            <div className="od-panel-head">EV impact · 2030 road-demand reduction</div>
            {OD_REGIONS.map((r) => (
              <OdSlider key={r.id} label={r.label}
                value={inputs.ev[r.id]} onChange={(v) => setEv(r.id, v)}
                min={0} max={0.4} step={0.005} fmt={(v) => odPct(v, 1)}
                note={"EV share of new sales 2030 ≈ " + odPct(OD_EV_SHARE[r.id], 0)} />
            ))}
          </div>

          {/* Elasticity matrix */}
          <div className="od-panel od-panel--wide">
            <div className="od-panel-head">Demand elasticity to GDP · by sector × region</div>
            <div className="od-matrix-scroll">
              <table className="od-matrix">
                <thead>
                  <tr>
                    <th className="od-matrix-corner">Sector</th>
                    {OD_REGIONS.map((r) => <th key={r.id}>{r.short}</th>)}
                  </tr>
                </thead>
                <tbody>
                  {OD_SECTORS.map((s) => (
                    <tr key={s.id}>
                      <th className="od-matrix-row" title={s.note}>{s.label}</th>
                      {OD_REGIONS.map((r) => (
                        <td key={r.id}>
                          <input
                            type="number" className="od-cellinput" step="0.05"
                            value={inputs.elast[s.id][r.id]}
                            onChange={(e) => setElast(s.id, r.id, Number(e.target.value))}
                          />
                        </td>
                      ))}
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
            <div className="od-panel-foot">
              Elasticity = % change in oil demand per 1% change in GDP. Negative values
              (e.g. OECD buildings) mean demand falls even as GDP grows.
            </div>
          </div>
        </div>
      </section>

      {/* ---- demand model table ---- */}
      <section className="od-section">
        <div className="od-section-head">
          <h2 className="od-h2"><span className="od-h2-num">03</span>Demand model · 2023 → 2030 (mb/d)</h2>
          <span className="od-section-tag">{scen.label}</span>
        </div>

        <div className="od-table-scroll">
          <table className="od-table">
            <thead>
              <tr>
                <th className="od-table-sector" rowSpan={2}>Sector</th>
                {OD_REGIONS.map((r) => <th key={r.id} colSpan={2} className="od-table-region">{r.short}</th>)}
                <th colSpan={2} className="od-table-region od-table-world">World</th>
              </tr>
              <tr className="od-table-sub">
                {OD_REGIONS.map((r) => (
                  <React.Fragment key={r.id}>
                    <th>'23</th><th className="od-col-30">'30</th>
                  </React.Fragment>
                ))}
                <th>'23</th><th className="od-col-30">'30</th>
              </tr>
            </thead>
            <tbody>
              {proj.rows.map((row) => (
                <tr key={row.sector.id}>
                  <th className="od-table-sector" title={row.sector.note}>
                    {row.sector.label}
                    {row.sector.road && <span className="od-ev-flag" title="EV reduction applied">EV</span>}
                  </th>
                  {OD_REGIONS.map((r) => (
                    <React.Fragment key={r.id}>
                      <td className="od-num">{odF(row.c23[r.id])}</td>
                      <td className="od-num od-col-30">{odF(row.c30[r.id])}</td>
                    </React.Fragment>
                  ))}
                  <td className="od-num od-num-strong">{odF(row.world23)}</td>
                  <td className="od-num od-num-strong od-col-30">{odF(row.world30)}</td>
                </tr>
              ))}
            </tbody>
            <tfoot>
              <tr className="od-table-total">
                <th className="od-table-sector">TOTAL</th>
                {OD_REGIONS.map((r) => (
                  <React.Fragment key={r.id}>
                    <td className="od-num">{odF(proj.regionTot23[r.id])}</td>
                    <td className="od-num od-col-30">{odF(proj.regionTot30[r.id])}</td>
                  </React.Fragment>
                ))}
                <td className="od-num od-num-strong">{odF(proj.world23)}</td>
                <td className="od-num od-num-strong od-col-30">{odF(proj.world30)}</td>
              </tr>
            </tfoot>
          </table>
        </div>
        <div className="od-table-foot">
          <span className="od-ev-flag">EV</span> sectors apply the road-transport EV reduction.
          World 2030 = <b>{odF(proj.world30, 2)} mb/d</b> ·
          change <b>{odSigned(change, 2)} mb/d</b> ·
          CAGR <b>{odSigned(cagr * 100, 2)}%</b>.
        </div>
      </section>

      {/* ---- IEA comparison ---- */}
      <section className="od-section">
        <div className="od-section-head">
          <h2 className="od-h2"><span className="od-h2-num">04</span>Comparison to IEA WEO 2024</h2>
        </div>
        <div className="od-cmp">
          <div className="od-cmp-row od-cmp-row--you">
            <div className="od-cmp-label">Your view<small>{scen.label}</small></div>
            <div className="od-cmp-track">
              <div className="od-cmp-bar od-cmp-bar--you" style={{ width: (proj.world30 / cmpMax * 100) + "%" }}>
                <span className="od-cmp-val">{odF(proj.world30, 1)}</span>
              </div>
            </div>
            <div className="od-cmp-delta">—</div>
          </div>
          {OD_IEA.map((s) => {
            const d = proj.world30 - s.value;
            return (
              <div className="od-cmp-row" key={s.id}>
                <div className="od-cmp-label">{s.label}<small>{s.note}</small></div>
                <div className="od-cmp-track">
                  <div className="od-cmp-bar" style={{ width: (s.value / cmpMax * 100) + "%" }}>
                    <span className="od-cmp-val">{odF(s.value, 1)}</span>
                  </div>
                </div>
                <div className={"od-cmp-delta " + (d >= 0 ? "is-up" : "is-down")}>
                  {odSigned(d, 1)}
                </div>
              </div>
            );
          })}
        </div>
        <div className="od-cmp-foot">
          Bars are 2030 world oil demand (mb/d). Delta = your view minus the IEA scenario.
          A view far above NZE implies the world is not on a net-zero trajectory.
        </div>
      </section>

      {/* ---- sensitivity tornado ---- */}
      <section className="od-section">
        <div className="od-section-head">
          <h2 className="od-h2"><span className="od-h2-num">05</span>Sensitivity · impact on 2030 demand</h2>
          <span className="od-section-tag">±{Math.round(OD_TORNADO_SWING * 100)}% each input</span>
        </div>
        <div className="od-tornado">
          {tornado.map((b) => (
            <div className="od-torn-row" key={b.label}>
              <div className="od-torn-label">{b.label}</div>
              <div className="od-torn-track">
                <span className="od-torn-axis" />
                {[b.low, b.high].map((val, i) => {
                  const w = Math.abs(val) / tMax * 50;
                  const pos = val < 0;
                  return (
                    <span key={i}
                      className={"od-torn-bar " + (pos ? "od-torn-bar--neg" : "od-torn-bar--pos")}
                      style={pos ? { right: "50%", width: w + "%" } : { left: "50%", width: w + "%" }} />
                  );
                })}
              </div>
              <div className="od-torn-range">±{odF(b.range / 2, 2)}</div>
            </div>
          ))}
        </div>
        <div className="od-cmp-foot">
          Each input is perturbed ±{Math.round(OD_TORNADO_SWING * 100)}% relative to its current
          value; bars show the resulting swing in 2030 world demand (mb/d), centred on the active
          case. The widest bars are the inputs your 2030 view is most sensitive to —
          spend your research time there.
        </div>
      </section>

      <div className="ep-home-footnote">
        Ported from <code>session_02_oil_demand_model.xlsx</code>. All elasticities and 2023
        baselines are approximate — refresh from IEA Oil 2024 or the Energy Institute Statistical
        Review before client use. Price feedback (demand elasticity to price) is not modeled here.
      </div>
    </div>
  );
}

window.OilDemandView = OilDemandView;
