// router.jsx — tiny client-side router for the combined single-page Motomelli
// site. Clean paths ("/", "/about", "/compare", ...) are driven by the History
// API. A single delegated click handler turns same-origin <a> clicks into
// in-app navigations, and it also transparently maps the *old* file-based
// links (About.html, product.html?id=x, Motomelli.html#anchor, ...) onto the
// new routes — so source that still points at .html keeps working.
//
// Exposes: window.mmNavigate, window.useRoute, window.mmNormalizePath
//
// Must load before app.jsx.

(function () {
  // Map a (lower-cased) filename to its clean route. Anything not listed is
  // assumed to already be a clean path.
  const FILE_TO_ROUTE = {
    "motomelli.html": "/",
    "index.html": "/",
    "compare.html": "/compare",
    "about.html": "/about",
    "contact.html": "/contact",
    "hoodies.html": "/hoodies",
    "privacy.html": "/privacy",
    "terms.html": "/terms",
    "cookies.html": "/cookies",
    "product.html": "/product",
    "": "/",
  };

  function normalizePath(pathname) {
    if (!pathname) return "/";
    const file = pathname.substring(pathname.lastIndexOf("/") + 1).toLowerCase();
    if (Object.prototype.hasOwnProperty.call(FILE_TO_ROUTE, file)) {
      return FILE_TO_ROUTE[file];
    }
    // strip a trailing slash (except the root)
    if (pathname.length > 1 && pathname.endsWith("/")) pathname = pathname.slice(0, -1);
    return pathname || "/";
  }

  // Parse an href into an in-app route { path, search, hash }, or null if it is
  // not an internal navigation (external host, mailto:, tel:, new tab, etc.).
  function parseHref(href) {
    if (href == null) return null;
    const raw = String(href).trim();
    if (!raw) return null;
    if (/^(mailto:|tel:|javascript:)/i.test(raw)) return null;

    // Pure in-page anchor — scroll within the current route.
    if (raw.charAt(0) === "#") {
      return { path: normalizePath(window.location.pathname), search: "", hash: raw };
    }

    let url;
    try {
      url = new URL(raw, window.location.origin);
    } catch (e) {
      return null;
    }
    if (url.origin !== window.location.origin) return null; // external

    return { path: normalizePath(url.pathname), search: url.search, hash: url.hash };
  }

  // Scroll to an element id (from a hash), retrying for a few frames while the
  // target route renders in.
  function scrollToHash(hash) {
    const id = decodeURIComponent((hash || "").replace(/^#/, ""));
    if (!id) { window.scrollTo(0, 0); return; }
    let tries = 0;
    const tick = () => {
      const el = document.getElementById(id);
      if (el) { el.scrollIntoView({ behavior: "instant", block: "start" }); return; }
      if (++tries < 30) requestAnimationFrame(tick);
    };
    requestAnimationFrame(tick);
  }

  function navigate(target, opts) {
    opts = opts || {};
    const route = typeof target === "string" ? parseHref(target) : target;
    if (!route) return;
    const prevPath = normalizePath(window.location.pathname);
    const url = route.path + (route.search || "") + (route.hash || "");

    if (opts.replace) history.replaceState({}, "", url);
    else history.pushState({}, "", url);

    // Notify subscribers (useRoute) that the location changed.
    window.dispatchEvent(new Event("mm:route"));

    // Scroll: to the hash target if present, otherwise to the top when the
    // page (path) actually changed.
    if (route.hash) scrollToHash(route.hash);
    else if (route.path !== prevPath) window.scrollTo(0, 0);
  }

  // Delegated link interception.
  document.addEventListener("click", function (e) {
    if (e.defaultPrevented) return;
    if (e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return;
    const a = e.target.closest && e.target.closest("a");
    if (!a) return;
    if (a.target && a.target !== "_self") return;        // new tab / frame
    if (a.hasAttribute("download")) return;
    if (a.getAttribute("rel") === "external") return;
    const href = a.getAttribute("href");
    const route = parseHref(href);
    if (!route) return;                                   // external/mailto → browser
    e.preventDefault();
    navigate(route);
  });

  // Keep React in sync with browser back/forward.
  if ("scrollRestoration" in window.history) {
    window.history.scrollRestoration = "manual";
  }

  // React hook: returns the current normalized route and re-renders on change.
  function useRoute() {
    const read = () => ({
      path: normalizePath(window.location.pathname),
      search: window.location.search,
      hash: window.location.hash,
    });
    const [route, setRoute] = React.useState(read);
    React.useEffect(() => {
      const onChange = () => setRoute(read());
      window.addEventListener("popstate", onChange);
      window.addEventListener("mm:route", onChange);
      return () => {
        window.removeEventListener("popstate", onChange);
        window.removeEventListener("mm:route", onChange);
      };
    }, []);
    return route;
  }

  Object.assign(window, {
    mmNavigate: navigate,
    mmNormalizePath: normalizePath,
    mmScrollToHash: scrollToHash,
    useRoute,
  });
})();
