// WeWire applicant — Assessment stages (intro → timed session → result).

const QUIT_MSG = 'Leave this session? Your answers won\'t be saved — you\'ll need to retake with a new set of questions.';

// ── Countdown timer (single session, no pause) ───────────────
function useSessionTimer(totalSeconds, onExpire, running) {
  const [left, setLeft] = React.useState(totalSeconds);
  const fired = React.useRef(false);
  const onExpireRef = React.useRef(onExpire);
  onExpireRef.current = onExpire;

  React.useEffect(() => {
    setLeft(totalSeconds);
    fired.current = false;
  }, [totalSeconds]);

  React.useEffect(() => {
    if (!running) return;
    const id = setInterval(() => {
      setLeft((s) => {
        if (s <= 1) {
          if (!fired.current) {
            fired.current = true;
            onExpireRef.current && onExpireRef.current();
          }
          return 0;
        }
        return s - 1;
      });
    }, 1000);
    return () => clearInterval(id);
  }, [running, totalSeconds]);

  const mm = String(Math.floor(left / 60)).padStart(2, '0');
  const ss = String(left % 60).padStart(2, '0');
  return { label: `${mm}:${ss}`, low: left <= 60, expired: left <= 0 };
}

function QuitConfirm({ onStay, onLeave }) {
  return (
    <div style={{ position: 'absolute', inset: 0, zIndex: 100, background: 'rgba(14,14,14,0.55)',
      display: 'flex', alignItems: 'flex-end', padding: 20, boxSizing: 'border-box' }}>
      <Card pad={22} style={{ width: '100%', border: 'none', boxShadow: '0 24px 60px rgba(0,0,0,0.25)' }}>
        <h2 style={{ fontFamily: DISP, fontWeight: 600, fontSize: 20, letterSpacing: '-0.02em', marginBottom: 10 }}>Leave session?</h2>
        <p style={{ fontSize: 14, color: WW.muted, lineHeight: 1.55, marginBottom: 18 }}>
          Timed sessions can't be paused. If you leave now, you'll retake this stage with a fresh set of questions.
        </p>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
          <Btn variant="primary" full onClick={onStay}>Keep going</Btn>
          <Btn variant="ghost" full onClick={onLeave}>Leave & retake later</Btn>
        </div>
      </Card>
    </div>
  );
}

// ── Intro ────────────────────────────────────────────────────
function AssessIntro({ stage, onStart, onBack, timed }) {
  const perSession = timed ? WWAssess.questionsPerSession() : null;
  const rows = [];
  if (timed) {
    rows.push(['clock', `${WWAssess.sessionMins(stage)} minutes`, 'One sitting — the timer starts when you begin.']);
    rows.push(['chart', `${perSession} questions`, 'Drawn from a broader question bank.']);
    rows.push(['lock', 'No pausing', 'Leaving mid-session voids progress; you\'ll retake with new questions.']);
  } else if (stage.mins) {
    rows.push(['clock', `${stage.mins} minutes`, 'Work at your own pace within the window.']);
  }
  if (stage.key === 'written') rows.push(['edit', '3 essays', '~150–300 words each.']);
  if (stage.key === 'case') rows.push(['brief', '48-hour window', 'A realistic WeWire problem to solve at home.']);
  if (stage.key === 'interview') rows.push(['pin', 'In person · Accra', 'Meet the team at WeWire HQ.']);

  return (
    <Screen footer={
      <Btn variant="primary" full onClick={onStart} icon="arrow">
        {stage.key === 'interview' ? 'Choose a time' : stage.key === 'case' ? 'View the brief' : timed ? 'Start timed session' : 'Start'}
      </Btn>
    }>
      <TopBar title={stage.name} onBack={onBack} />
      <div style={{ marginTop: 20, width: 64, height: 64, borderRadius: 18, background: WW.orangeSoft,
        display: 'grid', placeItems: 'center', color: WW.orangeDeep }}>
        <Icon name={STAGE_ICON[stage.key]} size={30} />
      </div>
      <Eyebrow style={{ marginTop: 22 }}>Step {stage.n}</Eyebrow>
      <h1 style={{ fontFamily: DISP, fontWeight: 600, fontSize: 30, letterSpacing: '-0.02em', margin: '8px 0 10px' }}>{stage.name}</h1>
      <p style={{ fontSize: 16, color: WW.muted, lineHeight: 1.55 }}>{stage.blurb}</p>

      <div style={{ display: 'flex', flexDirection: 'column', gap: 10, marginTop: 24 }}>
        {rows.map(([ic, t, d]) => (
          <Card key={t} pad={16} style={{ display: 'flex', alignItems: 'center', gap: 14 }}>
            <div style={{ width: 42, height: 42, borderRadius: 12, background: WW.sand, color: WW.ink,
              display: 'grid', placeItems: 'center', flex: 'none' }}><Icon name={ic} size={20} /></div>
            <div>
              <div style={{ fontWeight: 600, fontSize: 15 }}>{t}</div>
              <div style={{ fontSize: 13, color: WW.muted, lineHeight: 1.4 }}>{d}</div>
            </div>
          </Card>
        ))}
      </div>
      {timed && (
        <Card pad={16} style={{ background: WW.orangeSoft, border: 'none', marginTop: 14 }}>
          <div style={{ fontSize: 13, color: WW.orangeDeep, lineHeight: 1.55 }}>
            Complete this independently. Copying or sharing answers is not permitted.
          </div>
        </Card>
      )}
    </Screen>
  );
}

