/* Stethos — interactive "how it works" explainer for the landing page.
   Replaces the ambient animation with a guided, labeled, step-through story so a
   non-technical visitor understands exactly what the product does. */
const DSF = window.LatentHealthDesignSystem_2f3a71;
const { Badge: FBadge } = DSF;
const { useState, useEffect, useRef, useMemo } = React;

const N = 96;            // 4 days @ 24 ticks
const FLAG = 54;         // predicted crosses the flag line here
const THRESH = 0.30;
const clamp = (v, a, b) => Math.max(a, Math.min(b, v));

const STAGES = [
  {
    end: 24,
    tag: 'Day 1',
    title: 'Everything looks fine.',
    body: 'Margaret, 71, is admitted after a hip replacement. She talks with staff, presses her call bell when she needs something, and both lines sit high. Any dashboard today would show a normal patient.',
    color: 'var(--status-nominal)',
  },
  {
    end: 48,
    tag: 'Day 2',
    title: 'She goes quiet. That’s the warning.',
    body: 'Overnight she stops pressing the call bell. Her voice flattens; her conversations get shorter. A staff member reads this as “settling in.” Stethos reads it as withdrawal, the strongest signal that a stay is going wrong.',
    color: 'var(--status-warning)',
  },
  {
    end: 60,
    tag: 'Day 3',
    title: 'The predicted line crosses the flag.',
    body: 'Her current chart still looks acceptable, but the predicted discharge score drops below 0.30 and the patient is flagged. A satisfaction survey wouldn’t reveal any of this until ~40 days after she’s home.',
    color: 'var(--status-flagged)',
  },
  {
    end: 96,
    tag: 'The point',
    title: 'Caught in time, the outcome changes.',
    body: 'Because the flag fires during the stay, a nurse can actually intervene. The green line is what happens when someone steps in. The faded line is what happens if no one ever sees it: the outcome every survey-based system quietly accepts.',
    color: 'var(--status-nominal)',
  },
];

function activeStage(t) {
  for (let i = 0; i < STAGES.length; i++) if (t <= STAGES[i].end) return i;
  return STAGES.length - 1;
}

