/* reader.jsx — Van Haren book reader: library + reader (highlights, notes, read-aloud) */

function BookCover({ book, w = 116, h = 158, small }) {
  if (book.cover && /^(data:|https?:|\.{0,2}\/)/.test(book.cover)) {
    return (
      <div style={{ width: w, height: h, borderRadius: 10, overflow: "hidden", position: "relative", flex: "none", boxShadow: "var(--shadow-md)", background: "#fff", border: "1px solid var(--line)" }}>
        <img src={book.cover} alt="" style={{ width: "100%", height: "100%", objectFit: "cover", display: "block" }} />
        <div style={{ position: "absolute", left: 0, top: 0, bottom: 0, width: 6, background: "rgba(0,0,0,.18)" }}></div>
      </div>
    );
  }
  return (
    <div style={{ width: w, height: h, borderRadius: 10, overflow: "hidden", position: "relative", flex: "none", boxShadow: "var(--shadow-md)", background: `linear-gradient(150deg, ${book.color}, color-mix(in oklab, ${book.color}, #0b1c3a 60%))` }}>
      <div className="hexfield" style={{ opacity: .4 }} />
      <div style={{ position: "absolute", left: 0, top: 0, bottom: 0, width: 6, background: "rgba(0,0,0,.18)" }} />
      <div style={{ position: "absolute", inset: 0, padding: small ? 10 : 13, display: "flex", flexDirection: "column", color: "#fff" }}>
        <Logo height={small ? 11 : 13} white />
        <div style={{ flex: 1, display: "grid", placeItems: "center" }}>
          <div className="hex-flat" style={{ width: small ? 30 : 40, height: small ? 30 : 40, clipPath: "polygon(50% 0,93% 25%,93% 75%,50% 100%,7% 75%,7% 25%)", background: "rgba(255,255,255,.16)", display: "grid", placeItems: "center" }}>
            <Icon name="book" size={small ? 16 : 20} style={{ color: "#fff" }} />
          </div>
        </div>
        <div style={{ fontFamily: "var(--display)", fontWeight: 700, fontSize: small ? 11 : 13, lineHeight: 1.15 }}>{book.title.replace(/ —.*/, "")}</div>
        <div style={{ fontSize: small ? 8 : 9, opacity: .8, marginTop: 3 }}>{book.track}</div>
      </div>
    </div>
  );
}

function Library({ openBook }) {
  const [ubooks, setUbooks] = useState([]);
  useEffect(() => {
    if (!window.BookStore) return;
    window.BookStore.list().then(b => setUbooks((b || []).sort((a, c) => (c.created || 0) - (a.created || 0)))).catch(() => {});
  }, []);
  const all = [...ubooks, ...BOOKS];
  return (
    <div className="vh-in">
      <PageHead eyebrow="Library" title="Reader" sub="Read Van Haren titles inside the platform — with highlights, notes, read-aloud and completion credit toward your passport." />
      <div style={{ display: "grid", gridTemplateColumns: "repeat(2,1fr)", gap: 18 }}>
        {all.map(b => (
          <button key={b.id} className="card" onClick={() => openBook(b)} style={{ textAlign: "left", padding: 20, display: "flex", gap: 18, cursor: "pointer", alignItems: "center" }}>
            <BookCover book={b} />
            <div style={{ flex: 1, minWidth: 0, display: "flex", flexDirection: "column", gap: 9, alignSelf: "stretch" }}>
              <div>
                <div className="dim" style={{ fontSize: 11.5, fontWeight: 700, textTransform: "uppercase", letterSpacing: ".07em", display: "flex", alignItems: "center", gap: 8 }}>{b.track}{b.uploaded && <span style={{ fontSize: 10, fontWeight: 800, color: "#00838f", background: "rgba(0,131,143,.12)", borderRadius: 999, padding: "2px 8px", letterSpacing: ".05em" }}>UPLOADED</span>}</div>
                <h3 style={{ fontSize: 18, fontWeight: 600, marginTop: 5 }}>{b.title}</h3>
                <div className="dim" style={{ fontSize: 13, marginTop: 4 }}>{b.author} · {b.pages} pages</div>
              </div>
              <div style={{ marginTop: "auto" }}>
                <div className="between" style={{ fontSize: 12.5, marginBottom: 7 }}>
                  <span style={{ fontWeight: 700, color: b.done ? "var(--vh-teal)" : "var(--ink-2)" }}>{b.done ? "Finished" : b.read > 0 ? b.read + "% read" : "Not started"}</span>
                  {b.read > 0 && !b.done && <span className="dim">{b.mins} min left</span>}
                </div>
                <div className="bar"><i style={{ width: b.read + "%", background: b.done ? "var(--vh-teal)" : undefined }} /></div>
                <div style={{ marginTop: 14 }}>
                  <span className="btn btn-ghost" style={{ pointerEvents: "none" }}><Icon name={b.read > 0 ? "play" : "book"} size={15} />{b.done ? "Read again" : b.read > 0 ? "Continue reading" : "Start reading"}</span>
                </div>
              </div>
            </div>
          </button>
        ))}
      </div>
    </div>
  );
}