// ── MCQ / SJT player (timed, no resume) ────────────────────
function McqPlayer({ stage, questions, sessionMins, onSubmit, onQuitRequest }) {
  const [i, setI] = React.useState(0);
  const [ans, setAns] = React.useState({});
  const [confirmQuit, setConfirmQuit] = React.useState(false);
  const safeQuestions = questions?.length ? questions : [];

  const finish = React.useCallback(() => {
    if (!safeQuestions.length) return;
    let correct = 0;
    safeQuestions.forEach((qq, idx) => { if (ans[idx] === qq.answer) correct++; });
    onSubmit(Math.round((correct / safeQuestions.length) * 100), correct, safeQuestions.length);
  }, [ans, safeQuestions, onSubmit]);

  const timer = useSessionTimer(sessionMins * 60, finish, safeQuestions.length > 0);

  if (!safeQuestions.length) {
    return (
      <Screen>
        <TopBar title={stage.name} onBack={onQuitRequest} />
        <div style={{ marginTop: 40, textAlign: 'center', color: WW.muted, fontSize: 15 }}>
          Saving your results…
        </div>
      </Screen>
    );
  }

  const q = safeQuestions[i];
  const answered = Object.keys(ans).length;

  const tryQuit = () => setConfirmQuit(true);
  const leave = () => { setConfirmQuit(false); onQuitRequest(); };

  return (
    <div style={{ position: 'relative', height: '100%', display: 'flex', flexDirection: 'column' }}>
      {confirmQuit && <QuitConfirm onStay={() => setConfirmQuit(false)} onLeave={leave} />}
      <Screen footer={
        <div style={{ display: 'flex', gap: 10 }}>
          <Btn variant="ghost" onClick={() => setI(Math.max(0, i - 1))} disabled={i === 0} style={{ width: 56, padding: 0 }}><Icon name="back" size={20} /></Btn>
          {i < safeQuestions.length - 1
            ? <Btn variant="primary" full onClick={() => setI(i + 1)} icon="next">Next</Btn>
            : <Btn variant="primary" full onClick={finish} icon="check">Submit ({answered}/{safeQuestions.length})</Btn>}
        </div>
      }>
        <TopBar onBack={tryQuit} right={
          <Chip tone={timer.low ? 'red' : 'dark'} style={{ fontVariantNumeric: 'tabular-nums' }}>
            <Icon name="clock" size={13} /> {timer.label}
          </Chip>} />

        <div style={{ display: 'flex', gap: 7, margin: '6px 0 18px', flexWrap: 'wrap' }}>
          {safeQuestions.map((_, idx) => {
            const active = idx === i, done = ans[idx] !== undefined;
            return (
              <button key={idx} onClick={() => setI(idx)} style={{
                width: 34, height: 34, borderRadius: 10, border: 'none', cursor: 'pointer', fontFamily: DISP, fontWeight: 600, fontSize: 14,
                background: active ? WW.orange : done ? WW.ink : WW.sand, color: (active || done) ? '#fff' : WW.muted }}>
                {idx + 1}
              </button>
            );
          })}
          <div style={{ flex: 1 }} />
          <span style={{ fontSize: 12, color: WW.subtle, alignSelf: 'center', fontWeight: 600 }}>{i + 1} of {safeQuestions.length}</span>
        </div>

        <Eyebrow>{stage.name}</Eyebrow>
        <div style={{ fontFamily: DISP, fontWeight: 600, fontSize: 21, lineHeight: 1.3, letterSpacing: '-0.01em',
          margin: '10px 0 20px', textWrap: 'pretty' }}>{q.q}</div>

        <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
          {q.options.map((opt, oi) => {
            const sel = ans[i] === oi;
            return (
              <div key={oi} onClick={() => setAns({ ...ans, [i]: oi })} style={{
                display: 'flex', alignItems: 'center', gap: 13, padding: '15px 16px', borderRadius: 15, cursor: 'pointer',
                background: sel ? WW.orangeSoft : WW.white, border: `1px solid ${sel ? 'transparent' : WW.line}`,
                boxShadow: sel ? `inset 0 0 0 1.5px ${WW.orange}` : 'none', transition: 'background 160ms' }}>
                <div style={{ width: 26, height: 26, borderRadius: 8, flex: 'none', display: 'grid', placeItems: 'center',
                  background: sel ? WW.orange : WW.sand, color: sel ? '#fff' : WW.muted, fontFamily: DISP, fontWeight: 600, fontSize: 13 }}>
                  {String.fromCharCode(65 + oi)}
                </div>
                <span style={{ fontSize: 15, fontWeight: 500, lineHeight: 1.4, color: sel ? WW.orangeDeep : WW.ink }}>{opt}</span>
              </div>
            );
          })}
        </div>
      </Screen>
    </div>
  );
}

