/* Strive — Interactive Case. Pick from 6 real cases (product / ops / growth /
   tech). Each plays as a 3-turn mini-interview: your call → a follow-up → one
   more — Strive reacting each turn — then the proof clip + readiness + download. */

function IWave({ bars, refEl }) {
  var arr = [];
  var hs = [55,90,40,80,60,95,35,70,50,85,45,75,92,38,65,52];
  for (var i = 0; i < bars; i++) arr.push(<i key={i} style={{ height: hs[i % hs.length] + '%' }} />);
  return <div className="wave" ref={refEl}>{arr}</div>;
}

function FauxQR() {
  var seed = 0b1011010011100101101001110;
  var cells = [];
  for (var y = 0; y < 11; y++) for (var x = 0; x < 11; x++) {
    var corner = (x < 3 && y < 3) || (x > 7 && y < 3) || (x < 3 && y > 7);
    var on = corner || (((x * 7 + y * 13 + (seed >> ((x + y) % 24))) & 3) === 0);
    if (on) cells.push(<rect key={x + '-' + y} x={x * 9 + 3} y={y * 9 + 3} width="8" height="8" rx="1.5" />);
  }
  return (
    <svg className="iqr" viewBox="0 0 105 105" aria-label="Scan to download Strive">
      <rect x="0" y="0" width="105" height="105" rx="14" fill="#fff" />
      <g fill="#0A0A0A">{cells}</g>
    </svg>
  );
}

