// App — routing + composition with cart context + auth context.
//
// Key invariants:
// - We always call the same hooks in the same order (hook rule compliance):
//   useAuthSafe is resolved ONCE at module load (real hook if zsb.jsx loaded,
//   else a stub that returns a static object — no hooks). The chosen variant
//   is then used every render.
// - PASSWORD_RECOVERY: if Supabase fires a recovery event on this page (e.g.
//   user clicked an old reset link pointing to index.html), bounce them to
//   the dedicated reset-password.html which is safe for the hash router.

const useAuthSafe = window.useAuthStore || (() => ({
  user: null, profile: null, ready: true, isAdmin: false, isRecovery: false,
  refreshProfile: () => {},
}));

// Live-prices store. Mutates window.PRODUCTS so every page that reads
// PRODUCTS[id].price automatically displays Supabase's current value.
// Re-render is triggered by the React state update inside the hook.
const useProductsSafe = window.useProductsStore || (() => ({
  products: {}, ready: true, error: null, version: 0, refresh: () => {},
}));

// Language + theme stores resolve once at module-load (stable hook order).
const useLangSafe = window.useLangStore || (() => ({
  lang: "nl", setLang: () => {}, t: (nl) => nl,
}));
const useThemeSafe = window.useThemeStore || (() => ({
  theme: "light", setTheme: () => {}, toggleTheme: () => {},
}));
const useSettingsSafe = window.useSettingsStore || (() => ({ ready: true, version: 0, refresh: () => {} }));

// Login modal — popup over the current page so the URL doesn't have to
// switch to /#login for every login. Direct /#login route stays available
// (e.g. for deep links from emails). PageLogin in compact mode does all
// the actual auth work; this is purely the visual wrapper.
const LoginModal = ({ open, onClose }) => {
  const { useEffect } = React;
  useEffect(() => {
    if (!open) return;
    const onKey = (e) => { if (e.key === "Escape") onClose(); };
    window.addEventListener("keydown", onKey);
    // Prevent background scroll while open.
    const prev = document.body.style.overflow;
    document.body.style.overflow = "hidden";
    return () => {
      window.removeEventListener("keydown", onKey);
      document.body.style.overflow = prev;
    };
  }, [open, onClose]);
  if (!open) return null;
  if (!window.PageLogin) return null;
  // setPage passed to PageLogin: ignore the target page, just close the modal.
  // User stays on whatever page they were browsing before opening login.
  const closeAfterAuth = () => onClose();
  return (
    <>
      <div onClick={onClose} aria-hidden="true" style={{
        position:"fixed", inset:0, background:"rgba(0,0,0,.55)",
        zIndex:200, backdropFilter:"blur(2px)", WebkitBackdropFilter:"blur(2px)",
      }}/>
      <div role="dialog" aria-modal="true" aria-label={(window.localStorage && localStorage.getItem("zyro-lang") === "en") ? "Sign in" : "Inloggen"} style={{
        position:"fixed", top:"50%", left:"50%", transform:"translate(-50%,-50%)",
        zIndex:201, width:"min(520px, 94vw)", maxHeight:"92vh", overflowY:"auto",
        background:"var(--paper, #fff)", borderRadius:14,
        boxShadow:"0 20px 60px rgba(0,0,0,.25)",
      }}>
        <div style={{
          padding:"12px 14px", display:"flex", justifyContent:"flex-end",
          alignItems:"center", position:"sticky", top:0, background:"var(--paper, #fff)",
          borderBottom:"1px solid var(--line)", zIndex:1,
        }}>
          <button type="button" onClick={onClose} aria-label="Sluiten" className="icon-btn">
            <Icon name="x" size={20}/>
          </button>
        </div>
        <PageLogin setPage={closeAfterAuth} compact={true}/>
      </div>
    </>
  );
};