/* split into sentences */
function sentences(text) { return text.match(/[^.!?]+[.!?]+|\S+$/g) || [text]; }

function Reader({ book, back, toast, backLabel, action }) {
  /* uploaded books carry their own extracted chapters; demo titles use the sample text */
  const chapterData = (book.chapters && book.chapters.length && book.chapters[0].paras) ? book.chapters : READER_CHAPTERS;
  const flat = useMemo(() => {
    const arr = [];
    chapterData.forEach((ch, ci) => ch.paras.forEach((p, pi) => sentences(p).forEach((s, si) => {
      arr.push({ id: ci + "-" + pi + "-" + si, ci, pi, text: s.trim() });
    })));
    return arr;
  }, [book]);
  const N = flat.length;

  const [hl, setHl] = useState(() => new Set());
  const [notes, setNotes] = useState([{ id: "n0", quote: "value is co-created", text: "Use this framing in the Q3 service review deck." }]);
  const [tab, setTab] = useState("notes");
  const [tool, setTool] = useState("read"); // read | highlight
  const [reading, setReading] = useState(false);
  const [idx, setIdx] = useState(0);
  const [rate, setRate] = useState(1);
  const [noteDraft, setNoteDraft] = useState("");

  /* read-aloud voices (Web Speech API) */
  const [voices, setVoices] = useState([]);
  const [voiceURI, setVoiceURI] = useState(() => localStorage.getItem("vhl_voice") || "");
  useEffect(() => {
    if (!window.speechSynthesis) return;
    const load = () => setVoices(window.speechSynthesis.getVoices() || []);
    load();
    window.speechSynthesis.addEventListener("voiceschanged", load);
    return () => window.speechSynthesis.removeEventListener("voiceschanged", load);
  }, []);
  useEffect(() => { try { localStorage.setItem("vhl_voice", voiceURI); } catch (e) {} }, [voiceURI]);
  const preferred = voices.filter(v => /^(en|nl|de|fr)/i.test(v.lang));
  const voiceList = (preferred.length ? preferred : voices).slice(0, 24);
  const voiceName = (v) => v.name.replace(/^(Microsoft|Google|Apple)\s*/i, "").replace(/\s*-\s*(English|Dutch|German|French).*$/i, "");
  function pickVoice(uri) {
    setVoiceURI(uri);
    /* not mid-read: speak a short sample so the choice is audible */
    if (!reading && window.speechSynthesis) {
      try {
        window.speechSynthesis.cancel();
        const u = new SpeechSynthesisUtterance("This is how this voice sounds.");
        const v = voices.find(x => x.voiceURI === uri);
        if (v) { u.voice = v; u.lang = v.lang; }
        u.rate = rate;
        window.speechSynthesis.speak(u);
      } catch (e) {}
    }
  }

  const progress = Math.max(book.read || 0, Math.round((idx / N) * 100));

  /* read-aloud driver */
  useEffect(() => {
    if (!reading) return;
    if (idx >= N) { setReading(false); toast("Reached the end of this section", "checkCircle"); return; }
    const cur = flat[idx];
    let spoke = false;
    try {
      if (window.speechSynthesis) {
        window.speechSynthesis.cancel();
        const u = new SpeechSynthesisUtterance(cur.text);
        u.rate = rate; u.pitch = 1; u.volume = 1;
        const v = voices.find(x => x.voiceURI === voiceURI);
        if (v) { u.voice = v; u.lang = v.lang; }
        window.speechSynthesis.speak(u);
        spoke = true;
      }
    } catch (e) {}
    const words = cur.text.split(/\s+/).length;
    const dur = Math.max(1100, (words * 300) / rate);
    const t = setTimeout(() => setIdx(i => i + 1), dur);
    return () => { clearTimeout(t); if (spoke) try { window.speechSynthesis.cancel(); } catch (e) {} };
  }, [reading, idx, rate, voiceURI, voices.length]);

  useEffect(() => () => { try { window.speechSynthesis && window.speechSynthesis.cancel(); } catch (e) {} }, []);

  const activeId = reading ? flat[Math.min(idx, N - 1)].id : null;

  function clickSentence(s) {
    if (tool === "highlight") {
      setHl(prev => { const n = new Set(prev); n.has(s.id) ? n.delete(s.id) : n.add(s.id); return n; });
      if (!hl.has(s.id)) toast("Highlighted", "highlight");
    } else {
      setIdx(flat.findIndex(f => f.id === s.id)); setReading(true);
    }
  }
  function addNote() {
    if (!noteDraft.trim()) return;
    const firstHl = [...hl][0];
    const quote = firstHl ? flat.find(f => f.id === firstHl).text : "General note";
    setNotes(n => [{ id: "n" + Date.now(), quote: quote.slice(0, 60), text: noteDraft.trim() }, ...n]);
    setNoteDraft(""); toast("Note saved", "note");
  }

  const speeds = [0.75, 1, 1.25, 1.5];

  return (
    <div className="vh-in" style={{ height: "100%", display: "flex", flexDirection: "column" }}>
      {/* reader top bar */}
      <div className="between" style={{ marginBottom: 16, flexWrap: "wrap", gap: 14 }}>
        <div style={{ display: "flex", alignItems: "center", gap: 14 }}>
          <button className="btn btn-ghost" onClick={back}><Icon name="chevL" size={16} />{backLabel || "Library"}</button>
          <div>
            <h2 style={{ fontSize: 19, fontWeight: 700 }}>{book.title}</h2>
            <div className="dim" style={{ fontSize: 12.5 }}>{book.author}</div>
          </div>
        </div>
        <div style={{ display: "flex", alignItems: "center", gap: 16 }}>
          <div style={{ display: "flex", alignItems: "center", gap: 9 }}>
            <Ring value={progress} size={42} stroke={5} />
            <div><div style={{ fontWeight: 700, fontSize: 13 }}>{progress}%</div><div className="dim" style={{ fontSize: 11 }}>read</div></div>
          </div>
          {action && <button className="btn btn-outline" onClick={action.onClick}><Icon name={action.icon || "book"} size={16} />{action.label}</button>}
          <button className="btn btn-pri" onClick={() => { toast("Chapter marked as complete", "checkCircle"); }}><Icon name="checkCircle" size={16} />Mark complete</button>
        </div>
      </div>

      {/* read-aloud control bar */}
      <div className="card" style={{ padding: "11px 16px", marginBottom: 16, display: "flex", alignItems: "center", gap: 14, flexWrap: "wrap" }}>
        <button className="btn btn-acc" onClick={() => { if (reading) { setReading(false); try { window.speechSynthesis.cancel(); } catch (e) {} } else { setReading(true); } }} style={{ minWidth: 132 }}>
          <Icon name={reading ? "pause" : "volume"} size={17} />{reading ? "Pause read-aloud" : "Read aloud"}
        </button>
        <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
          <span className="dim" style={{ fontSize: 12.5, fontWeight: 600 }}>Speed</span>
          <div className="seg">{speeds.map(s => <button key={s} className={rate === s ? "on" : ""} onClick={() => setRate(s)} style={{ fontSize: 12, padding: "6px 10px" }}>{s}×</button>)}</div>
        </div>
        <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
          <span className="dim" style={{ fontSize: 12.5, fontWeight: 600 }}>Voice</span>
          <select value={voiceURI} onChange={(e) => pickVoice(e.target.value)} title="Pick a read-aloud voice — changing it plays a short sample"
            style={{ maxWidth: 190, fontSize: 12.5, fontWeight: 600, color: "var(--ink-2)", border: "1.5px solid var(--line)", borderRadius: 9, padding: "7px 8px", background: "var(--surface)", fontFamily: "var(--body)", outline: "none", cursor: "pointer" }}>
            <option value="">System default</option>
            {voiceList.map(v => <option key={v.voiceURI} value={v.voiceURI}>{voiceName(v)} · {v.lang}</option>)}
          </select>
        </div>
        <div className="divider" style={{ width: 1, height: 26 }} />
        <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
          <span className="dim" style={{ fontSize: 12.5, fontWeight: 600 }}>Tool</span>
          <div className="seg">
            <button className={tool === "read" ? "on" : ""} onClick={() => setTool("read")} style={{ fontSize: 12, padding: "6px 11px" }}><Icon name="play" size={13} style={{ marginRight: 5 }} />Tap to play</button>
            <button className={tool === "highlight" ? "on" : ""} onClick={() => setTool("highlight")} style={{ fontSize: 12, padding: "6px 11px" }}><Icon name="highlight" size={13} style={{ marginRight: 5 }} />Highlight</button>
          </div>
        </div>
        {reading && <span className="tag accent" style={{ marginLeft: "auto", fontSize: 11 }}><span style={{ width: 7, height: 7, borderRadius: 9, background: "var(--accent)", animation: "vhPulse 1s infinite alternate" }} />Reading aloud</span>}
      </div>

      {/* two-pane */}
      <div style={{ flex: 1, minHeight: 0, display: "grid", gridTemplateColumns: "1fr 320px", gap: 20 }}>
        {/* reading column */}
        <div className="card scroll" style={{ padding: "34px 44px", overflow: "auto" }}>
          <div style={{ maxWidth: 640, margin: "0 auto" }}>
            <div className="eyebrow" style={{ marginBottom: 6 }}>{book.track}</div>
            <h1 style={{ fontSize: 30, fontWeight: 700, marginBottom: 6 }}>{book.uploaded ? book.title : "Chapter 1 — A practical foundation"}</h1>
            <p className="dim" style={{ fontSize: 13.5, marginBottom: 28 }}>{book.author} · est. {book.mins || 14} min</p>
            {chapterData.map((ch, ci) => (
              <div key={ci} style={{ marginBottom: 30 }}>
                <h2 style={{ fontSize: 20, fontWeight: 700, margin: "0 0 14px" }}>{ch.n}. {ch.title}</h2>
                {ch.paras.map((p, pi) => (
                  <p key={pi} style={{ fontSize: 17, lineHeight: 1.75, color: "var(--ink-2)", marginBottom: 16, textWrap: "pretty" }}>
                    {sentences(p).map((s, si) => {
                      const id = ci + "-" + pi + "-" + si;
                      const isHl = hl.has(id), isActive = activeId === id;
                      return (
                        <span key={si} onClick={() => clickSentence({ id })}
                          style={{ cursor: "pointer", borderRadius: 4, padding: "1px 0", transition: "background .2s, color .2s",
                            background: isActive ? "color-mix(in oklab,var(--accent),transparent 55%)" : isHl ? "color-mix(in oklab,var(--vh-peach),transparent 35%)" : "transparent",
                            color: isActive ? "var(--ink)" : undefined,
                            boxShadow: isActive ? "0 0 0 3px color-mix(in oklab,var(--accent),transparent 55%)" : "none" }}>
                          {s + " "}
                        </span>
                      );
                    })}
                  </p>
                ))}
              </div>
            ))}
            <div style={{ display: "flex", justifyContent: "space-between", paddingTop: 18, borderTop: "1px solid var(--line)" }}>
              <button className="btn btn-outline" disabled title="Binnenkort" style={{ opacity:.5, cursor:"not-allowed" }}><Icon name="chevL" size={15} />Previous</button>
              <button className="btn btn-pri" disabled title="Binnenkort" style={{ opacity:.5, cursor:"not-allowed" }}>Next chapter<Icon name="chevR" size={15} /></button>
            </div>
          </div>
        </div>

        {/* side panel */}
        <div className="card" style={{ display: "flex", flexDirection: "column", minHeight: 0, overflow: "hidden" }}>
          <div className="seg" style={{ margin: 14, marginBottom: 0 }}>
            <button className={tab === "notes" ? "on" : ""} onClick={() => setTab("notes")} style={{ flex: 1, justifyContent: "center" }}><Icon name="note" size={14} style={{ marginRight: 6 }} />Notes</button>
            <button className={tab === "hl" ? "on" : ""} onClick={() => setTab("hl")} style={{ flex: 1, justifyContent: "center" }}><Icon name="highlight" size={14} style={{ marginRight: 6 }} />Highlights{hl.size ? " (" + hl.size + ")" : ""}</button>
          </div>

          {tab === "notes" && (
            <div style={{ display: "flex", flexDirection: "column", minHeight: 0, flex: 1 }}>
              <div style={{ padding: 14 }}>
                <textarea value={noteDraft} onChange={e => setNoteDraft(e.target.value)} placeholder="Write a note… (links to your latest highlight)" rows={3}
                  style={{ width: "100%", resize: "none", border: "1.5px solid var(--line)", borderRadius: 11, padding: 11, fontSize: 13.5, outline: "none", background: "var(--surface-2)", color: "var(--ink)" }} />
                <button className="btn btn-pri" style={{ width: "100%", marginTop: 9 }} onClick={addNote}><Icon name="plus" size={16} />Add note</button>
              </div>
              <div className="scroll" style={{ flex: 1, overflow: "auto", padding: "0 14px 14px", display: "flex", flexDirection: "column", gap: 10 }}>
                {notes.map(n => (
                  <div key={n.id} style={{ padding: 13, borderRadius: 12, background: "var(--surface-2)", border: "1px solid var(--line)" }}>
                    <div style={{ display: "flex", gap: 8, marginBottom: 7 }}>
                      <div style={{ width: 3, borderRadius: 9, background: "var(--accent)", flex: "none" }} />
                      <span className="dim" style={{ fontSize: 12, fontStyle: "italic", lineHeight: 1.4 }}>"{n.quote}"</span>
                    </div>
                    <p style={{ fontSize: 13.5, lineHeight: 1.5 }}>{n.text}</p>
                  </div>
                ))}
              </div>
            </div>
          )}

          {tab === "hl" && (
            <div className="scroll" style={{ flex: 1, overflow: "auto", padding: 14, display: "flex", flexDirection: "column", gap: 10 }}>
              {hl.size === 0 && (
                <div style={{ textAlign: "center", padding: "30px 16px", color: "var(--ink-3)" }}>
                  <Icon name="highlight" size={30} style={{ opacity: .5 }} />
                  <p style={{ fontSize: 13.5, marginTop: 10 }}>Switch to the <b>Highlight</b> tool and tap any sentence to save it here.</p>
                </div>
              )}
              {[...hl].map(id => {
                const s = flat.find(f => f.id === id);
                return (
                  <div key={id} style={{ padding: 13, borderRadius: 12, background: "color-mix(in oklab,var(--vh-peach),transparent 60%)", border: "1px solid color-mix(in oklab,var(--vh-orange),transparent 70%)", display: "flex", gap: 9 }}>
                    <Icon name="highlight" size={16} style={{ color: "var(--vh-orange)", flex: "none", marginTop: 2 }} />
                    <span style={{ fontSize: 13.5, lineHeight: 1.5 }}>{s ? s.text : ""}</span>
                  </div>
                );
              })}
            </div>
          )}
        </div>
      </div>
    </div>
  );
}