// ─── 6 cases, each a 3-turn mini-interview ───────────────────────────────────
var CASES = [
  { id:'blinkit', company:'Blinkit', cat:'OPS', color:'var(--tf-lime)', role:'Ops APM', clip:'Mumbai missing milk',
    turns:[
      { q:"Blinkit promised groceries in 12 minutes. In one Mumbai cluster, the promise just broke. Where do you look first?",
        options:[
          {id:'a',t:"Blame the riders — they're slow today.",d:16,note:"Riders are the symptom, not the cause. The sharp move is upstream — <em>what made them slow?</em>"},
          {id:'b',t:"Check if demand spiked faster than the store could pick.",d:60,note:"That's the instinct we hire for — supply vs. demand before blame. Let's go deeper."},
          {id:'c',t:"Flood the zone with more riders, right now.",d:34,note:"Fast — but it treats the symptom. <em>What if picking, not delivery, is the bottleneck?</em>"} ] },
      { q:"You suspect the store can't pick fast enough. What do you check to confirm it?",
        options:[
          {id:'a',t:"Pick time vs. order inflow, per 10-minute window.",d:60,note:"Exactly — find the window where the queue builds."},
          {id:'b',t:"Total orders for the day.",d:20,note:"Too coarse. The break happens in minutes, not days."},
          {id:'c',t:"Rider app-store reviews.",d:12,note:"Noise. Measure the queue, not opinions."} ] },
      { q:"Picking is the bottleneck, but only at the 8pm peak. What's your first fix?",
        options:[
          {id:'a',t:"Hire more pickers, permanently.",d:30,note:"Maybe — but the peak is 90 minutes. Permanent cost for a spike?"},
          {id:'b',t:"Pre-stage top SKUs and add peak-only pickers.",d:60,note:"Sharp — match capacity to the actual shape of the peak."},
          {id:'c',t:"Raise the promise to 20 minutes.",d:22,note:"Last resort — you'd break the brand promise to patch ops."} ] } ] },

  { id:'razorpay', company:'Razorpay', cat:'TECH', color:'var(--tf-sky)', role:'Backend Engineer', clip:'Rate limiter at 50k RPS',
    turns:[
      { q:"Razorpay's payments API must survive a flash sale at 50,000 req/sec without one merchant starving the rest. How do you rate-limit?",
        options:[
          {id:'a',t:"One global counter in app-server memory.",d:16,note:"It won't survive a second box, and dies on restart. <em>What about horizontal scale?</em>"},
          {id:'b',t:"Per-merchant token bucket in Redis.",d:60,note:"Strong — per-key isolation plus a shared store is the bar. Let's stress it."},
          {id:'c',t:"Drop requests randomly when CPU is high.",d:30,note:"Protects the box but punishes good merchants. <em>How do you stay fair?</em>"} ] },
      { q:"Per-merchant buckets in Redis — but Redis becomes the hot shard. How do you keep it fast?",
        options:[
          {id:'a',t:"Shard by merchant key with a local pre-check.",d:60,note:"Yes — partition the load and fail fast locally before the round-trip."},
          {id:'b',t:"Just use a bigger Redis box.",d:22,note:"Vertical scaling delays the wall — it doesn't remove it."},
          {id:'c',t:"Skip the cache, hit the DB.",d:12,note:"That moves the hot spot to the database. Worse."} ] },
      { q:"A merchant got 429s during a legitimate spike. What do you offer them?",
        options:[
          {id:'a',t:"Expose a burst allowance, then drain.",d:60,note:"The token bucket already gives burst — surface it cleanly."},
          {id:'b',t:"Remove their limit entirely.",d:18,note:"Now one merchant can starve the rest again."},
          {id:'c',t:"Tell them to retry.",d:28,note:"Retries without backoff make the storm worse."} ] } ] },

  { id:'swiggy', company:'Swiggy', cat:'GROWTH', color:'var(--tf-pink)', role:'Growth PM', clip:'Surge in the rain',
    turns:[
      { q:"It's pouring, demand triples, and Swiggy's surge fee makes users feel gouged. How do you price without losing trust?",
        options:[
          {id:'a',t:"Cap surge at 1.5× and eat the rest.",d:32,note:"Kind — but you may starve supply when you need it most."},
          {id:'b',t:"Show the 'why' — surge funds rider rain-pay.",d:60,note:"That's the move — reframe a fee as fairness, out loud."},
          {id:'c',t:"Hide the surge inside item prices.",d:14,note:"Smooth today, trust-bomb tomorrow. <em>What if someone screenshots two prices?</em>"} ] },
      { q:"You show the surge reason. How do you prove the money actually reaches riders?",
        options:[
          {id:'a',t:"A per-order rider-pay line on the receipt.",d:60,note:"Transparency you can audit beats a slogan."},
          {id:'b',t:"A blog post about fairness.",d:20,note:"Nobody reads it at checkout."},
          {id:'c',t:"Just say 'trust us'.",d:12,note:"Trust is the thing you're trying to earn — you can't assume it."} ] },
      { q:"Surge still feels steep at 2.5×. How do you soften it without killing supply?",
        options:[
          {id:'a',t:"Tiered surge + a free-delivery option if you wait.",d:60,note:"Give the user agency: pay now, or wait a little."},
          {id:'b',t:"Flat 1.2× always.",d:24,note:"Predictable — but supply vanishes exactly when it's scarce."},
          {id:'c',t:"Turn surge off in the rain.",d:16,note:"Then no rider rides, and nobody gets dinner."} ] } ] },

  { id:'cred', company:'CRED', cat:'GROWTH', color:'var(--tf-purple)', role:'Growth PM', clip:'Referrals that stall',
    turns:[
      { q:"CRED users love the product but won't refer friends. The reward is generous. What's blocking the share?",
        options:[
          {id:'a',t:"Bump the reward higher.",d:22,note:"If reward were the blocker, generous would already work."},
          {id:'b',t:"It's status — referring feels like admitting you need a perk.",d:60,note:"Sharp read on a premium brand — the cost is social, not financial."},
          {id:'c',t:"Add a referral banner everywhere.",d:26,note:"More surface, same resistance. <em>Why would someone want to be seen referring?</em>"} ] },
      { q:"It's a status problem. How do you make sharing feel like flexing, not begging?",
        options:[
          {id:'a',t:"Make the invite a scarce, branded artifact.",d:60,note:"Status flips when the invite itself signals belonging."},
          {id:'b',t:"Offer bigger cashback.",d:20,note:"Back to bribing — which already failed."},
          {id:'c',t:"Send more reminders.",d:14,note:"Nagging a status-conscious user backfires."} ] },
      { q:"Invites are now exclusive. How do you keep the network high-quality as it spreads?",
        options:[
          {id:'a',t:"Tie invite quota to the referrer's standing.",d:60,note:"Skin in the game keeps the network clean."},
          {id:'b',t:"Open invites to everyone.",d:18,note:"You just deleted the scarcity you built."},
          {id:'c',t:"Manually review each invite.",d:26,note:"Doesn't scale past the first city."} ] } ] },

  { id:'zerodha', company:'Zerodha', cat:'PRODUCT', color:'var(--tf-orange)', role:'Product PM', clip:'Death at KYC',
    turns:[
      { q:"Zerodha signups look healthy until KYC, where half of users vanish. The flow is legally required. How do you stop the bleed?",
        options:[
          {id:'a',t:"Shorten KYC by skipping required steps.",d:12,note:"Can't — it's regulatory. <em>What can you change that isn't the law?</em>"},
          {id:'b',t:"Find exactly where in KYC they drop, then de-risk that step.",d:60,note:"Yes — instrument first, fix the worst step, don't boil the ocean."},
          {id:'c',t:"Email everyone who dropped.",d:28,note:"A patch, not a fix. <em>Why did they leave at that step?</em>"} ] },
      { q:"Drop-off peaks at document upload. What's the most likely cause?",
        options:[
          {id:'a',t:"Camera + file-size friction on cheap phones.",d:60,note:"Watch a real upload on a budget Android — that's where it dies."},
          {id:'b',t:"Users just don't want to invest.",d:22,note:"Then they wouldn't have started. Look closer."},
          {id:'c',t:"The server is slow.",d:30,note:"Possible — but measure before you blame infra."} ] },
      { q:"You fix upload. Where's the second-biggest leak likely to be?",
        options:[
          {id:'a',t:"The wait for manual approval.",d:60,note:"Dead time kills momentum — set expectations or speed it up."},
          {id:'b',t:"The landing page.",d:18,note:"They're already past it — wrong end of the funnel."},
          {id:'c',t:"Pricing.",d:16,note:"Zerodha's hook is low cost — unlikely the blocker here."} ] } ] },

  { id:'meesho', company:'Meesho', cat:'TECH', color:'var(--tf-blink-yellow)', role:'Backend Engineer', clip:'100M notifications',
    turns:[
      { q:"Meesho needs to send 100M personalised notifications at 8pm without melting the DB or spamming users. How do you fan out?",
        options:[
          {id:'a',t:"Loop all users, write each send synchronously.",d:16,note:"Your DB falls over by user one million. <em>What decouples send from read?</em>"},
          {id:'b',t:"Pre-compute segments, queue jobs, rate-limit per device.",d:60,note:"That's the architecture — batch upstream, smooth downstream."},
          {id:'c',t:"Send them all in one giant 8pm batch.",d:24,note:"One spike, one outage. <em>How do you spread the load?</em>"} ] },
      { q:"Jobs are queued, but the push provider blips and retries pile up. How do you avoid a storm?",
        options:[
          {id:'a',t:"Exponential backoff + idempotency keys.",d:60,note:"Backoff plus dedupe is exactly the bar."},
          {id:'b',t:"Retry immediately, as fast as possible.",d:12,note:"You just DDoS'd your own provider."},
          {id:'c',t:"Drop failures silently.",d:22,note:"Now you can't tell who never got told."} ] },
      { q:"Sends work, but users feel spammed. How do you protect their attention?",
        options:[
          {id:'a',t:"Per-user frequency cap + a relevance score.",d:60,note:"Respect the inbox, or you train users to mute you."},
          {id:'b',t:"Send more, louder.",d:12,note:"The fastest way to the 'turn off notifications' button."},
          {id:'c',t:"Only ever send at 8pm.",d:26,note:"Predictable, but one window for 100M people is its own spike."} ] } ] },
];

