/* =========================================================================
   APP  —  state machine, transitions, and lead capture wiring
   ========================================================================= */

/* ---- The only two things that point outward. Swap these. ---------------- */
const BOOKING_URL   = 'https://calendly.com/the73media/outbound-consultation';
const LEAD_ENDPOINT = '/api/lead'; // same Vercel project serves the quiz and the back end, so this relative path works on any domain. Empty = skip POST, still reveal.
const LEAD_TOKEN    = '73m-pr-healthcheck-9f3a2c'; // sent as X-Lead-Token; server compares to LEAD_SHARED_TOKEN. Not a secret (ships in client), just a bot speed-bump.

const { useState, useEffect } = React;

/* Watchdog: if the rAF clock is throttled (backgrounded / heavily throttled tab),
   CSS entrance animations can freeze on their opacity:0 start frame. This guarantees
   any non-looping entrance animation resolves to its visible end-state within ~1.6s,
   so a viewer never lands on a blank frame. In a normal tab the animations have long
   since finished, so finish() is a harmless no-op. */
function useAnimationWatchdog(key) {
  useEffect(() => {
    const t = setTimeout(() => {
      document.querySelectorAll('.app *').forEach((el) => {
        if (!el.getAnimations) return;
        el.getAnimations().forEach((a) => {
          const dur = a.effect && a.effect.getTiming ? a.effect.getTiming().iterations : 1;
          if (dur === Infinity) return; // leave the spinner alone
          try { a.finish(); } catch (e) { /* already done */ }
        });
      });
    }, 1600);
    return () => clearTimeout(t);
  }, [key]);
}

/* Build the section-2 payload and POST it. Never blocks the reveal. */
async function sendLead({ name, phone, email, hp, dx }) {
  if (!LEAD_ENDPOINT) return;
  const answers = dx.scored.map((s) => ({ id: s.id, question: s.question, answer: s.label }));
  // The three biggest issues, named, with the answer that flagged each one and
  // the short reason it matters. Lets the back end lead the lead notification
  // with the problems instead of raw question ids.
  const topIssues = (dx.weak || []).map((w) => ({
    id: w.id,
    area: w.area,
    answer: w.label,
    pain: (window.PRESCRIPTIONS[w.id] && window.PRESCRIPTIONS[w.id].pain) || '',
  }));
  const payload = {
    name: name || '', phone: phone || '', email, website: hp || '',
    result: { band: dx.band, score: dx.pct, weakestAreas: dx.weakestAreas, topIssues },
    answers,
    meta: {
      source: 'pr-health-check',
      completedAt: new Date().toISOString(),
      userAgent: navigator.userAgent,
      referrer: document.referrer,
    },
  };
  try {
    const headers = { 'Content-Type': 'application/json' };
    if (LEAD_TOKEN) headers['X-Lead-Token'] = LEAD_TOKEN;
    await fetch(LEAD_ENDPOINT, { method: 'POST', headers, body: JSON.stringify(payload) });
  } catch (err) {
    console.warn('Lead POST failed, revealing result anyway.', err);
  }
}

/* Open the Calendly booking step as an on-page popup over the results, prefilled
   with what we already captured. Falls back to a new tab if the widget script did
   not load, so the click is never lost. */
function openCalendly(e, lead) {
  if (e && e.preventDefault) e.preventDefault();
  const params = new URLSearchParams();
  if (lead && lead.name) params.set('name', lead.name);
  if (lead && lead.email) params.set('email', lead.email);
  const url = BOOKING_URL + (params.toString() ? ('?' + params.toString()) : '');
  if (window.Calendly && window.Calendly.initPopupWidget) {
    window.Calendly.initPopupWidget({ url });
    return false;
  }
  window.open(url, '_blank', 'noopener');
  return false;
}
window.openCalendly = openCalendly;

function App() {
  const [phase, setPhase] = useState('intro');   // intro | quiz | capture | analyzing | results
  const [index, setIndex] = useState(0);
  const [answers, setAnswers] = useState({});
  const [lead, setLead] = useState(null);        // { name, phone, email } once captured
  const total = window.QUESTIONS.length;

  useAnimationWatchdog(phase + ':' + index);

  // live gauge value: pipeline health accumulating as points are banked, 0..1.
  // Using cumulative score / MAX so the node visibly climbs with every answer
  // (a running average would sit still when answers are similarly weighted) and
  // lands exactly on the final reveal score.
  function liveValue(a = answers) {
    const sum = window.QUESTIONS.reduce(
      (acc, q) => acc + (a[q.id] != null ? q.options[a[q.id]].score : 0), 0);
    return sum / window.MAX_SCORE;
  }

  const dx = window.diagnose(answers);

  function begin() { setPhase('quiz'); setIndex(0); }

  function answer(qid, optIdx) {
    const next = { ...answers, [qid]: optIdx };
    setAnswers(next);
    if (index < total - 1) {
      setIndex(index + 1);
    } else {
      setPhase('capture');
    }
  }

  function back() { if (index > 0) setIndex(index - 1); }

  function onSubmit({ name, phone, email: em, website }) {
    setLead({ name, phone, email: em });
    sendLead({ name, phone, email: em, hp: website, dx: window.diagnose(answers) });
    setPhase('analyzing');
  }

  function onSkip() { setLead(null); setPhase('analyzing'); }

  function retake() {
    setAnswers({}); setIndex(0); setLead(null); setPhase('intro');
  }

  return (
    <div className="app">
      <div className="grain" aria-hidden="true" />
      {phase === 'intro' && <window.Intro onBegin={begin} />}
      {phase === 'quiz' && (
        <window.Quiz index={index} total={total} answers={answers}
          onAnswer={answer} onBack={back} liveValue={liveValue()} />
      )}
      {phase === 'capture' && (
        <window.Capture band={dx.band} liveValue={liveValue()} onSubmit={onSubmit} onSkip={onSkip} />
      )}
      {phase === 'analyzing' && <window.Analyzing onDone={() => setPhase('results')} />}
      {phase === 'results' && (
        <window.Results dx={dx} lead={lead} onRetake={retake} bookingUrl={BOOKING_URL} />
      )}
    </div>
  );
}

ReactDOM.createRoot(document.getElementById('root')).render(<App />);
