// tour.jsx — guided "first 5 minutes" coachmark tour + first-run helpers.
// A spotlight walks the user across the real app (it navigates views, waits for
// the target to mount, scrolls it into view, then rings it) so the first run
// teaches the glass-box features instead of dumping the user on a dense report.
(function () {
  const { useState, useEffect, useCallback } = React;

  const SEEN_KEY = 'jiffyscore.tour.v1';
  const tourSeen = () => { try { return localStorage.getItem(SEEN_KEY) === '1'; } catch (e) { return true; } };
  const markSeen = () => { try { localStorage.setItem(SEEN_KEY, '1'); } catch (e) {} };

  // Steps reference the live agency journey. `view` routes first; `selector`
  // is polled until it exists so we never ring a stale frame.
  const STEPS = [
    { view: 'home', selector: '.js-stats', place: 'bottom',
      title: 'Your portfolio, scored', body: 'Every client is audited on one transparent methodology — no black-box scores. This is the health of the whole book at a glance.' },
    { view: 'results', selector: '.lab-dial-trigger', place: 'right', pad: 16,
      title: 'Open the glass box', body: 'Click any score to see exactly what drove it — and toggle fixes to watch the number move before you ship a thing.' },
    { view: 'results', selector: '.js-gauges', place: 'top',
      title: 'Every number shows its work', body: 'Six dimensions, each decomposed into weighted, evidenced sub-factors. Click one to drill in.' },
    { view: 'results', selector: '.js-gap', place: 'top',
      title: 'Fixes, ranked by impact', body: 'Priority gaps are ordered by the lift they unlock. Click any to simulate it against the live score.' },
    { view: 'visibility', selector: '.js-steal-row', place: 'top',
      title: 'Steal the citation', body: 'When an engine cites a competitor instead of you, see the exact passage it lifted — and precisely what to copy.' },
  ];

  function Tour({ run, go, onClose }) {
    const [i, setI] = useState(0);
    const [rect, setRect] = useState(null);
    const step = STEPS[i];

    const finish = useCallback(() => { markSeen(); setI(0); setRect(null); onClose(); }, [onClose]);

    // navigate → wait for target → scroll into view → measure
    useEffect(() => {
      if (!run) return;
      let cancelled = false;
      let tries = 0;
      setRect(null);
      if (step.view) go(step.view);
      const measure = () => {
        if (cancelled) return;
        const el = document.querySelector(step.selector);
        if (!el) { if (tries++ < 50) setTimeout(measure, 60); return; }
        const r = el.getBoundingClientRect();
        const vh = window.innerHeight;
        // bring it comfortably into view without scrollIntoView
        if (r.top < 90 || r.bottom > vh - 90) {
          window.scrollBy({ top: r.top - vh * 0.34, behavior: 'auto' });
          setTimeout(measure, 60); return;
        }
        setRect({ top: r.top, left: r.left, width: r.width, height: r.height });
      };
      const t = setTimeout(measure, step.view ? 260 : 60);
      return () => { cancelled = true; clearTimeout(t); };
    }, [i, run]); // eslint-disable-line

    useEffect(() => {
      if (!run) return;
      const onKey = e => { if (e.key === 'Escape') finish(); else if (e.key === 'ArrowRight') next(); else if (e.key === 'ArrowLeft') setI(p => Math.max(0, p - 1)); };
      window.addEventListener('keydown', onKey);
      return () => window.removeEventListener('keydown', onKey);
    }); // re-bind each render so next/finish are fresh

    if (!run) return null;
    const next = () => { if (i >= STEPS.length - 1) finish(); else setI(i + 1); };
    const pad = step.pad != null ? step.pad : 10;

    // tooltip placement relative to the spotlight
    let tip = null;
    if (rect) {
      const vw = window.innerWidth, vh = window.innerHeight;
      const W = Math.min(360, vw - 32);
      const cx = rect.left + rect.width / 2;
      let top, left = Math.min(Math.max(16, cx - W / 2), vw - W - 16);
      const place = step.place || 'bottom';
      if (place === 'bottom') top = rect.top + rect.height + pad + 14;
      else if (place === 'top') top = rect.top - pad - 14 - 168;
      else if (place === 'right') { top = Math.max(16, rect.top); left = Math.min(rect.left + rect.width + pad + 14, vw - W - 16); }
      if (top < 16) top = rect.top + rect.height + pad + 14;
      if (top > vh - 180) top = Math.max(16, rect.top - 180);
      tip = { top, left, width: W };
    }

    return (
      <div className="tour-root">
        <div className="tour-catch" onClick={() => {}} />
        {rect && (
          <div className="tour-spot" style={{ top: rect.top - pad, left: rect.left - pad, width: rect.width + pad * 2, height: rect.height + pad * 2 }} />
        )}
        {tip && (
        <div className="tour-tip" style={tip}>
          <div className="tour-tiphead">
            <span className="js-tag">First 5 minutes · {i + 1}/{STEPS.length}</span>
            <button className="tour-skip" onClick={finish}>Skip</button>
          </div>
          <h4 className="tour-title">{step.title}</h4>
          <p className="tour-body">{step.body}</p>
          <div className="tour-dots">
            {STEPS.map((_, n) => <span key={n} className={'tour-dot' + (n === i ? ' is-on' : '')} />)}
          </div>
          <div className="tour-actions">
            {i > 0 ? <button className="tour-back" onClick={() => setI(i - 1)}>Back</button> : <span />}
            <Btn sm kind="gold" icon={i >= STEPS.length - 1 ? 'check' : 'arrow'} onClick={next}>
              {i >= STEPS.length - 1 ? 'Start exploring' : 'Next'}
            </Btn>
          </div>
        </div>
        )}
      </div>
    );
  }

  window.Tour = Tour;
  window.tourSeen = tourSeen;
})();