// Catches render-time crashes per page so a single bad component never
// white-screens the whole site. Resets when the page slug changes.
class PageErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { error: null };
  }
  static getDerivedStateFromError(error) {
    return { error };
  }
  componentDidCatch(error, info) {
    try { console.error("[Zyro] page crash:", error, info); } catch (_) {}
  }
  componentDidUpdate(prevProps) {
    if (prevProps.resetKey !== this.props.resetKey && this.state.error) {
      this.setState({ error: null });
    }
  }
  render() {
    if (this.state.error) {
      const msg = (this.state.error && (this.state.error.message || String(this.state.error))) || "Onbekende fout";
      return (
        <div className="page section">
          <div className="wrap" style={{maxWidth:560, textAlign:"center"}}>
            <h2 className="h-display" style={{fontSize:32, marginBottom:10}}>Er ging iets mis op deze pagina</h2>
            <p style={{color:"var(--ink-dim)", marginBottom:18}}>
              Probeer terug te gaan naar de homepage of een andere pagina te kiezen.
              De rest van de site werkt nog gewoon.
            </p>
            <div className="gap-12" style={{justifyContent:"center", marginBottom:18}}>
              <a className="btn btn-primary" href="#home">{((typeof localStorage !== "undefined" && localStorage.getItem("zyro-lang") === "en") ? "Back to home" : "Terug naar home")}</a>
              <a className="btn btn-ghost" href="#shop">{((typeof localStorage !== "undefined" && localStorage.getItem("zyro-lang") === "en") ? "To models" : "Naar modellen")}</a>
            </div>
            <details style={{marginTop:18, fontSize:11, color:"var(--ink-mute)", textAlign:"left"}}>
              <summary style={{cursor:"pointer"}}>Technische details</summary>
              <pre style={{whiteSpace:"pre-wrap", marginTop:8, fontFamily:"var(--f-mono)"}}>{msg}</pre>
            </details>
          </div>
        </div>
      );
    }
    return this.props.children;
  }
}

