// router.jsx — vanilla-React client router for Top Natural Tips.
//
// No external dependency. Clean URLs via the History API. Loaded BEFORE the
// other JSX in index.html so every component can reference these helpers.
//
// Route spec shape: { view, section?, postSlug?, podcastSlug?, productHandle?, query? }
//   view ∈ 'home' | 'archive' | 'section' | 'podcast' | 'shop' | 'about'
//          | 'post' | 'product' | 'legal' | 'notfound'
//
// ROUTES is the single source of truth — both parseRoute() (path → spec) and
// buildPath() (spec → path) derive from it, so the two directions can never
// drift apart.

const ROUTES = [
  { view: 'home',     path: '/' },
  { view: 'archive',  path: '/diario' },
  { view: 'section',  path: '/salud',      section: 'Health' },
  { view: 'section',  path: '/belleza',    section: 'Beauty' },
  { view: 'section',  path: '/nutricion',  section: 'Nutrition' },
  { view: 'section',  path: '/ejercicio',  section: 'Exercise' },
  { view: 'podcast',  path: '/podcast' },
  { view: 'podcast',  path: '/podcast/:podcastSlug' },
  { view: 'shop',     path: '/tienda' },
  { view: 'about',    path: '/sobre' },
  { view: 'post',     path: '/articulo/:postSlug' },
  { view: 'product',  path: '/producto/:productHandle' },
  { view: 'legal',    path: '/terminos',          doc: 'terms' },
  { view: 'legal',    path: '/privacidad',        doc: 'privacy' },
  { view: 'legal',    path: '/terminos-de-venta', doc: 'sale' },
  { view: 'legal',    path: '/aviso-medico',      doc: 'medical' },
];

const ROUTER_EVENT = 'router:change';

// ---- path <-> spec ---------------------------------------------------------

// Collapse a pathname to a canonical form: decoded, no trailing slash (except
// root). Query/hash are handled separately by the caller.
function normalizePath(pathname) {
  let p = pathname || '/';
  try { p = decodeURIComponent(p); } catch (e) {}
  if (p.length > 1) p = p.replace(/\/+$/, '');
  return p || '/';
}

// Match a path against one ROUTE pattern. Returns a params object, or null.
function matchPattern(pattern, path) {
  const pat = pattern.split('/').filter(Boolean);
  const seg = path.split('/').filter(Boolean);
  if (pat.length !== seg.length) return null;
  const params = {};
  for (let i = 0; i < pat.length; i++) {
    if (pat[i][0] === ':') params[pat[i].slice(1)] = seg[i];
    else if (pat[i] !== seg[i]) return null;
  }
  return params;
}

// Parse the current pathname (+ optional search string) into a route spec.
// Unknown path → { view: 'notfound' }.
function parseRoute(pathname, search) {
  const path = normalizePath(pathname);
  let query = '';
  try {
    const raw = (search != null) ? search
      : (typeof location !== 'undefined' ? location.search : '');
    query = new URLSearchParams(raw).get('q') || '';
  } catch (e) {}

  for (const r of ROUTES) {
    const params = matchPattern(r.path, path);
    if (!params) continue;
    const spec = { view: r.view };
    if (r.section) spec.section = r.section;
    if (r.doc) spec.doc = r.doc;
    if (params.postSlug) spec.postSlug = params.postSlug;
    if (params.podcastSlug) spec.podcastSlug = params.podcastSlug;
    if (params.productHandle) spec.productHandle = params.productHandle;
    if (query) spec.query = query;
    return spec;
  }
  return query ? { view: 'notfound', query } : { view: 'notfound' };
}

// Build a pathname from a route spec. Prefers a parameterized route when the
// spec supplies the matching param (so /podcast/:slug wins over /podcast).
function buildPath(spec) {
  if (!spec || !spec.view) return '/';
  const candidates = ROUTES.filter(r =>
    r.view === spec.view
    && (r.view !== 'section' || r.section === spec.section)
    && (r.view !== 'legal'   || r.doc === spec.doc));

  for (const r of candidates) {
    if (r.path.indexOf(':postSlug') !== -1 && spec.postSlug)
      return r.path.replace(':postSlug', encodeURIComponent(spec.postSlug));
    if (r.path.indexOf(':podcastSlug') !== -1 && spec.podcastSlug)
      return r.path.replace(':podcastSlug', encodeURIComponent(spec.podcastSlug));
    if (r.path.indexOf(':productHandle') !== -1 && spec.productHandle)
      return r.path.replace(':productHandle', encodeURIComponent(spec.productHandle));
  }
  for (const r of candidates) {
    if (r.path.indexOf(':') === -1) return r.path;
  }
  return '/';
}

