// src/app.jsx — Top-level shell (R2)
// R2 changes:
//  - Production defaults baked in: cockpit OFF + variant tags OFF + image labels OFF
//  - Operator mode is local-dev only (cockpit + variant tags + image dev labels)
//  - Operator-mode flag plumbed through to all screens
//  - Added clinical-sage palette toggle to TweakSelect

const { useState: useStateA, useEffect: useEffectA, useMemo: useMemoA } = React;

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "archetype": "trust-clinical",
  "hero_type": "serif",
  "dark": false,
  "motion": "on",
  "force_gender": "auto",
  "force_age": "auto",
  "force_goal": "auto",
  "show_cockpit": false,
  "show_variant_tags": false
}/*EDITMODE-END*/;

function createCockpitSessionId() {
  if (typeof crypto !== 'undefined' && crypto.randomUUID) {
    return crypto.randomUUID().slice(0, 8);
  }
  if (typeof crypto !== 'undefined' && crypto.getRandomValues) {
    const bytes = new Uint8Array(4);
    crypto.getRandomValues(bytes);
    return Array.from(bytes, b => b.toString(16).padStart(2, '0')).join('');
  }
  return 'no-crypto';
}

function App() {
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
  const [screen, setScreen] = useStateA('landing');

  // cont.11 Phase 1E (V2 F2): fire-and-forget funnel telemetry to drive the admin
  // Dashboard funnel widget. The 4 events fire at:
  //   site_visit     -> app.jsx mount (here)
  //   quiz_start     -> quiz.jsx first mount (cont.14 A.3.a)
  //   quiz_complete  -> quiz.jsx isLast onComplete (cont.14 A.3.a)
  //   checkout_shown -> checkout.jsx mount (cont.14 A.3.a)
  // Per V2 F2: NEVER blocks the user flow; errors are silently swallowed by
  // sendFunnelEvent. Helper is exposed on window via api.jsx Object.assign.
  useEffectA(() => {
    if (typeof window.sendFunnelEvent === 'function') {
      window.sendFunnelEvent('site_visit', { page: window.location.pathname });
    }
  }, []);

  // cont.11 R1 fold (Opus LOW-3): last4/brand state removed. The card_last4/card_brand
  // props used to feed a Confirmation receipt row that was removed in V3 F12 (cont.11 P4)
  // — dead data flow. The card form is cosmetic per PEP-G-013; no card data should be
  // tracked in app state.
  // V3.5: thread the captured lead through to checkout so we don't re-prompt
  // for email (already POSTed at Q2) and so the order POST gets the right address.
  const [lead, setLead] = useStateA({ email: '', firstName: '' });
  const [quizAnswers, setQuizAnswers] = useStateA({});
  const sessionId = useMemoA(() => createCockpitSessionId(), []);

  const devOperatorEnabled = useMemoA(() => (
    typeof isDevOperatorHost === 'function' && isDevOperatorHost()
  ), []);
  const urlOperator = useMemoA(() => getInitialOperatorMode(), []);
  const operatorMode = devOperatorEnabled && (urlOperator || t.show_cockpit || t.show_variant_tags);

  const showCockpit     = devOperatorEnabled && (urlOperator || t.show_cockpit);
  const showVariantTags = devOperatorEnabled && (urlOperator || t.show_variant_tags);

  const forced = useMemoA(() => ({
    gender: devOperatorEnabled && t.force_gender !== 'auto' ? t.force_gender : null,
    age:    devOperatorEnabled && t.force_age !== 'auto'    ? t.force_age : null,
    goal:   devOperatorEnabled && t.force_goal !== 'auto'   ? t.force_goal : null,
  }), [devOperatorEnabled, t.force_gender, t.force_age, t.force_goal]);

  return (
    <CohortProvider
      forced={forced}
      archetype={t.archetype}
      heroType={t.hero_type}
      theme={t.dark ? 'dark' : 'light'}
      motion={t.motion}
    >
      <ScreenRouter
        screen={screen}
        setScreen={setScreen}
        quizAnswers={quizAnswers} setQuizAnswers={setQuizAnswers}
        lead={lead} setLead={setLead}
        showVariantTags={showVariantTags}
        operatorMode={operatorMode}
      />
      <CockpitOverlay
        visible={showCockpit}
        sessionId={sessionId}
        variant={screen === 'landing' ? 'hero_v?' : screen === 'quiz' ? 'q_active' : `${screen}_v0`}
      />
      {devOperatorEnabled && <ZeraTweaks t={t} setTweak={setTweak} urlOperator={urlOperator} />}
    </CohortProvider>
  );
}

