// Viewport auto-detection. A real narrow device (phones + small tablets) gets the
// bespoke MobileApp; desktop widths get the Sidebar+main layout. Subscribes to the
// MediaQueryList change event (with a resize fallback) and reacts live to width
// changes, so a 390px emulator flips to mobile and a 1400px desktop flips back —
// no manual toggle can ever be the only path or trap a narrow device again.
function useIsMobile(maxWidth = 820) {
  const query = "(max-width: " + maxWidth + "px)";
  const read = () => { try { return window.matchMedia(query).matches; } catch (e) { return false; } };
  const [isMobile, setIsMobile] = React.useState(read);
  React.useEffect(() => {
    let mql;
    try { mql = window.matchMedia(query); } catch (e) { return; }
    const onChange = () => setIsMobile(mql.matches);
    onChange();
    if (mql.addEventListener) mql.addEventListener("change", onChange);
    else if (mql.addListener) mql.addListener(onChange);       // older Safari
    window.addEventListener("resize", onChange);               // belt-and-braces
    return () => {
      if (mql.removeEventListener) mql.removeEventListener("change", onChange);
      else if (mql.removeListener) mql.removeListener(onChange);
      window.removeEventListener("resize", onChange);
    };
  }, [query]);
  return isMobile;
}

// App shell — login → auto (viewport-detected) mobile OR persistent-sidebar desktop.
function BackstageApp() {
  const [user, setUser] = React.useState(null);
  const [authReady, setAuthReady] = React.useState(false);
  const [activeNav, setActiveNav] = React.useState("dashboard");
  const [device, setDevice] = React.useState("desktop");

  // CLIENT-SIDE AUTH GATE (security-critical).
  // This SPA uses hash routes (#/suppliers …) which MemberSpace's path-based
  // protection cannot see, so login state — not the URL — must gate the whole
  // app. We wait for the MemberSpace widget to report READY, then ask it who the
  // member is. Protected content (`user` set) renders ONLY after an authoritative
  // { isLoggedIn: true } from MemberSpace.getMemberInfo(). Until the check
  // completes we show a loading screen and never flash protected content.
  React.useEffect(() => {
    let alive = true;
    let settled = false;
    const liveHost = !!(window.msIsLiveHost && window.msIsLiveHost());

    const setMember = m => setUser({
      name: m.name,
      email: m.email,
      initials: (m.name || "M").split(" ").slice(0, 2).map(s => s[0]).join("").toUpperCase(),
      role: m.plan || "Member",
    });

    // Authoritative check: getMemberInfo() → { isLoggedIn, member }.
    const check = () => {
      if (!window.msGetAuth) return;
      window.msGetAuth().then(res => {
        if (!alive || !res.ready) return;          // widget not active yet — ignore
        settled = true;
        if (res.isLoggedIn && res.member) setMember(res.member);
        else { setUser(null); setActiveNav("dashboard"); }
        setAuthReady(true);
      });
    };

    // Documented SPA pattern: run the check the moment MemberSpace is ready.
    const offReady = window.msOnReady ? window.msOnReady(check) : null;

    // Keep auth state live: login/signup, member-info updates, and logout — on
    // logout we drop straight back to the LoginScreen with no refresh needed.
    const offAuth = window.msOnAuth ? window.msOnAuth({
      onLogin: check,
      onInfo: check,
      onLogout: () => { if (alive) { setUser(null); setActiveNav("dashboard"); setAuthReady(true); } },
    }) : null;

    // Fallback if MemberSpace never initialises:
    //  • live host  → stay LOCKED (LoginScreen w/ MemberSpace popup) — never leak.
    //  • preview/non-prod → unlock the walkable demo (LoginScreen demo session).
    // Either way `user` stays null, so no protected content renders without auth.
    const t = setTimeout(() => {
      if (alive && !settled) { setUser(null); setAuthReady(true); }
    }, liveHost ? 7000 : 1800);

    return () => { alive = false; clearTimeout(t); if (offReady) offReady(); if (offAuth) offAuth(); };
  }, []);

  // Per-section URLs. MemberSpace gates by URL, so each section is its own route.
  // Prototype: hash routes (#/suppliers). Production: real paths (/suppliers) —
  // see MS_SECTION_PATHS in MemberSpaceIntegration.jsx.
  const VALID = ["dashboard","suppliers","hotels","air","events","resources","information","forms","vendor","feedback","deals","contact"];
  React.useEffect(() => {
    const fromHash = () => {
      const slug = (location.hash || "").replace(/^#\/?/, "").split(/[/?]/)[0];
      if (slug && VALID.indexOf(slug) !== -1) setActiveNav(slug);
      else if (!slug) setActiveNav("dashboard");
    };
    fromHash();
    window.addEventListener("hashchange", fromHash);
    return () => window.removeEventListener("hashchange", fromHash);
  }, []);

  function handleSelect(id) {
    if (id === "__account") {
      // Production: "My Account" is a MemberSpace Member Link (anchor) — the widget
      // opens the account modal; logout lives there / on the Member Button. In the
      // preview there's no widget, so we reset the demo session to show the entry.
      if (!(window.msIsLiveHost && window.msIsLiveHost())) { setUser(null); setActiveNav("dashboard"); if (history.replaceState) history.replaceState(null, "", location.pathname + location.search); else location.hash = ""; }
      return;
    }
    setActiveNav(id);
    if (location.hash !== "#/" + id) location.hash = "#/" + id;
    window.scrollTo(0, 0);
  }

  // Live viewport detection — real phones/small tablets (<=820px) get the bespoke
  // mobile experience automatically, full-viewport, with no iPhone bezel.
  const isMobile = useIsMobile(820);

  // Hold protected content until MemberSpace has reported login state.
  if (!authReady) return <AuthLoading />;

  if (!user) {
    return <LoginScreen onSignIn={({ email }) => {
      // Demo session is for the preview/non-prod walkthrough only — never grant a
      // fabricated session on the live host, where MemberSpace is the sole gate.
      if (window.msIsLiveHost && window.msIsLiveHost()) return;
      const name = email && email.includes("@")
        ? email.split("@")[0].replace(/[._]/g, " ").replace(/\b\w/g, c => c.toUpperCase())
        : "Amelia Cortes";
      const initials = name.split(" ").slice(0, 2).map(s => s[0]).join("").toUpperCase();
      setUser({ name, email, initials, role: "Lead Ops · Miami" });
      setActiveNav("dashboard");
    }} />;
  }

  function renderPage() {
    switch (activeNav) {
      case "dashboard": return <DashboardPage user={user} onSelect={handleSelect} />;
      case "suppliers": return <SuppliersPage />;
      case "hotels":    return <HotelContactsPage />;
      case "air":       return <AirPage />;
      case "events":    return <EventsPage />;
      case "resources": return <ResourcesPage />;
      case "information": return <InformationPage user={user} />;
      case "forms":     return <FormsPage />;
      case "vendor":    return <VendorRequestPage />;
      case "feedback":  return <FeedbackPage />;
      case "deals":     return <PartnerDealsPage />;
      case "contact":   return <ContactPage />;
      default:          return <StaticPage page={activeNav} />;
    }
  }

  // Sign-out / "My Account" on mobile routes through the SAME handler the desktop
  // uses: on the live host it opens the MemberSpace account modal (native logout);
  // in preview it resets the demo session → back to LoginScreen.
  const onMobileSignOut = () => handleSelect("__account");

  // ── AUTO MOBILE ──────────────────────────────────────────────────────────────
  // A genuinely narrow viewport gets MobileApp rendered DIRECTLY — full real
  // viewport width, NO IOSDevice bezel, no fixed width, no centering. It fills the
  // device. Auto-detection is the sole decider here, so the old fixed-frame trap
  // (a 392px bezel overflowing a ~390px phone and hiding its own escape) is gone,
  // and the manual toggle is irrelevant/hidden at mobile width.
  if (isMobile) {
    return (
      <MobileApp
        full
        user={user}
        active={activeNav}
        onSelect={handleSelect}
        onSignOut={onMobileSignOut}
      />
    );
  }

  // ── DESKTOP WIDTH ────────────────────────────────────────────────────────────
  // The device toggle survives only as a STAFF/PREVIEW aid on non-live hosts, and
  // only matters at desktop width: a staffer can force the bezel'd 392px mockup for
  // demos. It is never shown on the live host and never the only path to mobile.
  const showDeviceToggle = !(window.msIsLiveHost && window.msIsLiveHost());
  const previewMobile = showDeviceToggle && device === "mobile";

  return (
    <>
      {showDeviceToggle && <DeviceToggle device={device} onChange={setDevice} />}

      {previewMobile ? (
        <div style={{ minHeight: "100vh", background: "var(--ink-0)", display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", padding: "56px 24px 40px", gap: 22 }}>
          <div style={{ fontFamily: "var(--font-body)", fontWeight: 600, fontSize: 10, letterSpacing: "0.32em", color: "var(--ink-6)", textTransform: "uppercase" }}>
            Mobile Preview · Contractor Portal
          </div>
          <IOSDevice dark width={392} height={812}>
            <MobileApp user={user} active={activeNav} onSelect={handleSelect} onSignOut={onMobileSignOut} />
          </IOSDevice>
          <div style={{ fontFamily: "var(--font-mono)", fontSize: 11, color: "var(--ink-6)", maxWidth: 360, textAlign: "center", lineHeight: 1.5 }}>
            Staff preview only — real phones get this full-screen automatically. Narrow this window below 820px to see live auto-detection.
          </div>
        </div>
      ) : (
        <div style={{ display: "flex", alignItems: "flex-start", minHeight: "100vh", background: "var(--ink-0)" }}>
          <Sidebar activeId={activeNav} onSelect={handleSelect} user={user} />
          <main style={{ flex: 1, minWidth: 0, background: "var(--ink-1)", minHeight: "100vh" }}>
            {renderPage()}
          </main>
        </div>
      )}
    </>
  );
}

// Shown while the MemberSpace auth check is in flight — a neutral branded screen
// that deliberately reveals NO protected content until login state is known.
function AuthLoading() {
  return (
    <div style={{
      minHeight: "100vh", width: "100%",
      background: "linear-gradient(180deg, #0D0D0D 0%, #1A1A1A 100%)",
      display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", gap: 24,
    }}>
      <Logo size={120} />
      <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
        <span style={{ width: 8, height: 8, borderRadius: "50%", background: "var(--rdb-gold)", display: "inline-block", animation: "rdbpulse 1s ease-in-out infinite" }} />
        <span style={{ fontFamily: "var(--font-mono)", fontSize: 12, color: "var(--fg-2)", letterSpacing: "0.04em" }}>Verifying access…</span>
      </div>
    </div>
  );
}

function DeviceToggle({ device, onChange }) {
  const opt = (id, icon, label) => {
    const active = device === id;
    return (
      <button
        onClick={() => onChange(id)}
        style={{
          display: "flex", alignItems: "center", gap: 7,
          padding: "8px 14px",
          background: active ? "var(--rdb-gold)" : "transparent",
          color: active ? "#0D0D0D" : "var(--fg-2)",
          border: "none", cursor: "pointer",
          fontFamily: "var(--font-body)", fontWeight: 600, fontSize: 10,
          letterSpacing: "0.16em", textTransform: "uppercase",
          transition: "all 160ms cubic-bezier(.22,1,.36,1)",
        }}
      >
        <Icon name={icon} size={14} color={active ? "#0D0D0D" : "var(--ink-6)"} />
        {label}
      </button>
    );
  };
  return (
    <div style={{
      position: "fixed", top: 18, right: 22, zIndex: 200,
      display: "flex", border: "1px solid var(--ink-3)",
      background: "rgba(13,13,13,0.85)", backdropFilter: "blur(12px)",
    }}>
      {opt("desktop", "monitor", "Desktop")}
      {opt("mobile", "smartphone", "Mobile")}
    </div>
  );
}

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<BackstageApp />);