/* ---- big annotated chart ---- */
function ExplainerChart({ t, series }) {
  const W = 1000, H = 440, L = 56, R = 210, TOP = 30, BOT = 54;
  const { observed, preCrater, withInt, without } = series;
  const x = (i) => L + (i / (N - 1)) * (W - L - R);
  const y = (v) => H - BOT - clamp(v, 0, 1) * (H - TOP - BOT);
  const end = clamp(t, 1, N - 1);
  const pts = (arr, from, to) => {
    const o = [];
    for (let i = from; i <= to; i++) o.push(x(i).toFixed(1) + ',' + y(arr[i]).toFixed(1));
    return o.join(' ');
  };

  const preEnd = Math.min(end, FLAG);
  const curPre = preCrater[Math.min(end, FLAG)];
  const flagged = end >= FLAG;
  const inIntervention = end > FLAG;
  const preColor = flagged ? 'var(--status-flagged)' : 'var(--cyan-500)';
  const dayX = (d) => x(d * 24);

  return (
    <svg viewBox={`0 0 ${W} ${H}`} style={{ width: '100%', height: 'auto', display: 'block' }}>
      <defs>
        <linearGradient id="fx-crater" x1="0" y1="0" x2="0" y2="1">
          <stop offset="0%" stopColor={preColor} stopOpacity="0.14" />
          <stop offset="100%" stopColor={preColor} stopOpacity="0" />
        </linearGradient>
      </defs>

      {/* y guides */}
      {[0.25, 0.5, 0.75, 1].map(v => (
        <g key={v}>
          <line x1={L} x2={W - R} y1={y(v)} y2={y(v)} stroke="var(--border-faint)" strokeWidth="1" />
          <text x={L - 10} y={y(v) + 3} textAnchor="end" fontFamily="var(--font-mono)" fontSize="10" fill="var(--text-tertiary)">{v.toFixed(2)}</text>
        </g>
      ))}
      {/* day markers */}
      {[0, 1, 2, 3].map(d => (
        <text key={d} x={dayX(d)} y={H - 30} textAnchor="middle" fontFamily="var(--font-mono)" fontSize="11" fill="var(--text-tertiary)">Day {d + 1}</text>
      ))}

      {/* flag threshold */}
      <line x1={L} x2={W - R} y1={y(THRESH)} y2={y(THRESH)} stroke="var(--status-flagged)" strokeOpacity="0.55" strokeWidth="1.5" strokeDasharray="4 4" />
      <text x={W - R + 8} y={y(THRESH) + 4} fontFamily="var(--font-mono)" fontSize="11" fill="var(--status-flagged)">flag line · 0.30</text>

      {/* flag moment marker */}
      {flagged && (
        <g>
          <line x1={x(FLAG)} x2={x(FLAG)} y1={TOP} y2={H - BOT} stroke="var(--status-flagged)" strokeOpacity="0.4" strokeWidth="1" strokeDasharray="2 3" />
          <circle cx={x(FLAG)} cy={y(preCrater[FLAG])} r="5" fill="var(--status-flagged)" />
          <text x={x(FLAG)} y={TOP - 8} textAnchor="middle" fontFamily="var(--font-mono)" fontSize="11" fill="var(--status-flagged)">⚠ flagged</text>
        </g>
      )}

      {/* crater area + predicted line up to flag */}
      <path d={`M ${pts(preCrater, 0, preEnd)} L ${x(preEnd).toFixed(1)},${(H - BOT).toFixed(1)} L ${x(0).toFixed(1)},${(H - BOT).toFixed(1)} Z`} fill="url(#fx-crater)" />
      <polyline points={pts(preCrater, 0, preEnd)} fill="none" stroke={preColor} strokeWidth="3" strokeDasharray="6 5" strokeLinejoin="round" strokeLinecap="round" style={{ transition: 'stroke .3s var(--ease-out)' }} />

      {/* branches after flag */}
      {inIntervention && (
        <g>
          <polyline points={pts(without, FLAG, end)} fill="none" stroke="var(--status-flagged)" strokeOpacity="0.32" strokeWidth="2.5" strokeDasharray="3 5" strokeLinejoin="round" strokeLinecap="round" />
          <polyline points={pts(withInt, FLAG, end)} fill="none" stroke="var(--status-nominal)" strokeWidth="3" strokeLinejoin="round" strokeLinecap="round" />
          {end >= N - 1 && (
            <g fontFamily="var(--font-mono)" fontSize="12">
              <text x={x(end) + 8} y={y(withInt[end]) + 4} fill="var(--status-nominal)">with Stethos</text>
              <text x={x(end) + 8} y={y(without[end]) + 4} fill="var(--status-flagged)" fillOpacity="0.7">without</text>
            </g>
          )}
        </g>
      )}

      {/* observed (what staff see) */}
      <polyline points={pts(observed, 0, end)} fill="none" stroke="var(--text-secondary)" strokeWidth="2.5" strokeLinejoin="round" strokeLinecap="round" />

      {/* moving heads */}
      <circle cx={x(end)} cy={y(observed[end])} r="4.5" fill="var(--text-secondary)" />
      {!inIntervention && <circle cx={x(preEnd)} cy={y(curPre)} r="5.5" fill={preColor} />}
      {inIntervention && <circle cx={x(end)} cy={y(withInt[end])} r="5.5" fill="var(--status-nominal)" />}

      {/* end labels for the two base lines */}
      {end < FLAG + 4 && (
        <g fontFamily="var(--font-mono)" fontSize="12">
          <text x={x(preEnd) + 10} y={y(curPre) + 4} fill={preColor}>predicted at discharge</text>
        </g>
      )}
    </svg>
  );
}

