// ── CHT text normalisation — runs once before React renders ──────────────────
(function normaliseDays() {
  const RULES = [
    [/義大利/g,       "意大利"],
    [/裡/g,           "裏"],
    [/著(?!作|名)/g,  "着"],
  ];
  function fix(s) {
    if (typeof s !== "string") return s;
    return RULES.reduce((t, [pat, rep]) => t.replace(pat, rep), s);
  }
  function walk(obj) {
    if (!obj || typeof obj !== "object") return;
    Object.keys(obj).forEach(k => {
      if (typeof obj[k] === "string") obj[k] = fix(obj[k]);
      else walk(obj[k]);
    });
  }
  (window.DAYS || []).forEach(walk);
})();

// App root: handles routing, language state, search state

function App() {
  // Read view from hash for prev/next nav. Default = archive.
  const [view, setView]   = React.useState(() => parseHash().view);
  const [openIso, setOpenIso] = React.useState(() => parseHash().iso);
  const [lang, setLang]   = React.useState(() => localStorage.getItem("adm:lang") || "cht");
  const [query, setQuery] = React.useState("");

  function parseHash() {
    const h = window.location.hash.replace(/^#/, "");
    if (h.startsWith("entry/")) return { view: "entry", iso: h.slice("entry/".length) };
    if (h === "about") return { view: "about", iso: null };
    if (h === "admin") return { view: "admin", iso: null };
    if (h === "disclaimer") return { view: "disclaimer", iso: null };
    return { view: "archive", iso: null };
  }

  // Sync body class for language fonts
  React.useEffect(() => {
    document.body.classList.toggle("lang-eng", lang === "eng");
    localStorage.setItem("adm:lang", lang);
    document.documentElement.lang = lang === "cht" ? "zh-Hant" : "en";
  }, [lang]);

  // Hash sync
  React.useEffect(() => {
    let h = "";
    if (view === "entry" && openIso) h = "entry/" + openIso;
    else if (view === "about") h = "about";
    else if (view === "admin") h = "admin";
    else if (view === "disclaimer") h = "disclaimer";
    if (("#" + h) !== window.location.hash) window.location.hash = h;
  }, [view, openIso]);

  React.useEffect(() => {
    const onHash = () => {
      const p = parseHash();
      setView(p.view);
      setOpenIso(p.iso);
    };
    window.addEventListener("hashchange", onHash);
    return () => window.removeEventListener("hashchange", onHash);
  }, []);

  // Nav helpers
  function navTo(v) {
    if (v === "archive") { setView("archive"); setOpenIso(null); }
    else if (v === "about") setView("about");
    else if (v === "admin") setView("admin");
    else if (v === "disclaimer") setView("disclaimer");
    window.scrollTo({ top: 0, behavior: "instant" });
  }
  function openEntry(iso) {
    setView("entry");
    setOpenIso(iso);
  }

  const [showTop, setShowTop] = React.useState(false);
  React.useEffect(() => {
    const onScroll = () => setShowTop(window.scrollY > 300);
    window.addEventListener("scroll", onScroll, { passive: true });
    return () => window.removeEventListener("scroll", onScroll);
  }, []);

  return (
    <>
      <TopBar lang={lang} setLang={setLang} query={query} setQuery={setQuery} onNav={navTo} view={view} />
      {view === "archive" && <ArchiveView lang={lang} query={query} onOpen={openEntry} />}
      {view === "entry"   && <EntryView   lang={lang} iso={openIso} onNav={navTo} onOpen={openEntry} />}
      {view === "about"      && <AboutView      lang={lang} />}
      {view === "disclaimer" && <DisclaimerView lang={lang} onNav={navTo} />}
      {view === "admin"   && <AdminView    lang={lang} />}
      <BBFoot lang={lang} />
      {showTop && (
        <button className="scroll-top-btn" onClick={() => window.scrollTo({ top: 0, behavior: "smooth" })} aria-label="Back to top" data-tooltip={lang === "cht" ? "返回頂部" : "Back to Top"}>
          ↑
        </button>
      )}
    </>
  );
}

ReactDOM.createRoot(document.getElementById("root")).render(<App />);
