/* ============================================================
   speaking.jsx — Speaking section runner
   Exports: window.SpeakingInterstitial, window.SpeakingSection
   ============================================================ */
(function () {
const { useState, useEffect, useRef } = React;
const S = window.TestStore;

/* ============================================================
   Single question UI — prep → speak → done
   ============================================================ */
function SpeakingQuestion({ item, index, total, onComplete }) {
  const [phase, setPhase]       = useState("prep");   // prep | speak | done
  const [timeLeft, setTimeLeft] = useState(item.prepTime > 0 ? item.prepTime : 0);
  const phaseRef    = useRef("prep");
  const timerRef    = useRef(null);
  const startRef    = useRef(null);
  const mediaRef    = useRef(null);
  const streamRef   = useRef(null);
  const chunksRef   = useRef([]);

  /* cleanup on unmount */
  useEffect(() => () => {
    clearInterval(timerRef.current);
    stopMedia();
  }, []);

  /* kick off prep on mount / item change */
  useEffect(() => {
    phaseRef.current = "prep";
    setPhase("prep");
    if (item.prepTime > 0) {
      setTimeLeft(item.prepTime);
      runTimer(item.prepTime, beginSpeaking);
    } else {
      setTimeLeft(0);
      beginSpeaking();
    }
    return () => { clearInterval(timerRef.current); stopMedia(); };
  }, [item.id]);

  function runTimer(seconds, onDone) {
    clearInterval(timerRef.current);
    let t = seconds;
    timerRef.current = setInterval(() => {
      t -= 1;
      setTimeLeft(t);
      if (t <= 0) { clearInterval(timerRef.current); onDone(); }
    }, 1000);
  }

  function stopMedia() {
    try {
      if (mediaRef.current && mediaRef.current.state !== "inactive") mediaRef.current.stop();
      if (streamRef.current) streamRef.current.getTracks().forEach((t) => t.stop());
    } catch (e) {}
    mediaRef.current = null;
    streamRef.current = null;
  }

  function beginSpeaking() {
    if (phaseRef.current === "speak" || phaseRef.current === "done") return;
    clearInterval(timerRef.current);
    phaseRef.current = "speak";
    setPhase("speak");
    setTimeLeft(item.responseTime);
    startRef.current = Date.now();

    /* Try to start microphone recording */
    chunksRef.current = [];
    if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
      navigator.mediaDevices.getUserMedia({ audio: true })
        .then((stream) => {
          streamRef.current = stream;
          try {
            const mr = new MediaRecorder(stream, { audioBitsPerSecond: 16000 });
            mediaRef.current = mr;
            mr.ondataavailable = (e) => { if (e.data.size > 0) chunksRef.current.push(e.data); };
            mr.start();
          } catch (_) {}
        })
        .catch(() => {}); /* permission denied – UI still runs */
    }

    runTimer(item.responseTime, finishSpeaking);
  }

  function finishSpeaking() {
    if (phaseRef.current === "done") return;
    clearInterval(timerRef.current);
    const duration = startRef.current ? Math.round((Date.now() - startRef.current) / 1000) : 0;
    phaseRef.current = "done";
    setPhase("done");

    const mr = mediaRef.current;
    const stream = streamRef.current;
    mediaRef.current = null;
    streamRef.current = null;
    if (stream) stream.getTracks().forEach((t) => t.stop());

    let audioReady = false, timerFired = false, audioDataUrl = null;
    function tryComplete() {
      if (audioReady && timerFired)
        onComplete({ id: item.id, attempted: true, duration, ...(audioDataUrl ? { audioDataUrl } : {}) });
    }
    setTimeout(() => { timerFired = true; tryComplete(); }, 900);

    if (mr && mr.state !== "inactive") {
      mr.onstop = () => {
        const chunks = chunksRef.current;
        if (chunks.length > 0) {
          const blob = new Blob(chunks, { type: mr.mimeType || "audio/webm" });
          const reader = new FileReader();
          reader.onload = () => { audioDataUrl = reader.result; audioReady = true; tryComplete(); };
          reader.onerror = () => { audioReady = true; tryComplete(); };
          reader.readAsDataURL(blob);
        } else { audioReady = true; tryComplete(); }
      };
      mr.stop();
    } else { audioReady = true; tryComplete(); }
  }

  function skipPrep() { clearInterval(timerRef.current); beginSpeaking(); }

  /* helpers */
  const fmt = (s) => `${String(Math.floor(s / 60)).padStart(2, "0")}:${String(s % 60).padStart(2, "0")}`;
  const R = 58, C = 2 * Math.PI * R;
  const prepPct  = item.prepTime > 0 ? timeLeft / item.prepTime : 0;
  const speakPct = item.responseTime > 0 ? timeLeft / item.responseTime : 0;

  return (
    <div className="col center" style={{ flex: 1, padding: "44px 24px 56px", textAlign: "center" }}>

      {/* progress dots */}
      <div className="row gap-2" style={{ marginBottom: 26 }}>
        {Array.from({ length: total }, (_, i) => (
          <div key={i} style={{
            width: 8, height: 8, borderRadius: "50%",
            background: i < index ? "var(--correct)" : i === index ? "var(--primary)" : "var(--line-strong)",
            transition: "background .3s",
          }} />
        ))}
      </div>

      <span className="eyebrow" style={{ marginBottom: 8 }}>Speaking · Question {index + 1} of {total}</span>
      {item.topic && (
        <span className="badge badge-primary" style={{ marginBottom: 26 }}>{item.topic}</span>
      )}

      {/* Prompt card */}
      <div className="card" style={{ maxWidth: 660, width: "100%", padding: "30px 34px", marginBottom: 38, boxShadow: "var(--sh-md)", textAlign: "left" }}>
        <p style={{ fontSize: 19, lineHeight: 1.72, fontFamily: "var(--font-serif)", color: "var(--ink)", margin: 0 }}>
          {item.prompt || <span className="faint" style={{ fontStyle: "italic" }}>No prompt has been set for this question.</span>}
        </p>
      </div>

      {/* ---- PREP phase ---- */}
      {phase === "prep" && (
        <div className="col center" style={{ gap: 20 }}>
          <div style={{ position: "relative", width: 136, height: 136 }}>
            <svg width="136" height="136" style={{ transform: "rotate(-90deg)" }} aria-hidden="true">
              <circle cx="68" cy="68" r={R} fill="none" stroke="var(--surface-3)" strokeWidth="10" />
              <circle cx="68" cy="68" r={R} fill="none" stroke="var(--accent)" strokeWidth="10" strokeLinecap="round"
                strokeDasharray={C} strokeDashoffset={C * (1 - prepPct)}
                style={{ transition: "stroke-dashoffset 1s linear" }} />
            </svg>
            <div style={{ position: "absolute", inset: 0, display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center" }}>
              <span className="serif" style={{ fontSize: 31, fontWeight: 700, color: "var(--accent)", lineHeight: 1 }}>{fmt(timeLeft)}</span>
              <span style={{ fontSize: 10.5, fontWeight: 700, letterSpacing: "0.13em", textTransform: "uppercase", color: "var(--ink-faint)", marginTop: 5 }}>Prep</span>
            </div>
          </div>
          <p className="muted" style={{ fontSize: 14.5, maxWidth: 380, lineHeight: 1.6 }}>
            Read the question and prepare your answer. You will be prompted to speak when preparation time ends.
          </p>
          <button className="btn btn-primary" onClick={skipPrep}>
            <Icon name="mic" size={16} /> Begin Speaking Now
          </button>
        </div>
      )}

      {/* ---- SPEAK phase ---- */}
      {phase === "speak" && (
        <div className="col center" style={{ gap: 20 }}>
          <div style={{ position: "relative", width: 136, height: 136 }}>
            <svg width="136" height="136" style={{ transform: "rotate(-90deg)" }} aria-hidden="true">
              <circle cx="68" cy="68" r={R} fill="none" stroke="var(--incorrect-soft)" strokeWidth="10" />
              <circle cx="68" cy="68" r={R} fill="none" stroke="var(--incorrect)" strokeWidth="10" strokeLinecap="round"
                strokeDasharray={C} strokeDashoffset={C * (1 - speakPct)}
                style={{ transition: "stroke-dashoffset 1s linear" }} />
            </svg>
            <div style={{ position: "absolute", inset: 0, display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center" }}>
              <span className="serif" style={{ fontSize: 31, fontWeight: 700, color: "var(--incorrect)", lineHeight: 1 }}>{fmt(timeLeft)}</span>
              <span style={{ fontSize: 10.5, fontWeight: 700, letterSpacing: "0.13em", textTransform: "uppercase", color: "var(--ink-faint)", marginTop: 5 }}>Speaking</span>
            </div>
          </div>
          <div className="row gap-2" style={{
            padding: "9px 20px", borderRadius: 999,
            background: "var(--incorrect-soft)", border: "1.5px solid var(--incorrect-line)",
          }}>
            <div style={{ width: 9, height: 9, borderRadius: "50%", background: "var(--incorrect)", animation: "recPulse 1.2s ease-in-out infinite" }} />
            <span style={{ fontSize: 13.5, fontWeight: 600, color: "var(--incorrect)" }}>Recording in progress</span>
          </div>
          <p className="muted" style={{ fontSize: 14, maxWidth: 360 }}>
            Speak clearly and answer the question. The recording stops automatically when time runs out.
          </p>
          <button className="btn btn-ghost btn-sm" onClick={finishSpeaking}>
            <Icon name="check" size={15} /> Finish Response Early
          </button>
        </div>
      )}

      {/* ---- DONE phase ---- */}
      {phase === "done" && (
        <div className="col center" style={{ gap: 16 }}>
          <div style={{ width: 64, height: 64, borderRadius: 16, background: "var(--correct-soft)", color: "var(--correct)", display: "flex", alignItems: "center", justifyContent: "center" }}>
            <Icon name="checkCircle" size={32} />
          </div>
          <span style={{ fontWeight: 600, fontSize: 17, color: "var(--correct)" }}>Response recorded</span>
          {index < total - 1 && <p className="muted" style={{ fontSize: 14 }}>Moving to next question…</p>}
          {index === total - 1 && <p className="muted" style={{ fontSize: 14 }}>All responses recorded. Calculating your results…</p>}
        </div>
      )}
    </div>
  );
}

/* ============================================================
   Interstitial shown between Reading and Speaking
   ============================================================ */
window.SpeakingInterstitial = function SpeakingInterstitial({ onContinue }) {
  const items = S.getTestSpeakingItems();
  return (
    <div className="view-in center" style={{ display: "flex", height: "100vh", flexDirection: "column", padding: 24, textAlign: "center" }}>
      <div style={{
        width: 60, height: 60, borderRadius: 15,
        background: "var(--incorrect-soft)", color: "var(--incorrect)",
        display: "flex", alignItems: "center", justifyContent: "center", marginBottom: 22,
      }}>
        <Icon name="mic" size={30} />
      </div>
      <span className="eyebrow">Next section</span>
      <h2 className="display" style={{ fontSize: 32, margin: "10px 0 12px" }}>Speaking Section</h2>
      <p className="muted" style={{ fontSize: 16, maxWidth: 480, marginBottom: 8, lineHeight: 1.6 }}>
        You have completed the written sections. Now you will answer <strong>{items.length}</strong> spoken question{items.length !== 1 ? "s" : ""}.
      </p>
      <p className="muted" style={{ fontSize: 14.5, maxWidth: 440, marginBottom: 28 }}>
        Each question includes preparation time then a timed recording period. Speak clearly into your microphone.
      </p>

      {/* per-question preview */}
      <div className="col gap-2" style={{ maxWidth: 480, width: "100%", marginBottom: 32 }}>
        {items.map((it, i) => (
          <div key={it.id} className="panel row gap-3" style={{ padding: "10px 16px", alignItems: "center", textAlign: "left" }}>
            <span className="badge badge-primary" style={{ flexShrink: 0 }}>Q{i + 1}</span>
            <span style={{ fontSize: 13.5, fontWeight: 500, flex: 1, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{it.topic || "Speaking"}</span>
            <span className="faint" style={{ fontSize: 12.5, flexShrink: 0 }}>
              <Icon name="clock" size={12} /> {it.prepTime}s prep · {it.responseTime}s response
            </span>
          </div>
        ))}
      </div>

      <button className="btn btn-primary btn-lg" onClick={onContinue}>
        <Icon name="mic" size={17} /> Begin Speaking <Icon name="arrowRight" size={17} />
      </button>
    </div>
  );
};

/* ============================================================
   Speaking section orchestrator
   ============================================================ */
window.SpeakingSection = function SpeakingSection({ onComplete }) {
  const items = S.getTestSpeakingItems();
  const [currentIdx, setCurrentIdx] = useState(0);
  const [collected, setCollected]   = useState([]);
  const doneRef = useRef(false);

  useEffect(() => {
    if (!items.length && !doneRef.current) {
      doneRef.current = true;
      onComplete([]);
    }
  }, []);

  if (!items.length) return null;

  function handleDone(result) {
    const next = [...collected, result];
    setCollected(next);
    if (currentIdx < items.length - 1) {
      setCurrentIdx((i) => i + 1);
    } else if (!doneRef.current) {
      doneRef.current = true;
      onComplete(next);
    }
  }

  const item = items[currentIdx];

  return (
    <div className="col" style={{ height: "100vh" }}>
      {/* header */}
      <header className="row spread" style={{
        padding: "12px 22px", borderBottom: "1px solid var(--line)",
        background: "var(--surface)", alignItems: "center", flexShrink: 0,
      }}>
        <div className="row gap-3" style={{ alignItems: "center" }}>
          <div style={{ width: 36, height: 36, borderRadius: 9, background: "var(--incorrect-soft)", color: "var(--incorrect)", display: "flex", alignItems: "center", justifyContent: "center" }}>
            <Icon name="mic" size={19} />
          </div>
          <div className="col" style={{ lineHeight: 1.2 }}>
            <span style={{ fontWeight: 600, fontSize: 15, fontFamily: "var(--font-serif)" }}>Speaking Section</span>
            <span className="faint" style={{ fontSize: 12.5 }}>Question {currentIdx + 1} of {items.length}</span>
          </div>
        </div>
        <span className="badge" style={{ background: "var(--incorrect-soft)", color: "var(--incorrect)", border: "1px solid var(--incorrect-line)" }}>
          <div style={{ width: 7, height: 7, borderRadius: "50%", background: "var(--incorrect)", animation: "recPulse 1.4s ease-in-out infinite" }} />
          Recording
        </span>
      </header>

      {/* progress bar */}
      <div style={{ height: 4, background: "var(--surface-3)", flexShrink: 0 }}>
        <div style={{
          height: "100%",
          width: `${(currentIdx / items.length) * 100}%`,
          background: "var(--incorrect)",
          transition: "width .4s ease",
        }} />
      </div>

      {/* body */}
      <div className="grow col" style={{ overflow: "auto", background: "var(--paper)" }}>
        <SpeakingQuestion
          key={item.id + "_" + currentIdx}
          item={item}
          index={currentIdx}
          total={items.length}
          onComplete={handleDone}
        />
      </div>
    </div>
  );
};

})();