// ── Written response (multi-essay) ───────────────────────────
function WrittenScreen({ data, onSubmit, onBack }) {
  const cfg = window.WWFunnel?.normalizeWrittenConfig
    ? window.WWFunnel.normalizeWrittenConfig(data)
    : { prompts: [{ id: 'main', title: 'Written response', prompt: data.prompt }], minWords: data.minWords || 30, maxWords: data.maxWords || 500 };
  const perEssayMin = Math.max(30, Math.ceil((cfg.minWords || 150) / Math.max(cfg.prompts.length, 1)));
  const [answers, setAnswers] = React.useState(() => Object.fromEntries(cfg.prompts.map((p) => [p.id, ''])));
  const [activeIdx, setActiveIdx] = React.useState(0);

  const essays = cfg.prompts.map((p) => {
    const text = answers[p.id] || '';
    const wordCount = text.trim() ? text.trim().split(/\s+/).length : 0;
    return { ...p, text: text.trim(), wordCount };
  });
  const allOk = essays.every((e) => e.wordCount >= perEssayMin && e.wordCount <= cfg.maxWords);
  const active = essays[activeIdx] || essays[0];

  return (
    <Screen footer={
      <Btn variant="primary" full onClick={() => onSubmit(essays)} disabled={!allOk} icon="check">
        Submit all {cfg.prompts.length} responses
      </Btn>
    }>
      <TopBar title="Written Response" onBack={onBack} />
      <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', marginTop: 14 }}>
        {essays.map((e, i) => {
          const over = e.wordCount > cfg.maxWords;
          const ok = e.wordCount >= perEssayMin && !over;
          return (
            <button key={e.id} type="button" onClick={() => setActiveIdx(i)}
              style={{ border: `1px solid ${i === activeIdx ? WW.orange : WW.line}`, borderRadius: 999, padding: '8px 14px',
                background: i === activeIdx ? WW.orangeSoft : WW.white, cursor: 'pointer', fontFamily: FONT, fontSize: 13, fontWeight: 600,
                color: over ? WW.red : ok ? WW.green : WW.muted }}>
              {i + 1}. {e.title || e.id}{ok ? ' ✓' : over ? ' !' : ''}
            </button>
          );
        })}
      </div>
      <Card pad={18} style={{ background: WW.orangeSoft, border: 'none', marginTop: 14 }}>
        <Eyebrow color={WW.orangeDeep}>Essay {activeIdx + 1} of {essays.length}</Eyebrow>
        <div style={{ fontSize: 16, lineHeight: 1.5, marginTop: 8, color: WW.ink, fontWeight: 500 }}>{active.prompt}</div>
      </Card>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', margin: '20px 2px 8px' }}>
        <span style={{ fontSize: 13, fontWeight: 600, color: WW.muted }}>Your answer</span>
        <span style={{ fontSize: 12, fontWeight: 600, color: active.wordCount > cfg.maxWords ? WW.red : active.wordCount >= perEssayMin ? WW.green : WW.subtle }}>
          {active.wordCount} / {cfg.maxWords} words {active.wordCount > cfg.maxWords ? '· over limit' : active.wordCount >= perEssayMin ? '✓' : `· min ${perEssayMin}`}
        </span>
      </div>
      <textarea value={answers[active.id] || ''} onChange={(e) => setAnswers((prev) => ({ ...prev, [active.id]: e.target.value }))} rows={11}
        placeholder="Start writing — there's no perfect answer, only your thinking…"
        style={{ ...inputStyle, height: 'auto', padding: 16, resize: 'none', lineHeight: 1.6, fontSize: 15 }}
        onFocus={(e) => e.target.style.borderColor = WW.orange} onBlur={(e) => e.target.style.borderColor = WW.line} />
      <div style={{ fontSize: 12.5, color: WW.muted, marginTop: 10, lineHeight: 1.5 }}>
        Complete each essay before submitting. Target {cfg.minWords}–{cfg.maxWords} words per essay.
      </div>
    </Screen>
  );
}