var BASE = 1780;

function InteractiveCase() {
  const [active, setActive] = React.useState(0);
  const [turn, setTurn] = React.useState(0);
  const [thread, setThread] = React.useState([]);   // [{turn, choiceText, note}]
  const [shown, setShown] = React.useState(BASE);    // displayed readiness number
  const shownRef = React.useRef(BASE);
  const targetRef = React.useRef(BASE);              // absolute cumulative target
  const [done, setDone] = React.useState(false);
  const [playing, setPlaying] = React.useState(false);
  const waveRef = React.useRef(null);
  const C = CASES[active];
  const total = C.turns.length;

  function resetState() {
    if (window.striveAudio) window.striveAudio.stop();
    setTurn(0); setThread([]); shownRef.current = BASE; targetRef.current = BASE; setShown(BASE); setDone(false); setPlaying(false);
  }
  function selectCase(i) { if (i === active) return; setActive(i); resetState(); }
  function reset() { resetState(); }

  function animateTo(target) {
    const from = shownRef.current, t0 = performance.now(), dur = 800;
    (function tw(now){ const p = Math.min(1,(now-t0)/dur); const e = 1-Math.pow(1-p,3);
      const v = Math.round(from + (target-from)*e); shownRef.current = v; setShown(v);
      if (p<1) requestAnimationFrame(tw); })(t0);
    // guaranteed final value even if rAF is throttled (background tab / preview)
    setTimeout(function(){ shownRef.current = target; setShown(target); }, dur + 60);
  }

  function pick(opt) {
    const t = turn;
    setThread(prev => prev.concat([{ turn: t, choiceText: opt.t, note: opt.note }]));
    targetRef.current += opt.d;
    animateTo(targetRef.current);
    if (t < total - 1) {
      setTurn(t + 1);
    } else {
      setDone(true);
      setTimeout(play, 450);
    }
  }
  function play() {
    if (window.striveAudio && waveRef.current) {
      setPlaying(true);
      window.striveAudio.playClip(waveRef.current, { duration: 2.6, onEnd: () => setPlaying(false) });
    }
  }

  return (
    <div className="icase-shell">
      <div className="icase-picker" role="tablist" aria-label="Pick a case">
        {CASES.map(function (c, i) {
          return (
            <button key={c.id} role="tab" aria-selected={i === active}
              className={'cpick' + (i === active ? ' on' : '')} onClick={() => selectCase(i)}>
              <span className="cpick-dot" style={{ background: c.color }}></span>
              <span className="cpick-co">{c.company}</span>
              <span className="cpick-cat">{c.cat}</span>
            </button>
          );
        })}
      </div>

      <div className="icase">
        <div className="icase-top">
          <span className="icase-tag"><span className="dot" style={{ background: C.color }}></span>Live case · {C.company} · {C.cat}</span>
          {!done && <span className="icase-turn">Turn {turn + 1} / {total}</span>}
          {done && <button className="icase-reset" onClick={reset}>Try again</button>}
        </div>

        {/* conversation so far */}
        {thread.length > 0 && (
          <div className="ithread">
            {thread.map(function (m, i) {
              return (
                <div className="ithread-item" key={i}>
                  <div className="ichose"><span className="ichose-k">You</span>{m.choiceText}</div>
                  <div className="icoach"><span className="icoach-k">Strive</span><span dangerouslySetInnerHTML={{ __html: m.note }} /></div>
                </div>
              );
            })}
          </div>
        )}

        {/* current turn */}
        {!done && (
          <div className="icase-body" key={'t' + active + '-' + turn}>
            <div className="icase-q">{C.turns[turn].q}</div>
            {turn === 0 && <div className="icase-prompt">Your move — there's no single right answer, only sharper ones.</div>}
            <div className="icase-opts">
              {C.turns[turn].options.map(function (o) {
                return (
                  <button key={o.id} className="icase-opt" onClick={() => pick(o)}>
                    <span className="ok">{o.id.toUpperCase()}</span>
                    <span>{o.t}</span>
                    <span className="oarrow"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M5 12h14M13 6l6 6-6 6" strokeLinecap="round" strokeLinejoin="round"/></svg></span>
                  </button>
                );
              })}
            </div>
          </div>
        )}

        {/* result */}
        {done && (
          <div className="icase-body" key={'r' + active}>
            <div className="icase-clip">
              <button className={'clip-play big' + (playing ? ' on' : '')} onClick={play} aria-label="Play your proof clip">
                {playing
                  ? <svg viewBox="0 0 24 24"><rect x="6" y="5" width="4" height="14" rx="1"/><rect x="14" y="5" width="4" height="14" rx="1"/></svg>
                  : <svg viewBox="0 0 24 24"><path d="M8 5v14l11-7z"/></svg>}
              </button>
              <div className="icase-clip-body">
                <IWave bars={16} refEl={waveRef} />
                <div className="icase-clip-meta">Proof clip banked · "{C.clip}" · {playing ? 'playing…' : '0:47'}</div>
              </div>
            </div>

            <div className="icase-score">
              <div>
                <div className="icase-score-k">Your readiness · {C.role}</div>
                <div className="icase-score-n">{shown.toLocaleString('en-US')}<span className="up">+{shown - BASE}</span></div>
              </div>
            </div>

            <div className="icase-cta">
              <div className="icase-cta-copy">
                <div className="icase-cta-h">Three turns in — and Strive was just <strong>warming up.</strong></div>
                <p>The real {C.company} case keeps going by voice, with a mentor watching your tape. Finish it on the app and bank a profile recruiters can trust.</p>
                <div className="icase-cta-row">
                  <a href="#download" className="btn btn-lime">
                    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M5 12h14M13 6l6 6-6 6" strokeLinecap="round" strokeLinejoin="round"/></svg>
                    Finish this case on the app
                  </a>
                </div>
              </div>
              <div className="icase-qr">
                <FauxQR />
                <span>Scan to<br/>download</span>
              </div>
            </div>
          </div>
        )}
      </div>
    </div>
  );
}

(function mount() {
  var el = document.getElementById('case-demo');
  if (el && window.ReactDOM) ReactDOM.createRoot(el).render(<InteractiveCase />);
})();
