// Dictionary Word Wall — same neon cloud as the book Word Wall, but the
// nodes are the 550 dictionary headwords, sized by how heavily the books in
// the current language actually use each term. Clicking a term opens the
// existing popover with its dictionary definition.
//
// Data source: window.__dictWallData[lang] = [["term-id", "Term Display", count], ...]
// (populated by words/dictwall-<lang>.js script tags)
//
// This file reuses the .wwall-* CSS and the .wwall-popover modal from the
// book Word Wall — only the data source and the click target differ.

(function () {
  function L() { return (window.__langData && window.__langData[(window.i18n && window.i18n.getLang()) || "en"]) || {}; }
  function t(key, fallback) { return L()[key] != null ? L()[key] : (fallback != null ? fallback : key); }

  function escapeHTML(s) {
    return String(s).replace(/[&<>"']/g, c => ({"&": "&amp;","<": "&lt;",">": "&gt;","\"": "&quot;","'": "&#39;"}[c]));
  }

  function currentLang() { return (window.i18n && window.i18n.getLang()) || "en"; }

  const SORT_STORAGE_KEY = "wuys-dwall-sort";
  const REVERSE_STORAGE_KEY = "wuys-dwall-reverse";

  function currentSortMode() {
    const sel = document.getElementById("dwall-sort");
    return (sel && sel.value) || "freq";
  }
  function currentReverse() {
    try { return localStorage.getItem(REVERSE_STORAGE_KEY) === "1"; } catch (e) { return false; }
  }
  function persistReverse(rev) {
    try { localStorage.setItem(REVERSE_STORAGE_KEY, rev ? "1" : "0"); } catch (e) {}
  }
  function restoreSortMode() {
    const sel = document.getElementById("dwall-sort");
    if (!sel) return;
    try {
      const saved = localStorage.getItem(SORT_STORAGE_KEY);
      if (saved && Array.from(sel.options).some(o => o.value === saved)) {
        sel.value = saved;
      }
    } catch (e) {}
  }
  function persistSortMode(mode) {
    try { localStorage.setItem(SORT_STORAGE_KEY, mode); } catch (e) {}
  }

  function loadTerms(lang) {
    const arr = (window.__dictWallData && window.__dictWallData[lang]) || null;
    if (!arr) {
      console.warn("dictwall: no data loaded for lang", lang);
      return null;
    }
    return arr;
  }

  function makeSizer(triples) {
    if (!triples || triples.length === 0) return () => 14;
    // Use sqrt scaling on (count + 1) so zero-count entries still get a non-zero
    // base size (12px) and the wall remains a complete index of the dictionary.
    const counts = triples.map(t => t[2] + 1);
    const min = Math.min.apply(null, counts);
    const max = Math.max.apply(null, counts);
    const MIN_PX = 12;
    const MAX_PX = 64;
    if (max === min) return () => (MIN_PX + MAX_PX) / 2;
    return function (c) {
      const t = (Math.sqrt(c + 1) - Math.sqrt(min)) / (Math.sqrt(max) - Math.sqrt(min));
      return MIN_PX + t * (MAX_PX - MIN_PX);
    };
  }

  function tintFor(i) {
    const tones = ["wwall-t1", "wwall-t2", "wwall-t3", "wwall-t4", "wwall-t5"];
    return tones[i % tones.length];
  }

  function applySort(triples, mode, lang, reverse) {
    const arr = triples.slice();
    switch (mode) {
      case "alpha": {
        const collator = new Intl.Collator(lang || "en", { sensitivity: "base" });
        arr.sort((a, b) => collator.compare(a[1], b[1]));
        if (reverse) arr.reverse();
        return arr;
      }
      case "length":
        arr.sort((a, b) => b[1].length - a[1].length || b[2] - a[2]);
        if (reverse) arr.reverse();
        return arr;
      case "shuffle": {
        for (let i = arr.length - 1; i > 0; i--) {
          const j = Math.floor(Math.random() * (i + 1));
          const tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp;
        }
        return arr;
      }
      case "freq":
      default:
        // Already sorted by count desc upstream.
        if (reverse) arr.reverse();
        return arr;
    }
  }

  function renderCloud(host, triples) {
    if (!triples || triples.length === 0) {
      host.innerHTML = '<p class="wwall-empty">' + escapeHTML(t("page.library.ww_empty", "No words available for this selection.")) + '</p>';
      return;
    }
    const sizer = makeSizer(triples);
    const mode = currentSortMode();
    const reverse = mode !== "shuffle" && currentReverse();
    const visualOrder = applySort(triples, mode, currentLang(), reverse);

    const STAGGER_MS = 8;
    const STAGGER_CAP = 1800;
    host.innerHTML = visualOrder.map(([id, display, count], i) => {
      const size = sizer(count);
      const tint = tintFor(i);
      const bloomDelay = Math.min(i * STAGGER_MS, STAGGER_CAP);
      const pulseDur = (3 + Math.random() * 3.5).toFixed(2);
      const pulsePhase = -(Math.random() * parseFloat(pulseDur)).toFixed(2);
      const style = 'font-size:' + size.toFixed(1) + 'px;'
        + '--bloom-delay:' + bloomDelay + 'ms;'
        + '--pulse-dur:' + pulseDur + 's;'
        + '--pulse-delay:' + pulsePhase + 's';
      const titleAttr = count > 0
        ? escapeHTML(display) + ' — ' + count
        : escapeHTML(display);
      return '<span class="wwall-word ' + tint + '" '
        + 'role="button" tabindex="0"'
        + ' data-dict-term="' + escapeHTML(id) + '"'
        + ' data-dict-display="' + escapeHTML(display) + '"'
        + ' data-tint="' + tint + '"'
        + ' style="' + style + '"'
        + ' title="' + titleAttr + '">'
        + escapeHTML(display) + '</span>';
    }).join(" ");
  }

  function refreshCloud() {
    const host = document.getElementById("dwall-cloud");
    if (!host) return;
    const lang = currentLang();
    const triples = loadTerms(lang);
    renderCloud(host, triples);
  }

  // Popover rendering — opens the same modal element the book wall uses.
  const TINT_ACCENTS = {
    "wwall-t1": { neon: "#ff2db5", glow: "rgba(255, 45, 181, 0.55)" },
    "wwall-t2": { neon: "#00f0ff", glow: "rgba(0, 240, 255, 0.55)" },
    "wwall-t3": { neon: "#b8ff3a", glow: "rgba(184, 255, 58, 0.50)" },
    "wwall-t4": { neon: "#c060ff", glow: "rgba(192, 96, 255, 0.55)" },
    "wwall-t5": { neon: "#ffa831", glow: "rgba(255, 168, 49, 0.50)" }
  };

  function lookupTermDef(termId, lang) {
    const bag = (window.__langData && window.__langData[lang]) || {};
    const term = bag["dict.term." + termId];
    const def = bag["dict.def." + termId];
    if (term && def) return { term, def };
    return null;
  }

  function openDictPopover(termId, displayText, tint) {
    const pop = document.getElementById("wwall-popover");
    const title = document.getElementById("wwall-popover-title");
    const body = document.getElementById("wwall-popover-body");
    if (!pop || !title || !body) return;

    const accent = TINT_ACCENTS[tint] || TINT_ACCENTS["wwall-t4"];
    pop.style.setProperty("--accent-neon", accent.neon);
    pop.style.setProperty("--accent-neon-glow", accent.glow);

    const entry = lookupTermDef(termId, currentLang());
    title.textContent = entry ? entry.term : displayText;

    const parts = [];
    if (entry) {
      parts.push(
        '<div class="wwp-section">'
        + '<span class="wwp-section-label">' + escapeHTML(t("page.library.ww_definition", "Definition")) + '</span>'
        + '<div class="wwp-def">' + entry.def + '</div>'
        + '</div>'
      );
    } else {
      parts.push('<p class="wwp-empty">' + escapeHTML(t("page.library.ww_no_data", "No deeper data for this word yet.")) + '</p>');
    }
    body.innerHTML = parts.join("");

    pop.hidden = false;
    document.body.style.overflow = "hidden";
  }

  function isDictWallActive() {
    const v = document.querySelector('[data-view="dictwall"]');
    return v && v.classList.contains("active");
  }

  function bindControls() {
    document.body.addEventListener("change", (ev) => {
      const id = ev.target && ev.target.id;
      if (id === "dwall-sort") {
        persistSortMode(ev.target.value);
        updateActionButton();
        if (isDictWallActive()) refreshCloud();
      }
    });

    document.body.addEventListener("click", (ev) => {
      // Click on a dict-term node → open definition popover
      const term = ev.target.closest("[data-dict-term]");
      if (term) {
        openDictPopover(term.dataset.dictTerm, term.dataset.dictDisplay, term.dataset.tint || "wwall-t1");
        return;
      }
      // Action button (dwall-action) — same reshuffle/reverse pattern
      const btn = ev.target.closest("#dwall-action");
      if (btn) {
        const mode = currentSortMode();
        if (mode === "shuffle") {
          btn.classList.remove("spinning");
          void btn.offsetWidth;
          btn.classList.add("spinning");
          if (isDictWallActive()) refreshCloud();
        } else {
          const rev = !currentReverse();
          persistReverse(rev);
          updateActionButton();
          if (isDictWallActive()) refreshCloud();
        }
      }
    });

    document.body.addEventListener("keydown", (ev) => {
      if ((ev.key === "Enter" || ev.key === " ") && document.activeElement) {
        const term = document.activeElement.closest("[data-dict-term]");
        if (term) {
          ev.preventDefault();
          openDictPopover(term.dataset.dictTerm, term.dataset.dictDisplay, term.dataset.tint || "wwall-t1");
        }
      }
    });
  }

  function updateActionButton() {
    const btn = document.getElementById("dwall-action");
    const icon = document.getElementById("dwall-action-icon");
    if (!btn || !icon) return;
    const mode = currentSortMode();
    if (mode === "shuffle") {
      icon.textContent = "↻";
      btn.classList.remove("reversed");
      btn.setAttribute("aria-label", t("page.library.ww_reshuffle", "Re-shuffle"));
      btn.setAttribute("title", t("page.library.ww_reshuffle", "Re-shuffle"));
    } else {
      icon.textContent = "↓";
      const rev = currentReverse();
      btn.classList.toggle("reversed", rev);
      btn.setAttribute("aria-label", t("page.library.ww_reverse", "Reverse order"));
      btn.setAttribute("title", t("page.library.ww_reverse", "Reverse order"));
    }
  }

  function watchNav() {
    window.addEventListener("hashchange", () => {
      if (isDictWallActive()) setTimeout(refreshCloud, 0);
    });
    document.body.addEventListener("click", (ev) => {
      const link = ev.target.closest('.nav-link[data-view="dictwall"]');
      if (link) setTimeout(refreshCloud, 0);
    });
  }

  function onLangChange() {
    updateActionButton();
    if (isDictWallActive()) refreshCloud();
  }

  function init() {
    restoreSortMode();
    updateActionButton();
    bindControls();
    watchNav();
    window.addEventListener("langchange", onLangChange);
    if (isDictWallActive()) refreshCloud();
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", init);
  } else {
    init();
  }
})();
