// Caffè Italia · app root
const { useState: uS, useEffect: uE, useCallback: uC } = React;

// paperGlass = translucent variant of `paper`, used by the sticky header on scroll
// so its background follows the active theme instead of staying cream.
const PALETTES = {
  nero:      { paper:"#0a0907", paper2:"#141210", paper3:"#1e1b18", ink:"#f4ede0", rosso:"#dc2832", crema:"#d8c393", paperGlass:"rgba(10,9,7,.88)" },
  inchiostro:{ paper:"#000000", paper2:"#0c0c0c", paper3:"#1a1a1a", ink:"#ffffff", rosso:"#e02a36", crema:"#e8c98a", paperGlass:"rgba(0,0,0,.88)" },
  bianco:    { paper:"#ffffff", paper2:"#f6f4ef", paper3:"#ebe8df", ink:"#0e0d0c", rosso:"#c8202c", crema:"#d8c393", paperGlass:"rgba(255,255,255,.88)" },
};

// ─── URL <-> route bridge (hash-based, works on static hosting) ──────────────
// Hash format: #/{lang}/{page}/{arg}   ex: #/it/category/nespresso
// Supabase renvoie ses jetons dans le fragment (#access_token=…&type=recovery).
// Tant qu'il est là, le routeur n'y touche pas : supabase-js doit le lire et
// le nettoyer lui-même, sinon la session de récupération n'est jamais créée
// et le changement de mot de passe échoue faute d'utilisateur authentifié.
function hashCarriesAuthToken() {
  const h = window.location.hash || "";
  return /(?:^|[#&])(access_token|refresh_token|error_description|type=recovery)=?/.test(h);
}

// supabase-js consomme le jeton puis efface le fragment — et cet effacement
// déclenche un hashchange vers une URL vide, impossible à distinguer d'une
// navigation de l'utilisateur. Sans ce drapeau, l'écouteur ci-dessous relit
// une URL vide, conclut « accueil », et annule l'écran de récupération qu'on
// vient d'ouvrir. On avale exactement cet événement-là, une seule fois.
let authCleanupPending = /(?:^|[#&])(access_token|refresh_token|type=recovery)/
  .test(window.__INITIAL_HASH__ || "");

function parseHash() {
  const h = (window.location.hash || "").replace(/^#\/?/, "");
  if (!h) return { lang: detectInitialLang(), route: { page: "home" } };
  const parts = h.split("/").map(decodeURIComponent);
  let lang = parts[0];
  let i = 0;
  if (window.SUPPORTED_LANGS.includes(lang)) { i = 1; } else { lang = detectInitialLang(); }
  const p = parts[i], a = parts[i+1];
  let route = { page: "home" };
  if (p === "category" && a) route = { page: "category", cat: a };
  else if (p === "famille" && a)  route = { page: "family",   key: a };
  else if (p === "product"  && a) route = { page: "product",  id: a };
  else if (p === "story")         route = { page: "story" };
  else if (p === "all")           route = { page: "all" };
  else if (p === "page" && a)     route = { page: "page", slug: a };
  else if (p === "admin")         route = { page: "admin" };
  else if (p === "account")       route = { page: "account" };
  // Stripe success redirect: #/{lang}/commande/ok?session_id=cs_...
  else if (p === "commande" && a && a.split("?")[0] === "ok") route = { page: "page", slug: "commande-ok" };
  return { lang, route };
}
function toHash(lang, r) {
  const langPart = `/${lang}`;
  if (r.page === "home")     return `#${langPart}`;
  if (r.page === "category") return `#${langPart}/category/${encodeURIComponent(r.cat)}`;
  if (r.page === "family")   return `#${langPart}/famille/${encodeURIComponent(r.key)}`;
  if (r.page === "product")  return `#${langPart}/product/${encodeURIComponent(r.id)}`;
  if (r.page === "story")    return `#${langPart}/story`;
  if (r.page === "all")      return `#${langPart}/all`;
  if (r.page === "page")     return `#${langPart}/page/${encodeURIComponent(r.slug)}`;
  if (r.page === "admin")    return `#${langPart}/admin`;
  if (r.page === "account")  return `#${langPart}/account`;
  return `#${langPart}`;
}
function detectInitialLang() {
  try {
    const stored = localStorage.getItem("caffe_lang");
    if (window.SUPPORTED_LANGS.includes(stored)) return stored;
  } catch {}
  const nav = (navigator.language || "").slice(0,2).toLowerCase();
  return window.SUPPORTED_LANGS.includes(nav) ? nav : window.DEFAULT_LANG;
}

function App() {
  const [t, setTweak] = useTweaks(window.__TWEAK_DEFAULTS__);
  const initial = parseHash();
  // Set global lang BEFORE first render so t() and pick() resolve correctly.
  window.__LANG__ = initial.lang;
  const [lang, setLangState]  = uS(initial.lang);
  const [route, setRoute] = uS(initial.route);
  const [cart, setCart]   = uS(() => {
    try { return JSON.parse(localStorage.getItem("caffe_cart") || "[]"); }
    catch { return []; }
  });
  const [cartOpen, setCartOpen]   = uS(false);
  const [menuOpen, setMenuOpen]   = uS(false);
  // Dernier article ajouté. `seq` s'incrémente à chaque ajout — c'est lui
  // qui relance l'animation, y compris quand on réajoute le même produit.
  // Le header n'a besoin que de `seq` ; la toast affiche le reste.
  const [lastAdded, setLastAdded] = uS(null);

  // Expose current lang to all components via global (t() reads it)
  uE(() => {
    window.__LANG__ = lang;
    document.documentElement.lang = lang;
    try { localStorage.setItem("caffe_lang", lang); } catch {}
  }, [lang]);

  // Sync hash <-> (lang, route) — deep linking + back button
  uE(() => {
    const onHashChange = () => {
      if (authCleanupPending && !window.location.hash) { authCleanupPending = false; return; }
      const { lang: l, route: r } = parseHash();
      setLangState(l);
      setRoute(r);
    };
    window.addEventListener("hashchange", onHashChange);
    return () => window.removeEventListener("hashchange", onHashChange);
  }, []);
  uE(() => {
    if (hashCarriesAuthToken()) return;   // laisser supabase-js consommer le jeton
    const want = toHash(lang, route);
    if ((window.location.hash || "") !== want) {
      history.replaceState(null, "", want);
    }
  }, [lang, route.page, route.cat, route.id, route.key]);

  // Persist cart across reloads
  uE(() => {
    try { localStorage.setItem("caffe_cart", JSON.stringify(cart)); } catch {}
  }, [cart]);

  // Apply palette + mode + density to :root
  uE(() => {
    const root = document.documentElement;
    const P = PALETTES[t.palette] || PALETTES.nero;
    root.style.setProperty("--paper",       P.paper);
    root.style.setProperty("--paper-2",     P.paper2);
    root.style.setProperty("--paper-3",     P.paper3);
    root.style.setProperty("--paper-glass", P.paperGlass);
    root.style.setProperty("--ink",         P.ink);
    root.style.setProperty("--rosso",       P.rosso);
    root.style.setProperty("--crema",       P.crema);
    document.body.dataset.mode = t.mode || "light";
    document.body.dataset.density = t.density || "regular";
    document.body.dataset.palette = t.palette || "nero";
  }, [t.palette, t.mode, t.density]);

  // Scroll top on route change
  uE(() => { window.scrollTo({ top:0, behavior:"instant" }); }, [route.page, route.cat, route.id, route.key]);

  const navigate = uC((to) => {
    if (hashCarriesAuthToken()) { setRoute(to); return; }
    const want = toHash(window.__LANG__ || lang, to);
    if ((window.location.hash || "") !== want) {
      history.pushState(null, "", want);
    }
    setRoute(to);
  }, [lang]);
  // Supabase renvoie le lien de réinitialisation sur la racine du site, pas
  // sur une route : on amène l'utilisateur à l'écran qui sait finir le travail.
  const recovery = useRecoveryMode();
  uE(() => {
    if (recovery && route.page !== "account") navigate({ page: "account" });
  }, [recovery]);

  const setLang = uC((l) => {
    if (!window.SUPPORTED_LANGS.includes(l)) return;
    window.__LANG__ = l;  // sync before re-render so t()/pick() see the new lang
    const want = toHash(l, route);
    if ((window.location.hash || "") !== want) {
      history.pushState(null, "", want);
    }
    setLangState(l);
  }, [route]);
  const addToCart = uC((p, qty=1) => {
    setCart(prev => {
      const found = prev.find(x => x.id === p.id);
      if (found) return prev.map(x => x.id===p.id ? {...x, qty:x.qty+qty} : x);
      return [...prev, { ...p, qty }];
    });
    setLastAdded(prev => ({
      seq:    (prev ? prev.seq : 0) + 1,
      name:   window.pick(p.name),
      weight: window.fmtWeight(p),
      image:  p.image || "",
      qty,
    }));
  }, []);
  const removeFromCart = uC((id) => setCart(prev => prev.filter(x=>x.id!==id)), []);
  const setQty = uC((id, qty) => setCart(prev => prev.map(x=>x.id===id?{...x,qty}:x)), []);

  const cartCount = cart.reduce((s,i)=>s+i.qty,0);

  // Boot the product catalog from Supabase once. Screens read window.PRODUCTS
  // at render, so we assign it then flip catalogReady to trigger a re-render.
  const [catalogReady, setCatalogReady] = uS(false);
  uE(() => {
    let cancelled = false;
    (async () => {
      const { products } = await window.fetchCatalog();
      if (cancelled) return;
      window.PRODUCTS = products;
      setCatalogReady(true);
    })();
    return () => { cancelled = true; };
  }, []);

  // Pages that depend on the catalog wait for the first fetch; admin, account,
  // static info pages and the story page render immediately.
  const catalogPages = ["home", "category", "product", "all", "family"];
  let screen;
  if (!catalogReady && catalogPages.includes(route.page)) {
    screen = (
      <main className="wrap" style={{padding:"96px 32px",minHeight:"50vh",color:"var(--muted)"}}>
        {window.__LANG__==="it" ? "Caricamento del catalogo…" : "Chargement du catalogue…"}
      </main>
    );
  }
  else if (route.page === "home")        screen = <HomeScreen     navigate={navigate} onAdd={addToCart}/>;
  else if (route.page === "category") screen = <CategoryScreen cat={route.cat} navigate={navigate} onAdd={addToCart}/>;
  else if (route.page === "family")   screen = <CategoryScreen family={route.key} navigate={navigate} onAdd={addToCart}/>;
  else if (route.page === "product")   screen = <ProductScreen  id={route.id}   navigate={navigate} onAdd={addToCart}/>;
  else if (route.page === "story")     screen = <StoryScreen    navigate={navigate}/>;
  else if (route.page === "all")       screen = <ShopAllScreen  navigate={navigate} onAdd={addToCart}/>;
  else if (route.page === "page")      screen = <InfoPage       slug={route.slug} navigate={navigate}/>;
  else if (route.page === "admin")     screen = <AdminScreen    navigate={navigate}/>;
  else if (route.page === "account")   screen = <AccountScreen  navigate={navigate}/>;
  else screen = <HomeScreen navigate={navigate} onAdd={addToCart}/>;

  return (
    <>
      <Header
        route={route}
        navigate={navigate}
        onOpenCart={()=>setCartOpen(true)}
        onOpenMenu={()=>setMenuOpen(true)}
        cartCount={cartCount}
        cartPulse={lastAdded ? lastAdded.seq : 0}
        lang={lang}
        onSetLang={setLang}
      />
      {screen}
      <Footer navigate={navigate}/>

      <MenuDrawer open={menuOpen} onClose={()=>setMenuOpen(false)} navigate={navigate}/>
      <CartDrawer open={cartOpen} onClose={()=>setCartOpen(false)} items={cart} onRemove={removeFromCart} onQty={setQty} navigate={navigate}/>
      <CartToast item={lastAdded} onOpenCart={()=>setCartOpen(true)} suppressed={cartOpen}/>

      <TweaksPanel>
        <TweakSection label="Palette"/>
        <TweakRadio label="Tonalité"
          value={t.palette}
          options={["nero","inchiostro","bianco"]}
          onChange={(v)=>setTweak("palette", v)}/>
        <TweakRadio label="Thème"
          value={t.mode}
          options={["light","dark"]}
          onChange={(v)=>setTweak("mode", v)}/>

        <TweakSection label="Mise en page"/>
        <TweakRadio label="Densité"
          value={t.density}
          options={["compact","regular","comfy"]}
          onChange={(v)=>setTweak("density", v)}/>
        <TweakToggle label="Bandeau marquee" value={t.showRibbon} onChange={(v)=>setTweak("showRibbon", v)}/>
        <TweakToggle label="Accents italiens" value={t.italianAccents} onChange={(v)=>setTweak("italianAccents", v)}/>

        <TweakSection label="Navigation"/>
        <TweakButton label="Page d’accueil" onClick={()=>navigate({page:"home"})}/>
        <TweakButton label="Catégorie · Grains" onClick={()=>navigate({page:"category",cat:"grain"})}/>
        <TweakButton label="Catégorie · Épicerie" onClick={()=>navigate({page:"category",cat:"capsules"})}/>
        <TweakButton label="Fiche produit" onClick={()=>navigate({page:"product",id:"moreno-top-espresso-extra-1kg"})}/>
        <TweakButton label="Notre histoire" onClick={()=>navigate({page:"story"})}/>
        <TweakButton label="Ouvrir le panier" onClick={()=>setCartOpen(true)}/>
      </TweaksPanel>
    </>
  );
}

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