function ScreenRouter({ screen, setScreen, quizAnswers, setQuizAnswers, lead, setLead, showVariantTags, operatorMode }) {
  useEffectA(() => { window.scrollTo({ top: 0, behavior: 'instant' }); }, [screen]);

  switch (screen) {
    case 'landing':
      return <Landing onStartQuiz={() => setScreen('quiz')} showVariantTags={showVariantTags} operatorMode={operatorMode} />;
    case 'quiz':
      return <Quiz
        onComplete={(out) => { setQuizAnswers(out?.answers || {}); if (out?.answers?.lead) setLead(out.answers.lead); setScreen('results'); }}
        onExit={() => setScreen('landing')}
        showVariantTags={showVariantTags}
      />;
    case 'results':
      return <Results answers={quizAnswers} onCheckout={() => setScreen('checkout')} onExit={() => setScreen('landing')} showVariantTags={showVariantTags} operatorMode={operatorMode} />;
    case 'checkout':
      return <Checkout
        lead={lead}
        answers={quizAnswers}
        onConfirmed={() => setScreen('confirmed')}
        onExit={() => setScreen('results')}
      />;
    case 'confirmed':
      return <Confirmation onExit={() => setScreen('landing')} onRestart={() => setScreen('landing')} />;
    default:
      return null;
  }
}

function ZeraTweaks({ t, setTweak, urlOperator }) {
  return (
    <TweaksPanel>
      <TweakSection label="Archetype + type" />
      <TweakSelect
        label="Visual archetype"
        value={t.archetype}
        options={[
          { value: 'trust-clinical',  label: 'Trust-Clinical (default)' },
          { value: 'lifestyle-dtc',   label: 'Lifestyle DTC' },
          { value: 'clinical-sage',   label: 'Clinical-Sage (operator A/B)' },
        ]}
        onChange={(v) => setTweak('archetype', v)}
      />
      <TweakRadio
        label="Hero typography"
        value={t.hero_type}
        options={[
          { value: 'serif', label: 'Serif (premium)' },
          { value: 'sans',  label: 'Inter Tight' },
        ]}
        onChange={(v) => setTweak('hero_type', v)}
      />
      <TweakToggle label="Dark mode" value={t.dark} onChange={(v) => setTweak('dark', v)} />
      <TweakRadio
        label="Motion"
        value={t.motion}
        options={[{ value: 'on', label: 'On' }, { value: 'off', label: 'Off' }]}
        onChange={(v) => setTweak('motion', v)}
      />

      <TweakSection label="Force cohort (override)" />
      <TweakSelect
        label="Gender"
        value={t.force_gender}
        options={[
          { value: 'auto', label: 'Auto (Bayesian)' },
          { value: 'f', label: 'Female' },
          { value: 'm', label: 'Male' },
          { value: 'unknown', label: 'Unknown / neutral' },
        ]}
        onChange={(v) => setTweak('force_gender', v)}
      />
      <TweakSelect
        label="Age bracket"
        value={t.force_age}
        options={[
          { value: 'auto', label: 'Auto (inferred)' },
          { value: '18-29', label: '18 – 29' },
          { value: '30-44', label: '30 – 44' },
          { value: '45-59', label: '45 – 59' },
          { value: '60+',   label: '60 +' },
          { value: 'unknown', label: 'Unknown / neutral' },
        ]}
        onChange={(v) => setTweak('force_age', v)}
      />
      <TweakSelect
        label="Goal"
        value={t.force_goal}
        options={[
          { value: 'auto',            label: 'Auto (from Q1)' },
          { value: 'weight_loss',     label: 'Weight management' },
          { value: 'lean_muscle',     label: 'Lean muscle' },
          { value: 'recovery',        label: 'Recovery' },
          { value: 'energy_vitality', label: 'Energy / vitality' },
          { value: 'longevity',       label: 'Healthy aging' },
          { value: 'sleep_stress',    label: 'Sleep / stress' },
          { value: 'hormone',         label: 'Hormone' },
        ]}
        onChange={(v) => setTweak('force_goal', v)}
      />

      <TweakSection label={`Operator view${urlOperator ? ' · local URL active' : ''}`} />
      <TweakToggle label="Cohort cockpit"     value={t.show_cockpit}      onChange={(v) => setTweak('show_cockpit', v)} />
      <TweakToggle label="Show variant tags"  value={t.show_variant_tags} onChange={(v) => setTweak('show_variant_tags', v)} />

      <TweakSection label="API base · V3.5 wiring" />
      <ApiBaseTweak />
    </TweaksPanel>
  );
}