// Imperative href helper for plain <a href={hrefFor(spec)}>.
function hrefFor(spec) {
  return (typeof spec === 'string') ? spec : buildPath(spec);
}

// Map a header/strip nav key (Health/Beauty/Nutrition/Exercise/Shop/Podcasts)
// to a route spec. Shared by Header, CategoryStrip, Search, Footer.
function navSpecForKey(key) {
  if (key === 'Shop') return { view: 'shop' };
  if (key === 'Podcasts') return { view: 'podcast' };
  return { view: 'section', section: key };
}
function navHref(key) {
  return buildPath(navSpecForKey(key));
}

// ---- navigation ------------------------------------------------------------

// Fire pushState (or replaceState) and notify subscribers. Accepts a spec
// object or a raw path string.
function navigate(spec, opts) {
  opts = opts || {};
  let url = (typeof spec === 'string') ? spec : buildPath(spec);
  if (spec && typeof spec === 'object' && spec.query) {
    url += '?q=' + encodeURIComponent(spec.query);
  }
  const current = location.pathname + location.search;
  if (url !== current) {
    if (opts.replace) history.replaceState({}, '', url);
    else history.pushState({}, '', url);
  }
  // Always emit — same-route calls still let listeners react if they want to.
  window.dispatchEvent(new CustomEvent(ROUTER_EVENT));
}

// React hook — current route spec, kept in sync with popstate + navigate().
function useRoute() {
  const [route, setRoute] = React.useState(
    () => parseRoute(location.pathname, location.search));
  React.useEffect(() => {
    const onChange = () => setRoute(parseRoute(location.pathname, location.search));
    window.addEventListener('popstate', onChange);
    window.addEventListener(ROUTER_EVENT, onChange);
    return () => {
      window.removeEventListener('popstate', onChange);
      window.removeEventListener(ROUTER_EVENT, onChange);
    };
  }, []);
  return route;
}

// ---- anchors ---------------------------------------------------------------

// True for same-origin paths the router should own. Lets external links,
// hash anchors, mailto/tel, and protocol-relative URLs fall through.
function isRouterHref(href) {
  if (!href) return false;
  if (href[0] === '#') return false;
  if (/^(mailto:|tel:)/i.test(href)) return false;
  if (/^(https?:)?\/\//i.test(href)) {
    try { return new URL(href, location.href).origin === location.origin; }
    catch (e) { return false; }
  }
  return href[0] === '/';
}

// Should this click be intercepted, or left to the browser (new tab, etc.)?
function shouldIntercept(e, anchor) {
  if (e.button !== 0) return false;
  if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return false;
  if (e.defaultPrevented) return false;
  if (!anchor) return false;
  if (anchor.target && anchor.target !== '' && anchor.target !== '_self') return false;
  if (anchor.hasAttribute('download')) return false;
  if (anchor.getAttribute('rel') === 'external') return false;
  return isRouterHref(anchor.getAttribute('href'));
}

// Global click delegation: any internal <a href="/…"> anywhere in the tree
// becomes SPA navigation — RouterLink and plain <a href={hrefFor(...)}> both
// work without per-link wiring. preventDefault on the anchor's own handler
// (e.g. RouterLink) short-circuits this via e.defaultPrevented.
function onGlobalClick(e) {
  let el = e.target;
  while (el && el.nodeName !== 'A') el = el.parentNode;
  if (!shouldIntercept(e, el)) return;
  const url = new URL(el.getAttribute('href'), location.href);
  e.preventDefault();
  navigate(url.pathname + url.search);
}
document.addEventListener('click', onGlobalClick);

// <RouterLink to={spec|string} …> — drop-in for <a>. Renders a real href so
// crawlers and middle-click work; the global handler intercepts the click.
function RouterLink({ to, children, ...props }) {
  return React.createElement('a', { href: hrefFor(to), ...props }, children);
}

// ---- exports (also bare globals via the shared script scope) --------------

const Router = {
  ROUTES, parseRoute, buildPath, hrefFor, navigate, useRoute, RouterLink,
  navSpecForKey, navHref,
  current: () => parseRoute(location.pathname, location.search),
};
window.Router = Router;
window.navigate = navigate;
window.hrefFor = hrefFor;
window.navHref = navHref;
window.navSpecForKey = navSpecForKey;
window.RouterLink = RouterLink;

// Opt-in sanity check: append ?routerdebug to any URL to log round-trips.
if (typeof location !== 'undefined' && /routerdebug/.test(location.search)) {
  console.table(ROUTES.map(r => {
    const spec = parseRoute(r.path.replace(':postSlug', 'demo-slug')
                                  .replace(':podcastSlug', 'demo-ep'));
    return { pattern: r.path, parsed: JSON.stringify(spec), rebuilt: buildPath(spec) };
  }));
}
