/* global BOOK */
(function () {
  const STORAGE_KEY = "sd_book_state_v1";

  function $(id) {
    return document.getElementById(id);
  }

  function safeParse(json, fallback) {
    try {
      return JSON.parse(json);
    } catch {
      return fallback;
    }
  }

  function clamp(n, min, max) {
    return Math.max(min, Math.min(max, n));
  }

  function normalize(str) {
    return (str || "").toString().trim().toLowerCase();
  }

  const tocEl = $("bookToc");
  const searchEl = $("bookSearch");
  const titleEl = $("bookTitle");
  const subtitleEl = $("bookSubtitle");
  const metaEl = $("bookMeta");
  const bodyEl = $("bookBody");
  const hintEl = $("bookHint");
  const prevBtn = $("prevBtn");
  const nextBtn = $("nextBtn");
  const progressBarEl = $("bookProgressBar");
  const tocOpenBtn = $("tocOpenBtn");
  const tocCloseBtn = $("tocCloseBtn");
  const sidebarEl = document.querySelector(".book-sidebar");
  const themeBtn = $("themeBtn");
  const fontDecBtn = $("fontDecBtn");
  const fontIncBtn = $("fontIncBtn");

  if (!window.BOOK || !BOOK.groups) {
    if (titleEl) titleEl.textContent = "Book data not found";
    if (bodyEl) bodyEl.innerHTML = "<p>Missing <code>js/book-data.js</code> content.</p>";
    return;
  }

  const flatChapters = [];
  for (const group of BOOK.groups) {
    for (const ch of group.chapters) {
      flatChapters.push({
        groupId: group.id,
        groupTitle: group.title,
        ...ch,
      });
    }
  }

  const defaultState = {
    activeChapterId: flatChapters[0]?.id || null,
    dark: false,
    fontSize: 17,
  };

  const saved = safeParse(localStorage.getItem(STORAGE_KEY) || "null", null) || {};
  const state = {
    ...defaultState,
    ...saved,
    fontSize: clamp(Number(saved.fontSize ?? defaultState.fontSize), 14, 22),
  };

  function persist() {
    localStorage.setItem(
      STORAGE_KEY,
      JSON.stringify({
        activeChapterId: state.activeChapterId,
        dark: state.dark,
        fontSize: state.fontSize,
      })
    );
  }

  function setTheme(dark) {
    state.dark = !!dark;
    document.body.classList.toggle("book-dark", state.dark);
    const icon = themeBtn?.querySelector("i");
    if (icon) {
      icon.classList.toggle("fa-moon", !state.dark);
      icon.classList.toggle("fa-sun", state.dark);
    }
    persist();
  }

  function setFontSize(px) {
    state.fontSize = clamp(px, 14, 22);
    document.documentElement.style.setProperty("--book-font-size", `${state.fontSize}px`);
    persist();
  }

  function getChapterIndex(id) {
    return flatChapters.findIndex((c) => c.id === id);
  }

  function setActiveChapter(id, { scrollTop = true, closeTocMobile = true } = {}) {
    const exists = flatChapters.some((c) => c.id === id);
    state.activeChapterId = exists ? id : defaultState.activeChapterId;
    persist();
    renderReader();
    updateTocActive();
    if (scrollTop) {
      window.scrollTo({ top: 0, behavior: "smooth" });
    }
    if (closeTocMobile && sidebarEl?.classList.contains("is-open")) {
      sidebarEl.classList.remove("is-open");
    }
  }

  function updateTocActive() {
    tocEl?.querySelectorAll("[data-chapter-id]").forEach((a) => {
      const isActive = a.getAttribute("data-chapter-id") === state.activeChapterId;
      a.classList.toggle("is-active", isActive);
      a.setAttribute("aria-current", isActive ? "page" : "false");
    });
  }

  function renderToc(filter = "") {
    if (!tocEl) return;
    const q = normalize(filter);

    const groupsHtml = BOOK.groups
      .map((group) => {
        const items = group.chapters
          .filter((ch) => {
            if (!q) return true;
            const blob = normalize(`${ch.title} ${ch.description || ""} ${group.title}`);
            return blob.includes(q);
          })
          .map((ch) => {
            return `
              <a href="#${ch.id}" class="book-toc__item" data-chapter-id="${ch.id}">
                <div class="book-toc__title">${ch.title}</div>
                <p class="book-toc__desc">${ch.description || ""}</p>
              </a>
            `;
          })
          .join("");

        if (!items) return "";

        return `
          <div class="book-toc__group">
            <div class="book-toc__heading">${group.title}</div>
            <div class="book-toc__items">${items}</div>
          </div>
        `;
      })
      .join("");

    tocEl.innerHTML = groupsHtml || `<div class="text-muted small px-2">No chapters match your search.</div>`;

    tocEl.querySelectorAll("[data-chapter-id]").forEach((a) => {
      a.addEventListener("click", (e) => {
        e.preventDefault();
        setActiveChapter(a.getAttribute("data-chapter-id"));
      });
    });

    updateTocActive();
  }

  function renderReader() {
    const idx = getChapterIndex(state.activeChapterId);
    const chapter = flatChapters[idx] || flatChapters[0];
    if (!chapter) return;

    if (metaEl) metaEl.textContent = `${BOOK.title} • ${chapter.groupTitle}`;
    if (titleEl) titleEl.textContent = chapter.title;
    if (subtitleEl) subtitleEl.textContent = chapter.description || BOOK.subtitle || "";
    if (bodyEl) bodyEl.innerHTML = chapter.content || "<p>No content.</p>";

    if (hintEl) {
      const total = flatChapters.length;
      hintEl.textContent = `Chapter ${idx + 1} of ${total}${chapter.estimatedMinutes ? ` • ~${chapter.estimatedMinutes} min` : ""}`;
    }

    const hasPrev = idx > 0;
    const hasNext = idx < flatChapters.length - 1;
    if (prevBtn) prevBtn.disabled = !hasPrev;
    if (nextBtn) nextBtn.disabled = !hasNext;
  }

  function goPrev() {
    const idx = getChapterIndex(state.activeChapterId);
    if (idx > 0) setActiveChapter(flatChapters[idx - 1].id);
  }

  function goNext() {
    const idx = getChapterIndex(state.activeChapterId);
    if (idx >= 0 && idx < flatChapters.length - 1) setActiveChapter(flatChapters[idx + 1].id);
  }

  function updateProgress() {
    if (!progressBarEl) return;
    const scrollTop = window.scrollY || document.documentElement.scrollTop || 0;
    const docHeight = document.documentElement.scrollHeight - window.innerHeight;
    const pct = docHeight > 0 ? (scrollTop / docHeight) * 100 : 0;
    progressBarEl.style.width = `${clamp(pct, 0, 100)}%`;
  }

  function openToc() {
    sidebarEl?.classList.add("is-open");
  }

  function closeToc() {
    sidebarEl?.classList.remove("is-open");
  }

  // Wire events
  prevBtn?.addEventListener("click", goPrev);
  nextBtn?.addEventListener("click", goNext);
  tocOpenBtn?.addEventListener("click", openToc);
  tocCloseBtn?.addEventListener("click", closeToc);

  searchEl?.addEventListener("input", () => {
    renderToc(searchEl.value);
  });

  themeBtn?.addEventListener("click", () => setTheme(!state.dark));
  fontDecBtn?.addEventListener("click", () => setFontSize(state.fontSize - 1));
  fontIncBtn?.addEventListener("click", () => setFontSize(state.fontSize + 1));

  window.addEventListener("scroll", updateProgress, { passive: true });
  window.addEventListener("resize", updateProgress);

  document.addEventListener("keydown", (e) => {
    if (e.target && (e.target.tagName === "INPUT" || e.target.tagName === "TEXTAREA")) return;
    if (e.key === "ArrowLeft") goPrev();
    if (e.key === "ArrowRight") goNext();
    if (e.key === "Escape") closeToc();
    if (e.key === "/") {
      e.preventDefault();
      searchEl?.focus();
    }
  });

  // Initial render
  setTheme(state.dark);
  setFontSize(state.fontSize);
  renderToc("");

  // Choose chapter: URL hash > saved > first
  const hashId = (location.hash || "").replace("#", "");
  const startId = flatChapters.some((c) => c.id === hashId) ? hashId : state.activeChapterId;
  setActiveChapter(startId, { scrollTop: false, closeTocMobile: false });
  updateProgress();
})();