// API base tweak — flips between mock (default), live same-origin, and custom override.
function ApiBaseTweak() {
  const [base, setBase] = useStateA(() => getApiBase());
  useEffectA(() => {
    const fn = (e) => setBase(e.detail || getApiBase());
    window.addEventListener('zrx:api-base', fn);
    return () => window.removeEventListener('zrx:api-base', fn);
  }, []);
  function pick(v) { setApiBase(v); setBase(v); }
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
      <div style={{ display: 'flex', gap: 6 }}>
        {[['mock','Mock'],['/api','Live /api'],['custom','Custom']].map(([k, l]) => (
          <button key={k} onClick={() => pick(k === 'custom' ? (prompt('Custom API base (e.g. https://fujirx.com/api)') || base) : k)} style={{
            flex: 1, padding: '8px 10px', fontSize: 12, fontFamily: 'inherit', fontWeight: 600,
            background: base === k || (k === 'custom' && base !== 'mock' && base !== '/api') ? 'var(--cohort-accent)' : 'var(--brand-bg-elev)',
            color: base === k || (k === 'custom' && base !== 'mock' && base !== '/api') ? 'white' : 'var(--brand-text)',
            border: '1px solid var(--brand-border)', borderRadius: 8, cursor: 'pointer', minHeight: 36,
          }}>{l}</button>
        ))}
      </div>
      <div className="mono" style={{ fontSize: 10.5, color: 'var(--brand-text-soft)', wordBreak: 'break-all' }}>{base}</div>
    </div>
  );
}

// R4-03 CRIT: React error boundary so a single component throw doesn't blank the entire app.
// Without this, any TypeError in any descendant (Quiz/Results/Checkout) unmounts the tree
// and leaves the user staring at empty white. Wraps <App /> with recovery UI + restart button.
class ErrorBoundary extends React.Component {
  constructor(props) { super(props); this.state = { hasError: false, error: null }; }
  static getDerivedStateFromError(error) { return { hasError: true, error }; }
  componentDidCatch(error, info) { console.error('Fuji ErrorBoundary caught:', error, info); }
  render() {
    if (this.state.hasError) {
      return (
        <div style={{
          minHeight: '100vh', display: 'flex', flexDirection: 'column',
          alignItems: 'center', justifyContent: 'center',
          background: 'var(--brand-bg, #FAFAF7)', color: 'var(--brand-text, #1A1A1A)',
          fontFamily: "'Plus Jakarta Sans', -apple-system, sans-serif",
          padding: 32, textAlign: 'center', gap: 18,
        }}>
          <h1 style={{ fontFamily: "'Source Serif 4', Georgia, serif", fontSize: 36, fontWeight: 500, margin: 0 }}>
            Something went wrong.
          </h1>
          <p style={{ fontSize: 16, color: 'var(--brand-text-muted, #555)', maxWidth: 520 }}>
            {'Fuji'} hit an unexpected error and could not continue. Your data is safe — nothing was submitted. Please restart the quiz.
          </p>
          <button
            onClick={() => { window.location.href = '/'; }}
            style={{
              marginTop: 12, padding: '14px 28px',
              background: 'var(--cohort-accent, #6E58F0)', color: 'white',
              border: 'none', borderRadius: 12, fontSize: 16, fontWeight: 600,
              cursor: 'pointer', minHeight: 48,
              boxShadow: '0 4px 12px rgba(110, 88, 240, 0.25)',
            }}
          >
            Restart →
          </button>
        </div>
      );
    }
    return this.props.children;
  }
}

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