/* Find the best edition of a book — the educator-uploaded one (BookStore) first, then the catalogue. */
async function resolveLibraryBook(initial) {
  let b = null;
  try {
    if (window.BookStore) {
      const all = (await window.BookStore.list()) || [];
      b = all.filter((x) => x.id === initial.id || (initial.track && x.track === initial.track)).
      sort((a, c) => (c.created || 0) - (a.created || 0))[0] || null;
    }
  } catch (e) {}
  return b || BOOKS.find((x) => x.id === initial.id) || null;
}

/* Which course does a book belong to? (course deep-links) */
function bookCourseId(book) {
  if (!book) return null;
  return /ipma/i.test((book.track || "") + " " + (book.title || "")) ? "ipma" : null;
}

/* initialBook (optional) — pre-select a book, used when a course page deep-links into the Reader.
   Prefers the educator-uploaded edition for the same course (BookStore), then the catalogue entry.
   "Back" always returns to the full Library — the same view you get entering via the menu. */
function ReaderScreen({ t, toast, initialBook, goToCourse }) {
  const [book, setBook] = useState(null);
  const [resolving, setResolving] = useState(!!initialBook);
  useEffect(() => {
    if (!initialBook) return;
    let live = true;
    (async () => {
      const b = await resolveLibraryBook(initialBook);
      if (live) {if (b) setBook(b);setResolving(false);}
    })();
    return () => {live = false;};
  }, [initialBook]);
  if (resolving) return null;
  const courseId = book ? bookCourseId(book) : null;
  return book
    ? <Reader book={book} back={() => setBook(null)} toast={toast}
        action={goToCourse && courseId ? { label: "Go to course", icon: "graduation", onClick: () => goToCourse(courseId) } : null} />
    : <Library openBook={setBook} />;
}

Object.assign(window, { ReaderScreen, Reader, resolveLibraryBook });
