/* Shadowing avec micro — drill LIBRE (PEDAGOGIE P14, boucle phonologique).
   Écouter le modèle -> s'enregistrer -> réécouter les deux côte à côte ->
   s'auto-noter. La confrontation modèle/soi EST le feedback ; aucun effet SRS,
   rien n'est envoyé nulle part (l'enregistrement reste en mémoire locale). */

function shadowingSupported() {
  return !!(navigator.mediaDevices && navigator.mediaDevices.getUserMedia && window.MediaRecorder);
}

function ShadowingRecorder({ modelText, audioRef, audioUrl }) {
  const [phase, setPhase] = useState("idle"); // idle | recording | recorded
  const [micError, setMicError] = useState("");
  const [takeUrl, setTakeUrl] = useState("");
  const [busy, setBusy] = useState(false);
  const [selfNote, setSelfNote] = useState("");
  const [tally, setTally] = useState({ proche: 0, moyen: 0, loin: 0 });
  const recorderRef = useRef(null);
  const takeAudioRef = useRef(null);

  const discardTake = () => {
    if (takeAudioRef.current) { takeAudioRef.current.pause(); takeAudioRef.current = null; }
    setTakeUrl(prev => { if (prev) URL.revokeObjectURL(prev); return ""; });
    setSelfNote("");
    setPhase("idle");
  };

  // Nouvel item = nouvelle prise ; on libère l'ancienne.
  useEffect(() => { discardTake(); setMicError(""); }, [modelText]);
  useEffect(() => () => {
    if (recorderRef.current && recorderRef.current.state !== "inactive") recorderRef.current.stop();
    discardTake();
  }, []);

  const playModel = (onEnd) => {
    if (!window.LangAudio) return;
    window.LangAudio.speak(modelText || "", { ref: audioRef, url: audioUrl, onEnd });
  };

  const playTake = () => {
    if (!takeUrl) return;
    if (window.LangAudio) window.LangAudio.stop();
    if (takeAudioRef.current) takeAudioRef.current.pause();
    const a = new Audio(takeUrl);
    takeAudioRef.current = a;
    a.play().catch(() => {});
  };

  const compare = () => {
    // Modèle puis ma voix, enchaînés : c'est le contraste qui fait remarquer l'écart.
    setBusy(true);
    playModel(() => { playTake(); setBusy(false); });
    // garde-fou si onEnd ne revient pas (source sans événement de fin)
    setTimeout(() => setBusy(false), 8000);
  };

  const startRecording = async () => {
    setMicError("");
    if (!shadowingSupported()) {
      setMicError("Micro indisponible dans ce navigateur.");
      return;
    }
    try {
      const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
      if (window.LangAudio) window.LangAudio.stop();
      const recorder = new MediaRecorder(stream);
      const chunks = [];
      recorder.ondataavailable = (ev) => { if (ev.data && ev.data.size) chunks.push(ev.data); };
      recorder.onstop = () => {
        stream.getTracks().forEach(t => t.stop());
        const blob = new Blob(chunks, { type: recorder.mimeType || "audio/webm" });
        setTakeUrl(prev => { if (prev) URL.revokeObjectURL(prev); return URL.createObjectURL(blob); });
        setPhase("recorded");
      };
      recorderRef.current = recorder;
      recorder.start();
      setPhase("recording");
    } catch (e) {
      setMicError("Accès micro refusé — autorisez le micro pour vous enregistrer.");
      setPhase("idle");
    }
  };

  const stopRecording = () => {
    const r = recorderRef.current;
    if (r && r.state !== "inactive") r.stop();
  };

  const note = (key) => {
    setSelfNote(key);
    setTally(prev => ({ ...prev, [key]: prev[key] + 1 }));
  };

  if (!shadowingSupported()) {
    return <p className="faint" style={{ fontSize: 12.5, margin: 0 }}>Shadowing micro indisponible : ce navigateur ne permet pas l'enregistrement audio.</p>;
  }

  const noteChip = (key, label, color) => (
    <button key={key} onClick={() => note(key)} className="chip" style={{
      cursor: "pointer", fontSize: 12.5,
      background: selfNote === key ? color : "var(--card)",
      color: selfNote === key ? "#fff" : "var(--ink-soft)",
      borderColor: selfNote === key ? "transparent" : "var(--rule)",
    }}>{label}</button>
  );

  return (
    <div style={{ display: "grid", gap: 10, padding: "12px 14px", borderRadius: "var(--radius-sm)", background: "var(--card-2)", border: "1px solid var(--rule)" }}>
      <div style={{ display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap" }}>
        <span className="eyebrow">Shadowing micro</span>
        <span className="chip" style={{ fontSize: 11 }}>libre · rien n'est enregistré durablement</span>
        {(tally.proche + tally.moyen + tally.loin) > 0 && (
          <span className="faint" style={{ fontSize: 12, fontFamily: "var(--mono)", marginLeft: "auto" }}>
            {tally.proche} proche · {tally.moyen} moyen · {tally.loin} à retravailler
          </span>
        )}
      </div>
      <div style={{ display: "flex", gap: 8, flexWrap: "wrap", alignItems: "center" }}>
        {phase !== "recording" && (
          <Btn kind={phase === "recorded" ? "secondary" : "primary"} size="sm" icon="speaker" onClick={() => { startRecording(); }}>
            {phase === "recorded" ? "Refaire une prise" : "S'enregistrer"}
          </Btn>
        )}
        {phase === "recording" && (
          <Btn kind="primary" size="sm" icon="check" onClick={stopRecording}>■ Terminer la prise</Btn>
        )}
        {phase === "recording" && <span className="chip fade-up" style={{ background: "var(--warn-tint)", color: "var(--warn)", borderColor: "transparent" }}>● enregistrement…</span>}
        {phase === "recorded" && (
          <>
            <Btn kind="secondary" size="sm" icon="play" onClick={playTake}>Ma voix</Btn>
            <Btn kind="secondary" size="sm" icon="repeat" disabled={busy} onClick={compare}>Modèle puis moi</Btn>
          </>
        )}
      </div>
      {phase === "recorded" && (
        <div className="fade-up" style={{ display: "flex", gap: 6, flexWrap: "wrap", alignItems: "center" }}>
          <span className="faint" style={{ fontSize: 12.5 }}>Mon imitation est :</span>
          {noteChip("proche", "Proche", "var(--good)")}
          {noteChip("moyen", "Moyenne", "var(--ochre)")}
          {noteChip("loin", "À retravailler", "var(--warn)")}
          {selfNote === "loin" && <span className="faint" style={{ fontSize: 12 }}>Réécoutez le modèle lentement, puis refaites une prise.</span>}
        </div>
      )}
      {micError && <span className="chip" style={{ background: "var(--warn-tint)", color: "var(--warn)", borderColor: "transparent", fontSize: 12 }}>{micError}</span>}
    </div>
  );
}