// ── Take-home case ───────────────────────────────────────────
function CaseScreen({ data, onSubmit, onBack }) {
  const [file, setFile] = React.useState('');
  const [fileObj, setFileObj] = React.useState(null);
  const ref = React.useRef();
  const [deadline, setDeadline] = React.useState(null);
  const [hoursLeft, setHoursLeft] = React.useState(null);

  React.useEffect(() => {
    const email = window.WWAuth?.getEmail?.() || 'anon';
    const key = `ww_case_dl_${email}`;
    let stored = localStorage.getItem(key);
    if (!stored) {
      stored = (Date.now() + 48 * 60 * 60 * 1000).toString();
      localStorage.setItem(key, stored);
    }
    const dl = new Date(parseInt(stored));
    setDeadline(dl);
    const tick = () => setHoursLeft(Math.max(0, Math.ceil((dl - Date.now()) / (1000 * 60 * 60))));
    tick();
    const id = setInterval(tick, 60000);
    return () => clearInterval(id);
  }, []);

  const formatDeadline = (d) => {
    if (!d) return '—';
    return d.toLocaleDateString('en-GB', { weekday: 'short', day: 'numeric', month: 'short' }) +
      ' · ' + d.toLocaleTimeString('en-GB', { hour: '2-digit', minute: '2-digit' });
  };

  return (
    <Screen footer={<Btn variant="primary" full onClick={() => onSubmit(fileObj)} disabled={!file} icon="check">Submit case</Btn>}>
      <TopBar title="Take-home Case" onBack={onBack} />
      <div style={{ display: 'flex', gap: 8, marginTop: 14, flexWrap: 'wrap' }}>
        <Chip tone="warm"><Icon name="clock" size={13} /> Due by {formatDeadline(deadline)}</Chip>
        {hoursLeft !== null && (
          <Chip tone={hoursLeft <= 6 ? 'red' : 'neutral'}>
            {hoursLeft > 0 ? `${hoursLeft}h remaining` : 'Deadline passed'}
          </Chip>
        )}
      </div>
      <h1 style={{ fontFamily: DISP, fontWeight: 600, fontSize: 26, letterSpacing: '-0.02em', margin: '14px 0 12px' }}>{data.title}</h1>
      <Card pad={18}>
        <Eyebrow>The brief</Eyebrow>
        <div style={{ fontSize: 15, lineHeight: 1.6, marginTop: 10, color: WW.ink }}>{data.brief}</div>
      </Card>
      <input ref={ref} type="file" accept=".pdf" style={{ display: 'none' }}
        onChange={(e) => {
          const f = e.target.files[0];
          setFileObj(f || null);
          setFile(f?.name || 'case-memo.pdf');
        }} />
      <div onClick={() => ref.current?.click()} style={{ marginTop: 16, border: `1.5px dashed ${file ? WW.green : WW.lineStrong}`,
        borderRadius: 16, padding: '22px 18px', display: 'flex', alignItems: 'center', gap: 14, cursor: 'pointer',
        background: file ? WW.greenSoft : WW.white }}>
        <div style={{ width: 44, height: 44, borderRadius: 12, background: file ? WW.green : WW.sand,
          color: file ? '#fff' : WW.muted, display: 'grid', placeItems: 'center', flex: 'none' }}>
          <Icon name={file ? 'check' : 'upload'} size={20} /></div>
        <div style={{ minWidth: 0 }}>
          <div style={{ fontWeight: 600, fontSize: 15, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{file || 'Upload your memo (PDF)'}</div>
          <div style={{ fontSize: 12, color: WW.muted }}>{file ? 'Tap to replace' : '2 pages max'}</div>
        </div>
      </div>
    </Screen>
  );
}

// ── In-person interview scheduling ───────────────────────────
function InterviewScreen({ data, onSubmit, onBack }) {
  const [slots, setSlots] = React.useState([]);
  const [loading, setLoading] = React.useState(true);
  const [pick, setPick] = React.useState(null);

  React.useEffect(() => {
    let cancelled = false;
    (async () => {
      try {
        const rows = window.WWApplicant?.loadInterviewSlots
          ? await window.WWApplicant.loadInterviewSlots()
          : [];
        if (!cancelled) setSlots(rows);
      } catch (err) {
        console.warn('Could not load interview slots:', err.message);
        if (!cancelled) setSlots([]);
      } finally {
        if (!cancelled) setLoading(false);
      }
    })();
    return () => { cancelled = true; };
  }, []);

  return (
    <Screen footer={<Btn variant="primary" full onClick={() => onSubmit(slots[pick])} disabled={pick === null} icon="check">Confirm my interview</Btn>}>
      <TopBar title="Final Interview" onBack={onBack} />
      <Card pad={18} style={{ marginTop: 14, display: 'flex', gap: 14, alignItems: 'flex-start' }}>
        <div style={{ width: 44, height: 44, borderRadius: 12, background: WW.orangeSoft, color: WW.orangeDeep,
          display: 'grid', placeItems: 'center', flex: 'none' }}><Icon name="pin" size={20} /></div>
        <div>
          <div style={{ fontWeight: 600, fontSize: 15 }}>{data.where}</div>
          <div style={{ fontSize: 13, color: WW.muted, lineHeight: 1.5, marginTop: 4 }}>{data.format}</div>
          <div style={{ fontSize: 13, color: WW.muted, marginTop: 6 }}>You'll meet: {data.panel.join(' · ')}</div>
        </div>
      </Card>
      <Eyebrow style={{ margin: '22px 2px 12px' }}>Choose a time</Eyebrow>
      {loading ? (
        <Card pad={20}><div style={{ fontSize: 14, color: WW.muted }}>Loading available slots…</div></Card>
      ) : slots.length === 0 ? (
        <Card pad={20}><div style={{ fontSize: 14, color: WW.muted, lineHeight: 1.5 }}>No interview slots are open yet. The recruiting team will publish times soon — check back shortly.</div></Card>
      ) : (
      <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
        {slots.map((s, idx) => {
          const sel = pick === idx;
          return (
            <div key={s.id || idx} onClick={s.open ? () => setPick(idx) : undefined} style={{
              display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '15px 18px', borderRadius: 15,
              cursor: s.open ? 'pointer' : 'not-allowed', opacity: s.open ? 1 : 0.45,
              background: sel ? WW.orangeSoft : WW.white, border: `1px solid ${sel ? 'transparent' : WW.line}`,
              boxShadow: sel ? `inset 0 0 0 1.5px ${WW.orange}` : 'none' }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
                <Icon name="calendar" size={18} color={sel ? WW.orange : WW.muted} />
                <span style={{ fontWeight: 600, fontSize: 15 }}>{s.day || s.date}</span>
              </div>
              <span style={{ fontWeight: 600, fontSize: 15, color: s.open ? (sel ? WW.orangeDeep : WW.ink) : WW.subtle }}>
                {s.open ? s.time : 'Full'}</span>
            </div>
          );
        })}
      </div>
      )}
    </Screen>
  );
}

// ── Result / confirmation ────────────────────────────────────
function MilestoneScoreList({ rows, threshold }) {
  const label = (key) => (window.WWFunnel?.stageLabel ? window.WWFunnel.stageLabel(key) : key);
  if (!rows?.length) return null;
  return (
    <div style={{ marginTop: 22, textAlign: 'left', maxWidth: 320, marginLeft: 'auto', marginRight: 'auto' }}>
      {rows.map((row) => (
        <div key={row.key} style={{ display: 'flex', justifyContent: 'space-between', gap: 12, padding: '10px 14px',
          borderRadius: 12, background: 'rgba(251,247,240,0.08)', marginBottom: 8, fontSize: 14 }}>
          <span style={{ textAlign: 'left' }}>{label(row.key)}</span>
          <span style={{ fontWeight: 700, flex: 'none', color: row.passed ? WW.greenSoft : 'rgba(251,247,240,0.9)' }}>
            {row.score != null ? `${row.score}%` : '—'} {row.passed ? '✓' : `· need ${threshold}%`}
          </span>
        </div>
      ))}
    </div>
  );
}

function ResultScreen({ stage, score, onContinue, isLast, retakeNote, variant, milestoneDetails }) {
  const threshold = window.WWData?.ASSESS_CONFIG?.passThreshold || 70;
  const isMilestonePass = variant === 'milestone-pass';
  const isMilestoneFail = variant === 'milestone-fail';
  const isCaseReview = variant === 'case-review';
  const isMilestoneComplete = variant === 'milestone-complete';
  const isMilestone = isMilestonePass || isMilestoneFail;
  const showBigScore = score != null && !isMilestone && !isCaseReview && !isMilestoneComplete;

  let eyebrow = `${stage.name} · Complete`;
  let title = '';
  let body = '';
  let iconName = 'check';
  let accent = WW.orange;
  let glow = 'rgba(255,77,7,0.5)';

  if (isMilestonePass) {
    eyebrow = 'Milestone 1 · Passed automatically';
    title = 'You\'re through to Milestone 2';
    body = `Your scores met the ${threshold}% minimum on all four timed assessments. Written Response and Take-home Case are now unlocked — the next gate is a manual review by our team after you submit both.`;
    iconName = 'check';
    accent = WW.green;
    glow = 'rgba(54,90,51,0.55)';
  } else if (isMilestoneFail) {
    eyebrow = 'Milestone 1 · Automatic rejection';
    title = 'Thank you for applying';
    body = `Milestone 1 is scored automatically. You needed at least ${threshold}% on each timed assessment. Your application will not advance to the Written Response or Take-home Case stages.`;
    iconName = 'x';
    accent = WW.red;
    glow = 'rgba(192,57,43,0.45)';
  } else if (isCaseReview) {
    eyebrow = 'Milestone 2 · Awaiting team review';
    title = 'Submissions received — manual review';
    body = 'You\'ve completed Milestone 2. Unlike the timed assessments, there is no automatic pass or fail here — our recruiting team will read your Written Response and Take-home Case together and contact you if you\'re shortlisted for a final interview.';
    iconName = 'check';
  } else if (isMilestoneComplete) {
    eyebrow = 'Milestone 3 · Complete';
    title = 'You\'re all set';
    body = 'Your interview is booked. We\'ve sent the details to your email — we can\'t wait to meet you in Accra.';
    iconName = 'star';
    accent = WW.green;
    glow = 'rgba(54,90,51,0.55)';
  } else if (showBigScore) {
    body = 'Nicely done — that\'s logged.';
  } else if (stage.key === 'interview') {
    title = 'You\'re booked in.';
    body = 'We\'ve sent the details to your email. We can\'t wait to meet you in Accra.';
  } else if (stage.key === 'written') {
    title = 'Response received';
    body = 'Your written response is saved. Continue to the Take-home Case when you\'re ready.';
  } else {
    title = 'Received with thanks.';
    body = 'Our team will read every word. You\'ll hear from us on the next step soon.';
  }

  const ctaLabel = isMilestoneFail || isCaseReview || isMilestoneComplete || isLast
    ? 'Back to my application'
    : isMilestonePass
      ? 'Continue to Milestone 2'
      : 'Continue';

  return (
    <div style={{ minHeight: '100%', height: '100%', background: WW.ink, color: WW.cream, display: 'flex',
      flexDirection: 'column', padding: '64px 24px 36px', boxSizing: 'border-box', position: 'relative', overflow: 'hidden' }}>
      <div style={{ position: 'absolute', top: '14%', left: '50%', transform: 'translateX(-50%)', width: 300, height: 300,
        borderRadius: '50%', background: `radial-gradient(circle, ${glow}, transparent 65%)` }} />
      <div style={{ flex: 1 }} />
      <div style={{ position: 'relative', textAlign: 'center' }}>
        <div style={{ width: 96, height: 96, borderRadius: '50%', background: accent,
          display: 'grid', placeItems: 'center', margin: '0 auto 26px', boxShadow: `0 0 60px ${glow}` }}>
          <Icon name={iconName} size={48} color="#fff" />
        </div>
        <Eyebrow color="rgba(251,247,240,0.6)">{eyebrow}</Eyebrow>
        {showBigScore ? (
          <>
            <div style={{ fontFamily: DISP, fontWeight: 600, fontSize: 72, letterSpacing: '-0.03em', lineHeight: 1, margin: '14px 0 4px' }}>{score}<span style={{ fontSize: 32 }}>%</span></div>
            <div style={{ fontSize: 15, color: 'rgba(251,247,240,0.72)' }}>{body}</div>
          </>
        ) : (
          <>
            <h1 style={{ fontFamily: DISP, fontWeight: 600, fontSize: 32, letterSpacing: '-0.02em', margin: '14px 0 10px', lineHeight: 1.15 }}>{title}</h1>
            <p style={{ fontSize: 15, color: 'rgba(251,247,240,0.72)', lineHeight: 1.55, maxWidth: 320, margin: '0 auto' }}>{body}</p>
          </>
        )}
        {isMilestone && <MilestoneScoreList rows={milestoneDetails} threshold={threshold} />}
        {retakeNote && (
          <p style={{ fontSize: 13, color: 'rgba(251,247,240,0.55)', marginTop: 14, lineHeight: 1.5 }}>{retakeNote}</p>
        )}
      </div>
      <div style={{ flex: 1 }} />
      <Btn variant="primary" full onClick={onContinue} icon="arrow" style={{ position: 'relative' }}>
        {ctaLabel}
      </Btn>
    </div>
  );
}

// ── Stage flow wrapper ───────────────────────────────────────
function StageFlow({ stage, onComplete, onBack, applicantEmail, onBindGuard, applicationsOpen, onScoresChange, onMilestone1Evaluated, onMilestone2Submitted }) {
  const { QUESTIONS } = window.WWData;
  const timed = WWAssess.isTimedStage(stage.key);
  const [phase, setPhase] = React.useState('intro');
  const [score, setScore] = React.useState(null);
  const [resultVariant, setResultVariant] = React.useState(null);
  const [milestoneDetails, setMilestoneDetails] = React.useState(null);
  const [attemptId, setAttemptId] = React.useState(0);
  const [sessionQuestions, setSessionQuestions] = React.useState(null);
  const [sessionKey, setSessionKey] = React.useState(0);
  const [saving, setSaving] = React.useState(false);
  const [writtenData, setWrittenData] = React.useState(() => QUESTIONS.written);
  const [caseData, setCaseData] = React.useState(() => QUESTIONS.case);

  React.useEffect(() => {
    let cancelled = false;
    (async () => {
      if (!window.WWApplicant?.loadStagePrompts) return;
      try {
        const prompts = await window.WWApplicant.loadStagePrompts();
        if (cancelled) return;
        if (prompts.written) setWrittenData(prompts.written);
        if (prompts.case) setCaseData(prompts.case);
      } catch (err) {
        console.warn('Could not load stage prompts:', err.message);
      }
    })();
    return () => { cancelled = true; };
  }, []);

  const email = applicantEmail || WWAuth.getEmail() || 'anonymous';

  const persistStage = async (result) => {
    setSaving(true);
    try {
      if (window.WWApplicant?.saveStageResult) {
        await window.WWApplicant.saveStageResult(stage.key, result);
      }
    } catch (err) {
      console.warn('Stage save failed:', err.message);
    } finally {
      setSaving(false);
    }
  };

  const resolveMilestone1Result = async (sjtScore) => {
    let evaluation = {
      passed: false,
      breakdown: [],
      scores: { sjt: sjtScore },
      threshold: window.WWData?.ASSESS_CONFIG?.passThreshold || 70,
    };

    try {
      if (window.WWApplicant?.runMilestone1Gate) {
        evaluation = await window.WWApplicant.runMilestone1Gate('sjt', sjtScore);
      } else if (window.WWFunnel?.evaluateMilestone1) {
        evaluation = window.WWFunnel.evaluateMilestone1({ sjt: sjtScore });
      }
    } catch (err) {
      console.warn('Milestone 1 gate check failed:', err.message);
    }

    setMilestoneDetails(evaluation.breakdown);
    setResultVariant(evaluation.passed ? 'milestone-pass' : 'milestone-fail');

    if (onMilestone1Evaluated) onMilestone1Evaluated(evaluation);

    return evaluation;
  };

  const handleMcqSubmit = async (s, correct, total) => {
    const indices = (sessionQuestions || []).map((q) => q.poolIndex ?? q._poolIndex).filter((x) => x != null);
    try {
      await persistStage({
        score: s,
        payload: { correct, total, questionIndices: indices, attemptId },
        durationSec: WWAssess.sessionMins(stage) * 60,
      });
      setScore(s);
      if (stage.key === 'sjt') {
        await resolveMilestone1Result(s);
      }
    } catch (err) {
      console.warn('Submit failed:', err.message);
      setScore(s);
      if (stage.key === 'sjt') {
        setMilestoneDetails(null);
        setResultVariant('milestone-fail');
      }
    }
    // Switch to result BEFORE clearing questions — null questions crashes McqPlayer mid-render.
    setPhase('result');
    setSessionQuestions(null);
  };

  const handleWrittenSubmit = async (essays) => {
    const payloadEssays = (essays || []).map(({ id, title, prompt, text, wordCount }) => ({
      id, title, prompt, text, wordCount,
    }));
    try {
      await persistStage({ score: null, payload: { essays: payloadEssays } });
      if (onScoresChange) await onScoresChange();
    } catch (err) {
      console.warn('Written save failed:', err.message);
    } finally {
      setResultVariant(null);
      setPhase('result');
    }
  };

  const handleCaseSubmit = async (file) => {
    try {
      if (file && window.WWApplicant?.uploadCase && WWAuth.useSupabase && WWAuth.useSupabase()) {
        setSaving(true);
        await window.WWApplicant.uploadCase(file);
        await window.WWApplicant.saveStageResult(stage.key, { score: null, payload: { filename: file.name } });
      } else if (file) {
        await persistStage({ score: null, payload: { filename: file.name } });
      }
      if (onScoresChange) await onScoresChange();
      setResultVariant('case-review');
      if (onMilestone2Submitted) onMilestone2Submitted();
    } catch (err) {
      console.warn('Case save failed:', err.message);
      setResultVariant('case-review');
    } finally {
      setSaving(false);
      setPhase('result');
    }
  };

  const handleInterviewSubmit = async (slot) => {
    try {
      await persistStage({ score: null, payload: { slot } });
      if (onScoresChange) await onScoresChange();
      setResultVariant('milestone-complete');
    } catch (err) {
      console.warn('Interview save failed:', err.message);
      setResultVariant('milestone-complete');
    } finally {
      setPhase('result');
    }
  };

  const abortSession = React.useCallback((goHome) => {
    setSessionQuestions(null);
    setPhase('intro');
    if (goHome) onBack();
  }, [onBack]);

  React.useEffect(() => {
    if (!onBindGuard) return;
    onBindGuard(() => {
      if (phase === 'do' && timed) {
        if (!window.confirm(QUIT_MSG)) return false;
        abortSession(false);
      }
      return true;
    });
    return () => onBindGuard(null);
  }, [phase, timed, onBindGuard, abortSession]);

  React.useEffect(() => {
    if (phase !== 'do' || !timed) return;
    const warn = (e) => { e.preventDefault(); e.returnValue = ''; };
    window.addEventListener('beforeunload', warn);
    return () => window.removeEventListener('beforeunload', warn);
  }, [phase, timed]);

  const startSession = () => {
    const nextAttempt = attemptId + 1;
    setAttemptId(nextAttempt);
    if (timed) {
      const qs = WWAssess.pickSessionQuestions(stage.key, email, nextAttempt);
      setSessionQuestions(qs);
      setSessionKey((k) => k + 1);
    }
    setPhase('do');
  };

  const requestExit = (goHome) => {
    if (phase === 'do' && timed) {
      if (!window.confirm(QUIT_MSG)) return;
      abortSession(goHome);
      return;
    }
    if (goHome) onBack();
    else setPhase('intro');
  };

  if (phase === 'intro') {
    return (
      <AssessIntro stage={stage} timed={timed} onBack={onBack} onStart={startSession} />
    );
  }

  if (phase === 'result') {
    const variant = resultVariant
      || (stage.key === 'sjt' ? 'milestone-fail' : null)
      || (stage.key === 'case' ? 'case-review' : null)
      || (stage.key === 'interview' ? 'milestone-complete' : null);
    return (
      <ResultScreen
        stage={stage}
        score={score}
        variant={variant}
        milestoneDetails={milestoneDetails}
        isLast={stage.key === 'interview'}
        onContinue={onComplete}
      />
    );
  }

  if (stage.kind === 'mcq' || stage.kind === 'sjt') {
    return (
      <McqPlayer
        key={sessionKey}
        stage={stage}
        questions={sessionQuestions}
        sessionMins={WWAssess.sessionMins(stage)}
        onQuitRequest={() => abortSession(false)}
        onSubmit={handleMcqSubmit}
      />
    );
  }

  if (stage.kind === 'written') {
    return <WrittenScreen data={writtenData} onBack={() => requestExit(false)} onSubmit={handleWrittenSubmit} />;
  }
  if (stage.kind === 'case') {
    return <CaseScreen data={caseData} onBack={() => requestExit(false)} onSubmit={handleCaseSubmit} />;
  }
  if (stage.kind === 'interview') {
    return <InterviewScreen data={QUESTIONS.interview} onBack={() => requestExit(false)} onSubmit={handleInterviewSubmit} />;
  }
  return null;
}

Object.assign(window, { StageFlow, AssessIntro, McqPlayer, WrittenScreen, CaseScreen, InterviewScreen, ResultScreen });
