const LivenessChallengeOverlay = ({ challenges, onComplete, onCancel, onError }) => {
  const videoRef = React.useRef(null);
  const streamRef = React.useRef(null);
  const cancelledRef = React.useRef(false);
  const [prompt, setPrompt] = React.useState('');
  const [status, setStatus] = React.useState('Загрузка…');

  React.useEffect(() => {
    cancelledRef.current = false;
    const TIMEOUT_MS = 20000;

    const run = async () => {
      try {
        await loadFaceModels();
        if (cancelledRef.current) return;
        streamRef.current = await startCamera(videoRef.current);
        if (cancelledRef.current) return;

        const queue = challenges.map((n) => createChallenge(n));
        const deadline = performance.now() + TIMEOUT_MS;
        let i = 0;
        setPrompt(queue[0].label);
        setStatus('');

        while (i < queue.length) {
          if (cancelledRef.current) return;
          if (performance.now() > deadline) throw new Error('timeout');
          const r = await detectWithLandmarks(videoRef.current);
          if (!r) { await new Promise((res) => requestAnimationFrame(res)); continue; }
          const cur = queue[i];
          cur.detector.update(r.landmarks);
          if (cur.detector.isDone) {
            i++;
            if (i < queue.length) {
              setPrompt('Подождите…');
              let neutralSince = null;
              while (true) {
                if (cancelledRef.current) return;
                if (performance.now() > deadline) throw new Error('timeout');
                const r2 = await detectWithLandmarks(videoRef.current);
                if (r2 && queue[i].detector.isNeutral(r2.landmarks)) {
                  if (!neutralSince) neutralSince = performance.now();
                  if (performance.now() - neutralSince >= 500) break;
                } else {
                  neutralSince = null;
                }
                await new Promise((res) => requestAnimationFrame(res));
              }
              setPrompt(queue[i].label);
            }
          }
          await new Promise((res) => requestAnimationFrame(res));
        }
        if (cancelledRef.current) return;
        onComplete(challenges);
      } catch (e) {
        if (cancelledRef.current) return;
        if (e && e.message === 'timeout') onError('Время истекло');
        else onError('Ошибка: ' + (e && e.message ? e.message : String(e)));
      }
    };

    run();

    return () => {
      cancelledRef.current = true;
      stopCamera(streamRef.current);
      streamRef.current = null;
    };
  }, []);

  return (
    <div style={{ display:'flex', flexDirection:'column', gap: 12 }}>
      <div style={{ position:'relative', width:'100%', aspectRatio:'4 / 3', background:'#000', borderRadius: 14, overflow:'hidden' }}>
        <video ref={videoRef} autoPlay muted playsInline
               style={{ position:'absolute', inset: 0, width:'100%', height:'100%', objectFit:'cover' }}/>
      </div>
      <div style={{ fontSize: 18, fontWeight: 600, color:'var(--accent-hover)', minHeight: 28 }}>{prompt}</div>
      <div style={{ display:'flex', alignItems:'center', justifyContent:'space-between', gap: 10 }}>
        <div style={{ fontSize: 13, color:'var(--fg-muted)' }}>{status}</div>
        {onCancel && <Button variant="ghost" size="sm" onClick={onCancel}>Отмена</Button>}
      </div>
    </div>
  );
};

Object.assign(window, { LivenessChallengeOverlay });