const App = () => {
  // Settings store FIRST so shipping/free-threshold values are populated
  // into window.SHIPPING_CONFIG before the cart hook reads them.
  // Auth must come BEFORE cart so the cart store can scope its storage key
  // to the logged-in user (or guest). Switching accounts swaps carts; we
  // never merge carts across accounts.
  const settings = useSettingsSafe();
  const auth = useAuthSafe();
  const cart = useCartStore(auth && auth.user);
  const products = useProductsSafe();
  const lang = useLangSafe();
  const theme = useThemeSafe();
  const [showLogin, setShowLogin] = React.useState(false);

  // URL cleanup on first mount:
  //   /index.html  →  /
  //   /?id=1#admin →  /#admin
  // We strip ALL query strings (the app uses none). Hash is preserved so
  // hash-routes (#admin, #v20, recovery tokens etc.) keep working.
  React.useEffect(() => {
    try {
      const cleanedPath = location.pathname.replace(/\/index\.html$/, "/") || "/";
      const cleanedUrl = cleanedPath + location.hash;
      const currentUrl = location.pathname + location.search + location.hash;
      if (cleanedUrl !== currentUrl) {
        history.replaceState({}, "", cleanedUrl);
      }
    } catch (_) { /* never let URL cleanup crash the app */ }
  }, []);

  // Auto-close login modal once the user is signed in.
  React.useEffect(() => {
    if (showLogin && auth && auth.user) setShowLogin(false);
  }, [showLogin, auth && auth.user && auth.user.id]);

  const [page, setPageRaw] = React.useState(() => {
    const h = (location.hash || "").replace(/^#/, "");
    // Drop any trailing query/auth-token fragments
    const slug = h.split(/[&?]/)[0];
    return slug || "home";
  });

  const setPage = (id) => {
    setPageRaw(id);
    if (location.hash !== "#" + id) location.hash = id;
    window.scrollTo({top:0, behavior:"instant"});
  };

  React.useEffect(() => {
    const onHash = () => {
      const h = (location.hash || "").replace(/^#/, "");
      const slug = h.split(/[&?]/)[0];
      setPageRaw(slug || "home");
      window.scrollTo({top:0, behavior:"instant"});
    };
    window.addEventListener("hashchange", onHash);
    return () => window.removeEventListener("hashchange", onHash);
  }, []);

  // If Supabase fires PASSWORD_RECOVERY here (user clicked an old reset link
  // that pointed to index.html), redirect to the dedicated reset page.
  React.useEffect(() => {
    if (auth && auth.isRecovery) {
      location.href = "reset-password.html";
    }
  }, [auth && auth.isRecovery]);

  // Map URL slugs that aren't in main nav to screen labels
  const labelMap = {
    home:"01 Home", shop:"02 Modellen", v20:"03 V20 Pro", gt2000:"04 GT2000",
    compare:"05 Vergelijk", accessories:"06 Accessoires", regels:"07 Regels",
    service:"08 Service", contact:"09 Contact", cart:"10 Winkelmand", checkout:"11 Checkout",
    "payment-success":"12 Betaling", about:"13 Over Zyro", login:"14 Inloggen", account:"15 Mijn account", admin:"16 Admin",
  };

  const AuthCtx = window.AuthContext || React.createContext({ user: null });
  const ProductsCtx = window.ProductsContext || React.createContext({ products: {}, ready: true, refresh: () => {} });
  const SettingsCtx = window.SettingsContext || React.createContext({ ready: true, version: 0, refresh: () => {} });
  const LangCtx = window.LangContext || React.createContext({ lang: "nl", t: (nl) => nl, setLang: () => {} });
  const ThemeCtx = window.ThemeContext || React.createContext({ theme: "light", toggleTheme: () => {}, setTheme: () => {} });
  const navPage = (page === "v20" || page === "gt2000" || page === "compare") ? "shop" : page;

  return (
    <ThemeCtx.Provider value={theme}>
    <LangCtx.Provider value={lang}>
    <SettingsCtx.Provider value={settings}>
    <ProductsCtx.Provider value={products}>
    <AuthCtx.Provider value={auth}>
      <CartContext.Provider value={cart}>
        <div data-screen-label={labelMap[page] || page}>
          <ComplianceBar/>
          <Nav page={navPage} setPage={setPage} onLoginClick={() => setShowLogin(true)}/>
          <main key={page}>
            <PageErrorBoundary resetKey={page}>
              {page === "home" && <PageHome setPage={setPage}/>}
              {page === "shop" && <PageShop setPage={setPage}/>}
              {page === "v20" && <PageProduct bikeId="v20" setPage={setPage}/>}
              {page === "gt2000" && <PageProduct bikeId="gt2000" setPage={setPage}/>}
              {page === "compare" && <PageCompare setPage={setPage}/>}
              {page === "accessories" && <PageAccessories setPage={setPage}/>}
              {page === "regels" && <PageRegels setPage={setPage}/>}
              {page === "service" && <PageService setPage={setPage}/>}
              {page === "contact" && <PageContact setPage={setPage}/>}
              {page === "cart" && <PageCart setPage={setPage}/>}
              {page === "checkout" && <PageCheckout setPage={setPage}/>}
              {page === "payment-success" && window.PagePaymentSuccess && <PagePaymentSuccess setPage={setPage}/>}
              {page === "about" && <PageAbout setPage={setPage}/>}
              {page === "login" && window.PageLogin && <PageLogin setPage={setPage}/>}
              {page === "account" && window.PageAccount && <PageAccount setPage={setPage}/>}
              {page === "admin" && window.PageAdmin && <PageAdmin setPage={setPage}/>}
              {/* Unknown hash → quietly show home so the back button can't strand the user */}
              {!["home","shop","v20","gt2000","compare","accessories","regels","service","contact","cart","checkout","payment-success","about","login","account","admin"].includes(page) && <PageHome setPage={setPage}/>}
            </PageErrorBoundary>
          </main>
          <Footer setPage={setPage}/>
          <CartDrawer setPage={setPage}/>
          <LoginModal open={showLogin} onClose={() => setShowLogin(false)}/>
          {page !== "checkout" && page !== "payment-success" && page !== "contact" && page !== "login" && page !== "account" && page !== "admin" && <FloatingWhats/>}
        </div>
      </CartContext.Provider>
    </AuthCtx.Provider>
    </ProductsCtx.Provider>
    </SettingsCtx.Provider>
    </LangCtx.Provider>
    </ThemeCtx.Provider>
  );
};

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