function FlowExplainer() {
  const [t, setT] = useState(6);
  const [target, setTarget] = useState(24);
  const [playing, setPlaying] = useState(true);
  const raf = useRef(null);

  const series = useMemo(() => {
    const observed = [], preCrater = [], withInt = [], without = [];
    for (let i = 0; i < N; i++) {
      const p = i / (N - 1);
      observed.push(0.60 - 0.16 * p + 0.03 * Math.sin(p * 20));
      preCrater.push(clamp(0.84 - 0.74 * Math.pow(clamp((p - 0.22) / 0.40, 0, 1), 1.5), 0.10, 0.9));
    }
    const base = preCrater[FLAG];
    for (let i = 0; i < N; i++) {
      const k = clamp((i - FLAG) / (N - 1 - FLAG), 0, 1);
      withInt.push(base + (0.74 - base) * Math.pow(k, 0.7));
      without.push(clamp(base - 0.12 * k, 0.08, 1));
    }
    return { observed, preCrater, withInt, without };
  }, []);

  // animate t toward target, dwelling at each day boundary so the story lands,
  // then looping back to the start automatically when it reaches the end
  const holdUntil = useRef(0);
  const loopPending = useRef(false);
  useEffect(() => {
    let last = performance.now();
    const speed = 15; // ticks/sec — slow enough to read
    function step(now) {
      const dt = (now - last) / 1000; last = now;
      setT(prev => {
        const tgt = playing ? N - 1 : target;
        if (playing && now < holdUntil.current) return prev;
        if (loopPending.current) { loopPending.current = false; setTarget(24); return 6; }
        if (Math.abs(prev - tgt) < 0.6) {
          if (playing && prev >= N - 1) { holdUntil.current = now + 2600; loopPending.current = true; }
          return tgt;
        }
        const dir = tgt > prev ? 1 : -1;
        const next = clamp(prev + dir * speed * dt, 0, N - 1);
        if (playing && dir > 0) {
          for (const s of STAGES) {
            if (prev < s.end && next >= s.end && s.end < N - 1) { holdUntil.current = now + 2600; return s.end; }
          }
        }
        return next;
      });
      raf.current = requestAnimationFrame(step);
    }
    raf.current = requestAnimationFrame(step);
    return () => cancelAnimationFrame(raf.current);
  }, [target, playing]);

  const ti = Math.round(t);
  const stage = activeStage(ti);
  const st = STAGES[stage];
  const predNow = ti >= FLAG ? series.withInt[ti] : series.preCrater[ti];
  const obsNow = series.observed[ti];
  const statusVar = ti >= FLAG && ti <= 62 ? 'flagged' : (predNow < 0.5 ? 'warning' : 'nominal');
  const dayLabel = ['Day 1', 'Day 2', 'Day 3', 'Day 4'][Math.min(3, Math.floor(ti / 24))];
  const hh = String((Math.floor((ti % 24)) )).padStart(2, '0');

  function goStage(i) { setPlaying(false); setTarget(STAGES[i].end); }

  return (
    <div>
      {/* how-it-works strip */}
      <div style={{ display: 'flex', alignItems: 'stretch', gap: 12, marginTop: 40, flexWrap: 'wrap' }} className="lh-flow-strip">
        {[
          ['Signals you already collect', 'The call bell, the intercom mic, RTLS badges, the EMR: 16 signals your hospital already has.'],
          ['Our model, every hour', 'They collapse into four questions and one score, recomputed continuously for every patient.'],
          ['A discharge score, live', 'One number: how satisfied this patient will be at discharge, while you can still change it.'],
        ].map(([h, b], i) => (
          <React.Fragment key={i}>
            <div style={{ flex: 1, minWidth: 220, background: 'var(--surface-1)', border: '1px solid var(--border)', borderRadius: 'var(--radius-lg)', padding: '18px 20px' }}>
              <div style={{ fontFamily: 'var(--font-mono)', fontSize: 11, letterSpacing: '0.08em', textTransform: 'uppercase', color: 'var(--cyan-300)', marginBottom: 8 }}>{String(i + 1).padStart(2, '0')}</div>
              <div style={{ fontFamily: 'var(--font-display)', fontSize: 17, fontWeight: 500, color: 'var(--text-primary)', letterSpacing: '-0.01em', marginBottom: 6 }}>{h}</div>
              <div style={{ fontFamily: 'var(--font-body)', fontSize: 14, lineHeight: 1.5, color: 'var(--text-secondary)' }}>{b}</div>
            </div>
            {i < 2 && <div style={{ display: 'flex', alignItems: 'center', color: 'var(--text-tertiary)', fontSize: 20 }} className="lh-flow-arrow">→</div>}
          </React.Fragment>
        ))}
      </div>

      {/* chart card */}
      <div style={{ marginTop: 24, borderRadius: 'var(--radius-xl)', border: '1px solid var(--border)', background: 'var(--surface-1)', boxShadow: 'var(--shadow-card)', overflow: 'hidden' }}>
        {/* header: legend + live readout */}
        <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 20, padding: '18px 22px', borderBottom: '1px solid var(--border)', flexWrap: 'wrap' }}>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
            <div style={{ fontFamily: 'var(--font-display)', fontSize: 18, fontWeight: 500, letterSpacing: '-0.01em', color: 'var(--text-primary)' }}>One patient’s stay, hour by hour</div>
            <div style={{ display: 'flex', gap: 18, flexWrap: 'wrap' }}>
              <span style={{ display: 'inline-flex', alignItems: 'center', gap: 7, fontFamily: 'var(--font-body)', fontSize: 13, color: 'var(--text-secondary)' }}>
                <span style={{ width: 20, height: 3, background: 'var(--text-secondary)', borderRadius: 2 }} /> What the ward sees today
              </span>
              <span style={{ display: 'inline-flex', alignItems: 'center', gap: 7, fontFamily: 'var(--font-body)', fontSize: 13, color: 'var(--text-secondary)' }}>
                <span style={{ width: 20, height: 0, borderTop: '3px dashed var(--cyan-400)' }} /> What Stethos predicts
              </span>
            </div>
          </div>
          <div style={{ textAlign: 'right' }}>
            <div style={{ fontFamily: 'var(--font-mono)', fontSize: 11, letterSpacing: '0.1em', textTransform: 'uppercase', color: 'var(--text-tertiary)' }}>Predicted at discharge</div>
            <div style={{ display: 'flex', alignItems: 'baseline', gap: 10, justifyContent: 'flex-end' }}>
              <span style={{
                fontFamily: 'var(--font-mono)', fontVariantNumeric: 'tabular-nums', fontSize: 44, fontWeight: 600, lineHeight: 1.1,
                color: statusVar === 'flagged' ? 'var(--status-flagged)' : statusVar === 'warning' ? 'var(--status-warning)' : 'var(--status-nominal)',
                textShadow: statusVar === 'flagged' ? '0 0 22px var(--red-glow)' : 'none', transition: 'color .3s var(--ease-out)',
              }}>{predNow.toFixed(2)}</span>
              <FBadge variant={statusVar} dot>{statusVar}</FBadge>
            </div>
          </div>
        </div>

        {/* chart */}
        <div style={{ padding: '14px 16px 4px' }}>
          <ExplainerChart t={ti} series={series} />
        </div>

        {/* stage caption */}
        <div style={{ margin: '0 16px 16px', padding: '18px 20px', background: 'var(--surface-2)', border: '1px solid var(--border)', borderLeft: `3px solid ${st.color}`, borderRadius: 'var(--radius-md)' }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 8 }}>
            <span style={{ fontFamily: 'var(--font-mono)', fontSize: 11, letterSpacing: '0.1em', textTransform: 'uppercase', color: st.color }}>{st.tag}</span>
            <span style={{ fontFamily: 'var(--font-display)', fontSize: 18, fontWeight: 500, color: 'var(--text-primary)', letterSpacing: '-0.01em' }}>{st.title}</span>
          </div>
          <p style={{ fontFamily: 'var(--font-body)', fontSize: 15.5, lineHeight: 1.6, color: 'var(--text-secondary)', margin: 0, maxWidth: 760 }}>{st.body}</p>
        </div>

        {/* controls */}
        <div style={{ display: 'flex', alignItems: 'center', gap: 14, padding: '14px 22px', borderTop: '1px solid var(--border)', flexWrap: 'wrap' }}>
          <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap' }} className="lh-stage-btns">
            {STAGES.map((s, i) => (
              <button key={i} onClick={() => goStage(i)} style={{
                fontFamily: 'var(--font-mono)', fontSize: 11.5, padding: '6px 11px', borderRadius: 'var(--radius-sm)', cursor: 'pointer',
                border: '1px solid ' + (stage === i ? 'var(--cyan-tint-strong)' : 'var(--border)'),
                background: stage === i ? 'var(--cyan-tint)' : 'transparent',
                color: stage === i ? 'var(--cyan-300)' : 'var(--text-secondary)',
                transition: 'all var(--dur-fast) var(--ease-out)', whiteSpace: 'nowrap',
              }}>{i + 1}. {s.tag}</button>
            ))}
          </div>
          <div style={{ flex: 1 }} />
          <span style={{ fontFamily: 'var(--font-mono)', fontSize: 12, color: 'var(--text-tertiary)', minWidth: 96, textAlign: 'right' }}>{dayLabel} · {hh}:00</span>
        </div>
        <div style={{ padding: '0 22px 18px' }}>
          <input type="range" min="0" max={N - 1} value={ti} onChange={e => { setPlaying(false); const v = parseInt(e.target.value, 10); setT(v); setTarget(v); }}
            style={{ width: '100%', accentColor: 'var(--cyan-500)' }} aria-label="Scrub through the stay" />
        </div>
      </div>
    </div>
  );
}

Object.assign(window, { FlowExplainer });
