/* CoursViewer — vue web in-app des cours (même JSON que le PDF, 2e cible de rendu).
   Tout élément .kr est CLIQUABLE -> LangAudio.speak (mp3 ElevenLabs si connu,
   sinon repli voix ko-KR du navigateur). Le PDF reste dispo en export. */

// Enrobe tout Hangul "nu" dans un .kr (-> cliquable pour le TTS). Si la chaîne
// contient déjà des .kr (cas des html de leçon), on ne touche à rien.
function krWrap(s) {
  if (s == null) return "";
  s = String(s);
  if (/class\s*=\s*["'][^"']*\bkr\b/.test(s)) return s;
  return s.replace(/[가-힣ㄱ-ㆎ]+/g, (m) => '<span class="kr">' + m + '</span>');
}
function coursHtml(s) { return { __html: krWrap(s) }; }

function CoursLessonBlocks({ lesson }) {
  const blocks = (lesson && lesson.blocks) || [];
  return blocks.map((blk, bi) => {
    const t = blk.type;
    if (t === "section") return (
      <div key={bi} style={{ marginTop: 16 }}>
        <h3 style={{ fontFamily: "var(--serif)", fontSize: 18, color: "var(--accent-deep)", margin: "0 0 3px" }}>{blk.titre}</h3>
        {blk.intro && <p className="muted" style={{ fontSize: 13.5, margin: 0 }} dangerouslySetInnerHTML={coursHtml(blk.intro)} />}
      </div>
    );
    if (t === "objectif") return (
      <div key={bi} className="card cours-enc" style={{ background: "var(--card-2)" }}>
        <div className="cours-enc-t">🎯 Objectif</div>
        <div dangerouslySetInnerHTML={coursHtml(blk.texte)} />
        {(blk.acquis || blk.nouveau) && (
          <div className="cours-grid2">
            <div><span className="cours-lab">Déjà acquis</span><div dangerouslySetInnerHTML={coursHtml(blk.acquis)} /></div>
            <div><span className="cours-lab">Nouveau</span><div dangerouslySetInnerHTML={coursHtml(blk.nouveau)} /></div>
          </div>
        )}
      </div>
    );
    if (t === "table") return (
      <div key={bi} className="cours-table-wrap">
        <table className="cours-table">
          <thead><tr>{(blk.cols || []).map((c, i) => <th key={i}>{c}</th>)}</tr></thead>
          <tbody>{(blk.rows || []).map((row, ri) => (
            <tr key={ri}>{row.map((cell, ci) => (
              <td key={ci} className={(blk.classes && blk.classes[ci]) || ""} dangerouslySetInnerHTML={coursHtml(cell)} />
            ))}</tr>
          ))}</tbody>
        </table>
      </div>
    );
    if (t === "grille") return (
      <div key={bi} style={{ marginTop: 10 }}>
        {blk.titre && <div className="cours-grille-t">{blk.titre}</div>}
        {blk.intro && <p className="muted" style={{ fontSize: 12.5, margin: "0 0 6px" }} dangerouslySetInnerHTML={coursHtml(blk.intro)} />}
        <table className="cours-grille"><tbody>{(blk._cells || []).map((row, ri) => (
          <tr key={ri}>{row.map((c, ci) => <td key={ci} className="kr">{c}</td>)}</tr>
        ))}</tbody></table>
      </div>
    );
    if (t === "regle" || t === "piege" || t === "astuce" || t === "exemple") {
      const lab = { regle: "📐 Règle", piege: "⚠️ Piège", astuce: "💡 Astuce", exemple: "🔎 Exemple" }[t];
      return (
        <div key={bi} className={"card cours-enc cours-" + t}>
          <div className="cours-enc-t">{lab}{blk.titre ? " — " + blk.titre : ""}</div>
          <div dangerouslySetInnerHTML={coursHtml(blk.html)} />
        </div>
      );
    }
    if (t === "phrases" || t === "phrase") {
      const items = t === "phrases" ? (blk.items || []) : [blk];
      return (
        <div key={bi} style={{ display: "grid", gap: 8, margin: "6px 0" }}>
          {items.map((it, ii) => (
            <div key={ii} className="card" style={{ padding: 12 }}>
              <div>{(it.blocs || []).map((b, bii) => (
                <span key={bii} className="kr" style={{ fontSize: 20, marginRight: 6, display: "inline-block" }}>{b && b.txt ? b.txt : String(b)}</span>
              ))}</div>
              {it.fr && <div className="muted" style={{ fontSize: 13, marginTop: 3 }} dangerouslySetInnerHTML={coursHtml(it.fr)} />}
            </div>
          ))}
        </div>
      );
    }
    if (t === "dialogue") return (
      <div key={bi} className="card cours-enc">
        <div className="cours-enc-t">💬 Mini-dialogue{blk.titre ? " — " + blk.titre : ""}</div>
        {(blk.turns || []).map((tn, ti) => (
          <div key={ti} style={{ margin: "5px 0" }}>
            <b style={{ marginRight: 6, color: "var(--accent-deep)" }}>{tn.who}</b>
            <span className="kr" style={{ fontSize: 19 }}>{tn.kr}</span>
            {tn.fr && <span className="muted" style={{ fontSize: 12.5 }} dangerouslySetInnerHTML={coursHtml(" — " + tn.fr)} />}
          </div>
        ))}
      </div>
    );
    if (t === "exercice") return (
      <div key={bi} className="card cours-enc">
        <div className="cours-enc-t">✍️ Exercice {blk.num} — <span dangerouslySetInnerHTML={coursHtml(blk.consigne)} /></div>
        <ol className="cours-ol">{(blk.items || []).map((it, ii) => <li key={ii} dangerouslySetInnerHTML={coursHtml(it.q)} />)}</ol>
      </div>
    );
    if (t === "corrige") return (
      <div key={bi} className="card cours-enc cours-corr">
        <div className="cours-enc-t">✅ Corrigé {blk.num}</div>
        <ol className="cours-ol">{(blk.items || []).map((it, ii) => <li key={ii} dangerouslySetInnerHTML={coursHtml(it)} />)}</ol>
      </div>
    );
    if (t === "tajournee") return (
      <div key={bi} className="card cours-enc cours-tj">
        <div className="cours-enc-t">🗓️ Ta journée — <span dangerouslySetInnerHTML={coursHtml(blk.consigne)} /></div>
        {blk.modele && <div className="muted" style={{ fontSize: 13 }}>Modèle : <span className="kr">{blk.modele}</span></div>}
        {blk.amorces && <div className="muted" style={{ fontSize: 12.5, marginTop: 3 }}>Amorces : {blk.amorces.map((a, ai) => <span key={ai} className="kr" style={{ marginRight: 8 }}>{a}</span>)}</div>}
      </div>
    );
    if (t === "bilan") return (
      <div key={bi} className="card cours-enc cours-bilan">
        <div className="cours-enc-t">🎯 Je peux…</div>
        <ul className="cours-ul">{(blk.items || []).map((it, ii) => <li key={ii} dangerouslySetInnerHTML={coursHtml(it)} />)}</ul>
      </div>
    );
    if (t === "revision") return (
      <div key={bi} className="card cours-enc"><div className="cours-enc-t">🔁 Révision</div><div dangerouslySetInnerHTML={coursHtml(blk.html)} /></div>
    );
    if (t === "html") return <div key={bi} dangerouslySetInnerHTML={coursHtml(blk.html)} />;
    if (t === "legende") return blk.note ? <p key={bi} className="muted" style={{ fontSize: 12.5 }} dangerouslySetInnerHTML={coursHtml(blk.note)} /> : null;
    return null; // pagebreak & co.
  });
}

function CoursViewer({ niveauFilter }) {
  const [status, setStatus] = useState("loading");
  const [index, setIndex] = useState(null);
  const [sel, setSel] = useState(null);          // entrée du catalogue choisie
  const [lesson, setLesson] = useState(null);
  const [lessonStatus, setLessonStatus] = useState("idle");

  useEffect(() => {
    let alive = true;
    fetch("data/cours/index.json")
      .then(r => r.json())
      .then(j => { if (alive) { setIndex(j); setStatus("ready"); } })
      .catch(() => { if (alive) setStatus("error"); });
    return () => { alive = false; if (window.LangAudio) window.LangAudio.stop(); };
  }, []);

  const openLesson = (entry) => {
    setSel(entry);
    setLesson(null);
    setLessonStatus("loading");
    if (window.LangAudio) window.LangAudio.stop();
    fetch("data/cours/" + entry.file)
      .then(r => r.json())
      .then(j => { setLesson(j); setLessonStatus("ready"); window.scrollTo(0, 0); })
      .catch(() => setLessonStatus("error"));
  };

  const back = () => { setSel(null); setLesson(null); setLessonStatus("idle"); if (window.LangAudio) window.LangAudio.stop(); };

  // Délégation : un clic sur n'importe quel .kr -> on l'entend.
  const onClickSpeak = (e) => {
    const el = e.target.closest && e.target.closest(".kr");
    if (!el || !window.LangAudio) return;
    const txt = (el.textContent || "").trim();
    if (!txt) return;
    // Un jamo CONSONNE seul (ㄱ, ㅅ…) ferait dire son NOM par le TTS (« 기역 »).
    // On ne l'écoute donc pas. Voyelles seules et syllabes : OK.
    if (txt.length === 1) { const c = txt.charCodeAt(0); if (c >= 0x3131 && c <= 0x314e) return; }
    window.LangAudio.speak(txt);
  };

  if (status === "loading") return (window.LoadingCard ? <LoadingCard lines={3} /> : <div className="muted">Chargement…</div>);
  if (status === "error") return (window.ErrorState ? <ErrorState title="Cours indisponibles" body="data/cours/index.json introuvable (lance le build)." /> : <div className="muted">Cours indisponibles.</div>);

  // --- Vue LECTURE d'une leçon ---
  if (sel) {
    const m = (lesson && lesson.meta) || {};
    return (
      <div className="cours-view" onClick={onClickSpeak} style={{ display: "grid", gap: "var(--gap)" }}>
        <div style={{ display: "flex", gap: 10, alignItems: "center", flexWrap: "wrap" }}>
          <Btn kind="ghost" size="sm" icon="back" onClick={back}>Retour</Btn>
          <span style={{ flex: 1 }} />
          <span className="chip">👆 Touche un mot coréen pour l'entendre</span>
          {sel.pdf && <a className="chip" href={sel.pdf} target="_blank" rel="noopener" style={{ textDecoration: "none" }}>PDF ↗</a>}
        </div>
        {lessonStatus === "loading" && (window.LoadingCard ? <LoadingCard lines={5} /> : <div className="muted">Chargement…</div>)}
        {lessonStatus === "error" && <div className="muted">Leçon introuvable.</div>}
        {lessonStatus === "ready" && lesson && (
          <div style={{ display: "grid", gap: 12 }}>
            <div>
              <div className="muted" style={{ fontSize: 12, letterSpacing: ".08em", textTransform: "uppercase" }}>{m.serie} · {m.code}</div>
              <h2 style={{ fontFamily: "var(--serif)", fontSize: 24, color: "var(--accent-deep)", margin: "2px 0 0" }}>{m.titre}</h2>
              {m.sous_titre && <p className="muted" style={{ fontSize: 14, margin: "2px 0 0" }}>{m.sous_titre}</p>}
            </div>
            <CoursLessonBlocks lesson={lesson} />
          </div>
        )}
      </div>
    );
  }

  // --- Vue CATALOGUE ---
  const niveaux = ((index && index.niveaux) || []).filter(n => !niveauFilter || n.niveau === niveauFilter);
  return (
    <div style={{ display: "grid", gap: "var(--gap)" }}>
      {niveaux.map(n => (
        <section key={n.niveau} style={{ display: "grid", gap: 10 }}>
          <Eyebrow>{n.niveau}</Eyebrow>
          <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fill,minmax(240px,1fr))", gap: 10 }}>
            {n.lecons.map(l => (
              <button key={l.file} className="card" onClick={() => openLesson(l)} style={{ textAlign: "left", border: "1px solid var(--rule)", cursor: "pointer", padding: 14, display: "grid", gap: 4 }}>
                <span style={{ fontFamily: "var(--mono)", fontSize: 11.5, color: "var(--accent)", fontWeight: 600 }}>{l.code}</span>
                <span style={{ fontWeight: 600, color: "var(--accent-deep)" }}>{l.titre}</span>
                {l.titre_court && <span className="kr muted" style={{ fontSize: 13 }}>{l.titre_court}</span>}
              </button>
            ))}
          </div>
        </section>
      ))}
    </div>
  );
}

(function injectCoursCSS() {
  if (typeof document === "undefined" || document.getElementById("cours-css")) return;
  const s = document.createElement("style");
  s.id = "cours-css";
  s.textContent = [
    ".cours-view .kr{cursor:pointer;border-radius:4px;transition:background .12s;}",
    ".cours-view .kr:hover{background:rgba(184,85,74,.14);}",
    ".cours-view .kr:active{background:rgba(184,85,74,.28);}",
    ".cours-enc{padding:14px 16px;}",
    ".cours-enc-t{font-weight:700;font-size:13.5px;color:var(--accent-deep);margin-bottom:6px;}",
    ".cours-grid2{display:grid;grid-template-columns:1fr 1fr;gap:6px 16px;margin-top:8px;}",
    ".cours-lab{font-size:11px;text-transform:uppercase;letter-spacing:.05em;color:var(--muted);display:block;}",
    ".cours-table-wrap{overflow-x:auto;}",
    ".cours-table{width:100%;border-collapse:collapse;margin:6px 0;font-size:14px;}",
    ".cours-table th{text-align:left;background:var(--card-2);padding:6px 9px;font-size:12.5px;border-bottom:1px solid var(--rule);}",
    ".cours-table td{padding:6px 9px;border-bottom:1px solid var(--rule);vertical-align:top;}",
    ".cours-table td.kr,.cours-table .kr{font-size:18px;}",
    ".cours-grille-t{font-weight:600;color:var(--accent-deep);margin:6px 0 4px;font-size:14px;}",
    ".cours-grille{border-collapse:collapse;width:100%;table-layout:fixed;}",
    ".cours-grille td{border:1px solid var(--rule);text-align:center;padding:7px 2px;font-size:22px;}",
    ".cours-ol,.cours-ul{margin:4px 0 0 18px;padding:0;display:grid;gap:3px;font-size:14px;}",
    ".cours-view .small{font-size:12.5px;color:var(--muted);}",
    ".cours-view .tight{margin:4px 0 4px 18px;}",
    ".cours-view .kr-big{font-size:1.3em;}",
    ".cours-view table{max-width:100%;}",
    ".cours-piege{background:var(--warn-tint);}",
    ".cours-corr,.cours-bilan{background:var(--good-tint);}",
  ].join("\n");
  document.head.appendChild(s);
})();

Object.assign(window, { CoursViewer, CoursLessonBlocks });
