/* ============================================================
   market-sensor-rangestate.jsx — RangeState (V5.1 §5.6) overlay.
   A compact "Trend vs Range" card for the Risk Sensing page.
   Same pattern as MsrDecoupling: self-loads data/rangestate.json,
   renders NOTHING if the feed is absent (so it can never break the
   page before the backend ships the V5.1 feed). Non-scoring context
   only — never touches the SBS score or the volatility state.
   Exports window.MsrRangeState. Reuses .msr tokens from the core file.
   ============================================================ */
(function () {
  const { useState: rsState, useEffect: rsEffect, useCallback: rsCb } = React;

  const RS_TONE = { mustard: '#DCB482', slate: '#95A9AB' };
  const rsPct = (v, max) => Math.max(0, Math.min(100, v / max * 100));

  /* derive everything the card needs from the minimal feed */
  function rsView(d) {
    const st = d.state || {};
    const cond = d.conditions || {};
    const r2 = cond.r2_20 || {};
    const ov = d.overlay || {};
    const raw = !!st.raw_signal_today;
    let chip, gly, color, pills, fallbackDisplay;

    if (st.label === 'ON') {
      chip = 'SIDEWAYS';gly = '\u2194';color = st.color || 'mustard';
      fallbackDisplay = 'Range inside the uptrend';
      pills = [
      { d: 'off', t: 'Let-the-winner-run carry', v: ov.tp_carry || 'paused' },
      { d: 'hold', t: 'Aggressive breakouts', v: ov.aggressive || 'awareness-only' },
      { d: 'on', t: 'Buy the defended low', v: ov.defended_low || 'unlocked' }];

    } else if (raw) {
      chip = 'FORMING';gly = '\u25CB';color = st.color || 'mustard';
      fallbackDisplay = 'Range forming \u2014 not confirmed';
      pills = [{ d: 'hold', t: 'Signal unconfirmed', v: 'full rulebook live' }];
    } else {
      chip = 'TRENDING';gly = '\u25B2';color = st.color || 'slate';
      fallbackDisplay = 'Trending \u2014 rulebook fully live';
      pills = [{ d: 'on', t: 'No overlay', v: 'all setups live' }];
    }

    return {
      chip, gly, pills,
      tone: RS_TONE[color] || RS_TONE.mustard,
      line: st.one_line || st.display || fallbackDisplay,
      r2val: r2.value != null ? r2.value : null,
      r2thr: r2.threshold != null ? r2.threshold : 0.20,
      freq: st.freq_pct != null ? st.freq_pct : 17
    };
  }

  function MsrRangeState() {
    const [data, setData] = rsState(null);

    const load = rsCb(() => {
      const R = window.__resources || {};
      const url = R.rangestate || 'data/rangestate.json';
      fetch(url, { cache: 'no-store' }).
      then((r) => {if (!r.ok) throw new Error('rangestate.json ' + r.status);return r.json();}).
      then((d) => setData(d)).
      catch(() => setData(false)); /* false = checked, absent → render nothing */
    }, []);
    rsEffect(() => {load();}, [load]);

    if (!data) return null;

    const v = rsView(data);
    const pin = v.r2val != null ? rsPct(v.r2val, 1.0) : 0;
    const thr = rsPct(v.r2thr, 1.0);

    return (
      <div className="msr-sec">
        <div className="msr-sec-head">
          <div>
            <div className="msr-sec-eb">Regime overlay · §5.6</div>
            <h2 className="msr-sec-h">Trend vs Range</h2>
          </div>
          <span className="msr-sec-note">Is the tape trending or ranging? Context only — changes which setups are eligible, never sizing or stops.</span>
        </div>

        <div className="msr-rs-card" style={{ ['--tone']: v.tone }}>
          <div className="msr-rs-row1">
            <span className="msr-rs-chip"><span className="gly">{v.gly}</span>{v.chip}</span>
            <p className="msr-rs-line" dangerouslySetInnerHTML={{ __html: v.line }} />
          </div>

          {v.r2val != null &&
          <div className="msr-rs-meter">
            <div className="msr-rs-meter-lbl">
              <span>{'\u25C0'} Sideways</span>
              <span className="hi">Trending {'\u25B6'}&nbsp;&nbsp; R{'\u00B2'} <b>{v.r2val.toFixed(2)}</b></span>
            </div>
            <div className="msr-rs-scale">
              <div className="msr-rs-track" />
              <div className="msr-rs-zone" style={{ width: thr + '%' }} />
              <div className="msr-rs-pin" style={{ left: pin + '%' }} />
            </div>
          </div>}

          <div className="msr-rs-pills">
            {v.pills.map((p, i) =>
            <span className="msr-rs-pill" key={i}><span className={'d ' + p.d} />{p.t} · <b>{p.v}</b></span>
            )}
          </div>
        </div>
      </div>);
  }

  Object.assign(window, { MsrRangeState });
})();