// app.jsx — main shell, routing, state. Member shell + Admin shell.

const { useState, useEffect, useMemo } = React;

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "showStatusBar": false,
  "accent": "#B5563C",
  "showFriends": true
}/*EDITMODE-END*/;

function applyAccent(hex) {
  document.documentElement.style.setProperty("--primary", hex);
}

const DEFAULT_USER = {
  name: "",
  email: "",
  initials: "",
  joined: "",
  visits: 0,
  streak: 0,
  creditPacks: [],
  credits: 0,
  booked: [],
  bookingPrivacy: {},
  visibleByDefault: true,
  waitlist: [],
  savedClasses: [],
  savedCoaches: [],
  following: [],
  pendingFollowers: [],
  sentRequests: [],
  monthly: [],
  history: []
};

function hydrateUser(rawUser) {
  let meta = {};
  if (rawUser.metadata) {
    try {
      meta = typeof rawUser.metadata === "string" ? JSON.parse(rawUser.metadata) : rawUser.metadata;
    } catch (e) {
      console.error("Failed to parse metadata", e);
    }
  }
  
  const creditPacks = (rawUser.creditPacks || []).map(p => ({
    id: p.id,
    packageId: p.package_id || p.packageId,
    packageName: p.package_name || p.packageName,
    credits: p.credits,
    total: p.total,
    purchased: p.purchased,
    expires: p.expires
  }));
  
  const names = (rawUser.name || "Member").split(" ");
  const initials = names.map(n => n[0]).slice(0, 2).join("").toUpperCase();
  
  return {
    id: rawUser.id,
    name: rawUser.name || "Member",
    email: rawUser.email || "",
    joined: rawUser.joined || "2026",
    visits: rawUser.visits || 0,
    streak: meta.streak || 0,
    creditPacks: creditPacks,
    credits: creditPacks.reduce((sum, p) => sum + p.credits, 0),
    booked: rawUser.booked || [],
    bookingPrivacy: meta.bookingPrivacy || {},
    visibleByDefault: meta.visibleByDefault !== false, // default true
    waitlist: meta.waitlist || [],
    savedClasses: meta.savedClasses || [],
    savedCoaches: meta.savedCoaches || [],
    following: meta.following || [],
    pendingFollowers: meta.pendingFollowers || [],
    sentRequests: meta.sentRequests || [],
    monthly: meta.monthly || [
      { m: "Dec", n: 2 },
      { m: "Jan", n: 4 },
      { m: "Feb", n: 5 },
      { m: "Mar", n: 7 },
      { m: "Apr", n: 9 },
      { m: "May", n: 6 },
    ],
    history: rawUser.history || [],
    initials: initials,
    tone: meta.tone || "var(--primary)",
    kind: rawUser.kind || "member",
    role: rawUser.role || "Member",
    roles: rawUser.roles || ["Member"],
    permissions: rawUser.permissions || []
  };
}

function App() {
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);

  // Member mode state
  const [user, setUser] = useState(DEFAULT_USER);
  const [splash, setSplash] = useState(false);
  const [auth, setAuth] = useState(false);
  const [tab, setTab] = useState("today");
  const [classSheet, setClassSheet] = useState(null);
  const [confirmed, setConfirmed] = useState(null);
  const [waitlist, setWaitlist] = useState(null);
  const [packagesOpen, setPackagesOpen] = useState(false);
  const [checkoutPkg, setCheckoutPkg] = useState(null);
  const [bankTransferPkg, setBankTransferPkg] = useState(null);
  const [purchaseSubmitted, setPurchaseSubmitted] = useState(null);
  const [settingsOpen, setSettingsOpen] = useState(false);

  // Admin mode state
  const [adminMode, setAdminMode] = useState(false);
  const [admin, setAdmin] = useState(window.NADI.CURRENT_ADMIN);
  const [adminTab, setAdminTab] = useState("now");
  const [adminSubRoute, setAdminSubRoute] = useState(null); // packages|classes|studios|accounts|payments|reports
  const [adminMember, setAdminMember] = useState(null);
  const [adminCoach, setAdminCoach] = useState(null);
  const [adminSession, setAdminSession] = useState(null);
  const [adminRoster, setAdminRoster] = useState(null);
  const [adminAddSession, setAdminAddSession] = useState(false);

  // Friend sheets
  const [findFriendsOpen, setFindFriendsOpen] = useState(false);
  const [friendProfile, setFriendProfile] = useState(null);

  // Toast
  const [toast, setToast] = useState(null);
  const showToast = (msg) => { setToast(msg); setTimeout(() => setToast(null), 2800); };

  // Schedule and bookings caches
  const [schedule, setSchedule] = useState(window.NADI.SCHEDULE);
  const [upcomingBookings, setUpcomingBookings] = useState([]);
  const [dataLoaded, setDataLoaded] = useState(false);

  window.NADI_SET_SCHEDULE = setSchedule;
  window.NADI_RELOAD_SCHEDULE = async () => {
    try {
      const res = await fetch("/api/schedule");
      if (res.ok) {
        const schData = await res.json();
        const mapped = schData.map((s) => {
          const [y, m, d] = s.date.split("-").map(Number);
          const dateObj = new Date(y, m - 1, d);
          const dayOfWeek = (dateObj.getDay() + 6) % 7;
          
          let roomShort = "Daun";
          if (s.room.includes("Akar") || s.room.includes("B")) {
            roomShort = "Akar";
          }
          
          return {
            id: s.id,
            day: dayOfWeek,
            date: s.date,
            time: s.time,
            classId: s.class_id,
            coachId: s.coach_id,
            room: s.room,
            roomShort: roomShort,
            capacity: s.capacity,
            booked: s.booked,
            friends: s.friends || [],
            anonCount: s.anonCount || 0,
            waitlistCount: s.waitlistCount || 0,
            attendedCount: s.attendedCount || 0
          };
        });
        window.NADI.SCHEDULE = mapped;
        setSchedule(mapped);
      }
    } catch (e) {
      console.error("Failed to reload schedule", e);
    }
  };

  const loadUserData = async (rawUser) => {
    const token = localStorage.getItem("nadi_token");
    const headers = token ? { "Authorization": `Bearer ${token}` } : {};
    
    let bookedIds = [];
    let historyList = [];
    let stats = {};
    
    try {
      const upcomingRes = await fetch("/api/bookings/upcoming", { headers });
      if (upcomingRes.ok) {
        const upcomingData = await upcomingRes.json();
        setUpcomingBookings(upcomingData);
        bookedIds = upcomingData.map(b => b.session_id);
      }
    } catch (e) {
      console.error(e);
    }
    
    try {
      const historyRes = await fetch("/api/bookings/history", { headers });
      if (historyRes.ok) {
        const historyData = await historyRes.json();
        historyList = historyData.map(h => ({
          id: h.id,
          date: new Date(h.date).toLocaleDateString("en-GB", { weekday: "short", day: "2-digit", month: "short" }),
          classId: h.class_id,
          coachId: h.coach_id,
          roomShort: h.room.includes("—") ? h.room.split("—")[1].trim() : h.room.includes("-") ? h.room.split("-")[1].trim() : h.room
        }));
      }
    } catch (e) {
      console.error(e);
    }
    
    try {
      const statsRes = await fetch("/api/user/stats", { headers });
      if (statsRes.ok) {
        stats = await statsRes.json();
      }
    } catch (e) {
      console.error(e);
    }
    
    const hydrated = hydrateUser({
      ...rawUser,
      booked: bookedIds,
      history: historyList,
    });
    
    if (stats.streak !== undefined) hydrated.streak = stats.streak;
    if (stats.visits !== undefined) hydrated.visits = stats.visits;
    if (stats.monthly !== undefined) hydrated.monthly = stats.monthly;
    
    setUser(hydrated);
    if (hydrated.kind === "admin") {
      setAdmin(hydrated);
    }
    return hydrated;
  };

  window.NADI_REFRESH_DATA = async () => {
    const token = localStorage.getItem("nadi_token");
    if (!token) return;
    try {
      const profileRes = await fetch("/api/user/profile", {
        headers: { "Authorization": `Bearer ${token}` }
      });
      if (profileRes.ok) {
        const rawUser = await profileRes.json();
        await loadUserData(rawUser);
      }
      await window.NADI_RELOAD_SCHEDULE();
    } catch (e) {
      console.error("Failed to refresh user data", e);
    }
  };

  const saveUserMetadata = async (updatedUser) => {
    const token = localStorage.getItem("nadi_token");
    if (!token) return;
    try {
      const payload = {
        streak: updatedUser.streak,
        bookingPrivacy: updatedUser.bookingPrivacy,
        visibleByDefault: updatedUser.visibleByDefault,
        savedClasses: updatedUser.savedClasses,
        savedCoaches: updatedUser.savedCoaches,
        following: updatedUser.following,
        pendingFollowers: updatedUser.pendingFollowers,
        sentRequests: updatedUser.sentRequests,
        monthly: updatedUser.monthly,
        tone: updatedUser.tone
      };
      await fetch("/api/user/metadata", {
        method: "PUT",
        headers: {
          "Content-Type": "application/json",
          "Authorization": `Bearer ${token}`
        },
        body: JSON.stringify(payload)
      });
    } catch (e) {
      console.error("Failed to save user metadata", e);
    }
  };

  const loadAdminData = async () => {
    const token = localStorage.getItem("nadi_token");
    const headers = token ? { "Authorization": `Bearer ${token}` } : {};
    
    try {
      const [mRes, pAllRes, pPendRes] = await Promise.all([
        fetch("/api/admin/members", { headers }),
        fetch("/api/admin/payments", { headers }),
        fetch("/api/admin/payments?status=pending", { headers })
      ]);
      
      if (mRes.ok) {
        const mData = await mRes.json();
        window.NADI_ADMIN.MEMBERS = mData.map(m => {
          const names = (m.name || "Member").split(" ");
          const initials = names.map(n => n[0]).slice(0, 2).join("").toUpperCase();
          return {
            id: m.id,
            name: m.name,
            email: m.email,
            phone: m.phone || "+62 812 1100 2030",
            joined: m.joined,
            status: m.status,
            visits: m.visits,
            credits: m.credits || 0,
            package: m.package || "—",
            lastVisit: m.last_visit || "—",
            initials: initials,
            tone: "#B5563C"
          };
        });
      }
      
      if (pAllRes.ok) {
        const pData = await pAllRes.json();
        window.NADI_ADMIN.PAYMENTS = pData.map(p => {
          const dt = p.created_at || "2026-05-05T12:00:00";
          return {
            id: p.id,
            date: dt.includes("T") ? dt.split("T")[0] : dt.split(" ")[0],
            time: dt.includes("T") ? dt.split("T")[1].slice(0, 5) : dt.split(" ")[1]?.slice(0, 5) || "12:00",
            member: p.user_name || "Member",
            memberId: p.user_id,
            item: p.package_name || "Package",
            amount: p.amount,
            method: p.method
          };
        });
      }
      
      if (pPendRes.ok) {
        const pendingData = await pPendRes.json();
        window.NADI_ADMIN.PACK_PURCHASES = pendingData.map(p => {
          const dt = p.created_at || "2026-05-05T12:00:00";
          const dateStr = dt.includes("T") ? dt.replace("T", " ").slice(0, 16) : dt.slice(0, 16);
          return {
            id: p.id,
            memberId: p.user_id,
            memberName: p.user_name || "Member",
            packageId: p.package_id,
            packageName: p.package_name || "Package",
            classes: p.package_classes || 5,
            validityDays: p.package_validity_days || 30,
            amount: p.amount,
            bankId: p.bank_id || "b1",
            submitted: dateStr,
            status: p.status,
            note: p.note || "",
            proof: p.proof
          };
        });
      }
    } catch (e) {
      console.error("Failed to load admin data", e);
    }
  };
  window.NADI_RELOAD_ADMIN_DATA = loadAdminData;

  // Load public data once
  useEffect(() => {
    const loadPublic = async () => {
      try {
        const [ctRes, coRes, pkgRes, stRes] = await Promise.all([
          fetch("/api/class-types"),
          fetch("/api/coaches"),
          fetch("/api/packages"),
          fetch("/api/studios")
        ]);

        if (ctRes.ok) window.NADI.CLASS_TYPES = await ctRes.json();
        if (coRes.ok) {
          const coData = await coRes.json();
          window.NADI.COACHES = coData.map(c => ({
            id: c.id,
            name: c.name,
            firstName: c.name.split(" ")[0],
            title: c.title || "",
            initials: c.name.split(" ").map(n => n[0]).join("").toUpperCase(),
            tone: c.id === "ayu" ? "#C28464" : c.id === "made" ? "#8A7E5C" : c.id === "kade" ? "#A14A2E" : "#6D7A53",
            bio: c.bio || "",
            specialties: c.specialties ? c.specialties.split(",") : [],
            yrs: c.yrs || 5,
            userId: c.user_id,
            rate: c.rate || 200000
          }));
        }
        if (pkgRes.ok) {
          const pkgData = await pkgRes.json();
          window.NADI.PACKAGES = pkgData.map(p => ({
            id: p.id,
            name: p.name,
            classes: p.classes,
            price: p.price,
            validityDays: p.validity_days || p.validityDays,
            badge: p.badge,
            desc: p.desc
          }));
        }
        if (stRes.ok) {
          const stData = await stRes.json();
          window.NADI.STUDIOS = stData.map(s => ({
            id: s.id,
            name: s.name.includes("—") ? s.name.split("—")[1].trim() : s.name,
            full: s.name,
            desc: s.style || ""
          }));
        }
        await window.NADI_RELOAD_SCHEDULE();
      } catch (e) {
        console.error("Failed to load public configuration data", e);
      } finally {
        setDataLoaded(true);
      }
    };
    window.NADI_RELOAD_PUBLIC = loadPublic;
    loadPublic();
  }, []);

  // Auto-login or show splash after public configuration is parsed
  useEffect(() => {
    if (!dataLoaded) return;
    const token = localStorage.getItem("nadi_token");
    if (token) {
      fetch("/api/user/profile", {
        headers: { "Authorization": `Bearer ${token}` }
      })
      .then(res => {
        if (res.ok) return res.json();
        throw new Error("Invalid session token");
      })
      .then(u => {
        loadUserData(u);
      })
      .catch(() => {
        localStorage.removeItem("nadi_token");
        setSplash(true);
      });
    } else {
      setSplash(true);
    }
  }, [dataLoaded]);

  useEffect(() => { applyAccent(t.accent || "#B5563C"); }, [t.accent]);

  // ── Member actions ────────────────────────────────────────
  const onConfirmBooking = async (session, privacy) => {
    setClassSheet(null);
    const token = localStorage.getItem("nadi_token");
    const headers = token ? { "Authorization": `Bearer ${token}` } : {};
    
    try {
      const res = await fetch("/api/bookings", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          ...headers
        },
        body: JSON.stringify({ session_id: session.id })
      });
      if (res.ok) {
        const nextPrivacy = { ...(user.bookingPrivacy || {}), [session.id]: privacy };
        const nextUser = {
          ...user,
          bookingPrivacy: nextPrivacy,
          booked: [...new Set([...(user.booked || []), session.id])],
        };
        setUser(nextUser);
        setConfirmed(session);
        await saveUserMetadata(nextUser);
        
        const profileRes = await fetch("/api/user/profile", { headers });
        if (profileRes.ok) {
          const rawUser = await profileRes.json();
          await loadUserData(rawUser);
        }
        await window.NADI_RELOAD_SCHEDULE();
      } else {
        const errData = await res.json();
        showToast(errData.detail || "Failed to book class");
      }
    } catch (e) {
      console.error(e);
      showToast("Network error occurred.");
    }
  };

  const onCancelBooking = async (session) => {
    const booking = upcomingBookings.find((b) => b.id === session.bookingId)
                 || upcomingBookings.find((b) => b.session_id === session.id);
    if (!booking) {
      setUser({ ...user, booked: (user.booked || []).filter((id) => id !== session.id) });
      showToast("Booking cancelled.");
      return;
    }
    
    const token = localStorage.getItem("nadi_token");
    const headers = token ? { "Authorization": `Bearer ${token}` } : {};
    
    try {
      const res = await fetch(`/api/bookings/${booking.id}`, {
        method: "DELETE",
        headers: headers
      });
      if (res.ok) {
        showToast("Booking cancelled — credit refunded.");
        const profileRes = await fetch("/api/user/profile", { headers });
        if (profileRes.ok) {
          const rawUser = await profileRes.json();
          await loadUserData(rawUser);
        }
        await window.NADI_RELOAD_SCHEDULE();
      } else {
        const errData = await res.json();
        showToast(errData.detail || "Failed to cancel booking");
      }
    } catch (e) {
      console.error(e);
      showToast("Network error occurred.");
    }
  };

  const handleContinueAsSinta = async () => {
    try {
      const res = await fetch("/api/auth/signin", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ email: "sinta@mail.com", password: "password123" }),
      });
      if (res.ok) {
        const data = await res.json();
        localStorage.setItem("nadi_token", data.access_token);
        await loadUserData(data.user);
        setSplash(false);
        setTab("me");
      } else {
        setSplash(false);
        setUser(window.NADI.CURRENT_USER);
        setTab("me");
      }
    } catch (e) {
      setSplash(false);
      setUser(window.NADI.CURRENT_USER);
      setTab("me");
    }
  };

  const onJoinWaitlist = (session) => {
    const nextUser = { ...user, waitlist: [...new Set([...(user.waitlist || []), session.id])] };
    setUser(nextUser);
    showToast("Added to the waitlist. We'll text you.");
    saveUserMetadata(nextUser);
  };

  const onChoosePackage = (pkg) => { setPackagesOpen(false); setCheckoutPkg(pkg); };
  const onConfirmCheckout = (pkg) => {
    setCheckoutPkg(null);
    setBankTransferPkg(pkg);
  };

  const onSubmitBankTransfer = async ({ pkg, bankId, proof, note }) => {
    const token = localStorage.getItem("nadi_token");
    const headers = token ? { "Authorization": `Bearer ${token}` } : {};
    
    try {
      const res = await fetch("/api/checkout", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          ...headers
        },
        body: JSON.stringify({
          package_id: pkg.id,
          method: "Bank Transfer",
          proof: proof ? proof.dataUrl : null,
          note: note || ""
        })
      });
      if (res.ok) {
        setBankTransferPkg(null);
        setPurchaseSubmitted(pkg);
      } else {
        const errData = await res.json();
        showToast(errData.detail || "Failed to submit transfer proof");
      }
    } catch (e) {
      console.error(e);
      showToast("Network error occurred.");
    }
  };

  const toggleSavedClass = (id) => {
    const has = user.savedClasses.includes(id);
    const nextUser = { ...user, savedClasses: has ? user.savedClasses.filter((x) => x !== id) : [...user.savedClasses, id] };
    setUser(nextUser);
    showToast(has ? "Removed from saved." : "Saved.");
    saveUserMetadata(nextUser);
  };

  const toggleSavedCoach = (id) => {
    const has = user.savedCoaches.includes(id);
    const nextUser = { ...user, savedCoaches: has ? user.savedCoaches.filter((x) => x !== id) : [...user.savedCoaches, id] };
    setUser(nextUser);
    showToast(has ? "Removed teacher." : "Teacher saved.");
    saveUserMetadata(nextUser);
  };

  // ── Friends actions ───────────────────────────────────────
  const sendFriendRequest = (id) => {
    if (user.sentRequests.includes(id)) return;
    const nextUser = { ...user, sentRequests: [...user.sentRequests, id] };
    setUser(nextUser);
    showToast("Request sent.");
    saveUserMetadata(nextUser);
  };

  const acceptFriendRequest = (id) => {
    const nextUser = {
      ...user,
      following: [...user.following, id],
      pendingFollowers: user.pendingFollowers.filter((x) => x !== id),
    };
    setUser(nextUser);
    showToast("Now following.");
    saveUserMetadata(nextUser);
  };

  const declineFriendRequest = (id) => {
    const nextUser = { ...user, pendingFollowers: user.pendingFollowers.filter((x) => x !== id) };
    setUser(nextUser);
    showToast("Request declined.");
    saveUserMetadata(nextUser);
  };

  const unfollowFriend = (id) => {
    const nextUser = { ...user, following: user.following.filter((x) => x !== id) };
    setUser(nextUser);
    showToast("Unfollowed.");
    saveUserMetadata(nextUser);
  };

  // ── Admin actions ─────────────────────────────────────────
  const enterAdmin = async () => {
    await loadAdminData();
    setAdminMode(true);
    setAdminTab("now");
    setAdminSubRoute(null);
  };

  const exitAdmin = () => { setAdminMode(false); setTab("today"); };

  const badges = useMemo(() => ({ today: (user.booked || []).length > 0 ? 1 : 0 }), [user.booked]);

  // ── SPLASH / AUTH ─────────────────────────────────────────
  if (splash) return (
    <>
      {t.showStatusBar && <StatusBar />}
      <SplashScreen
        onContinue={handleContinueAsSinta}
        onSignIn={() => { setSplash(false); setAuth(true); }}
        onAuth={async (u) => { setSplash(false); await loadUserData(u); setTab("me"); showToast(`Signed in as ${(u.name || "Member").split(" ")[0]}.`); }}
      />
      <TweaksHost {...{ t, setTweak, setTab, setSplash, setAuth, setPackagesOpen, enterAdmin, adminMode }} />
    </>
  );
  if (auth) return (
    <>
      {t.showStatusBar && <StatusBar />}
      <SignInScreen onClose={() => { setAuth(false); setSplash(true); }} onAuth={async (u) => { setAuth(false); await loadUserData(u); setTab("me"); showToast(`Signed in as ${(u.name || "Member").split(" ")[0]}.`); }} />
      <TweaksHost {...{ t, setTweak, setTab, setSplash, setAuth, setPackagesOpen, enterAdmin, adminMode }} />
    </>
  );

  // ── ADMIN SHELL ───────────────────────────────────────────
  if (adminMode) {
    return (
      <>
        {t.showStatusBar && <StatusBar />}
        <AdminTopStrip admin={admin} onExitAdmin={exitAdmin} />

        <div style={{
          position: "absolute", left: 0, right: 0,
          top: (t.showStatusBar ? 28 : 0) + 41,  // status bar + admin strip
          bottom: 0,
          display: "flex", flexDirection: "column",
          paddingBottom: "calc(var(--nav-h) + var(--safe-bot))",
          overflow: "hidden",
        }}>
          {adminSubRoute ? <AdminSubRoute route={adminSubRoute} onBack={() => setAdminSubRoute(null)} openMember={setAdminMember} openCoach={setAdminCoach} showToast={showToast} />
            : adminTab === "now" && <AdminNowScreen admin={admin} openMember={setAdminMember} openSession={setAdminSession} />}
          {!adminSubRoute && adminTab === "schedule" && <AdminScheduleScreen openSession={setAdminSession} openAddSession={() => setAdminAddSession(true)} showToast={showToast} />}
          {!adminSubRoute && adminTab === "people" && <AdminPeopleScreen openMember={setAdminMember} openCoach={setAdminCoach} showToast={showToast} />}
          {!adminSubRoute && adminTab === "more" && <AdminMoreScreen admin={admin} openSection={setAdminSubRoute} onExitAdmin={exitAdmin} showToast={showToast} />}
        </div>

        <AdminTabBar tab={adminTab} setTab={(t) => { setAdminTab(t); setAdminSubRoute(null); }} />

        {/* Admin sheets */}
        <AdminMemberSheet member={adminMember} onClose={() => setAdminMember(null)} showToast={showToast} />
        <AdminCoachSheet coach={adminCoach} onClose={() => setAdminCoach(null)} showToast={showToast} />
        <AdminSessionSheet session={adminSession} onClose={() => setAdminSession(null)} showToast={showToast} openRoster={(s) => { setAdminSession(null); setAdminRoster(s); }} />
        <AdminRosterSheet session={adminRoster} onClose={() => setAdminRoster(null)} openMember={setAdminMember} showToast={showToast} />
        <AdminAddSessionSheet open={adminAddSession} onClose={() => setAdminAddSession(false)} showToast={showToast} />

        <Toast msg={toast} />
        <TweaksHost {...{ t, setTweak, setTab, setSplash, setAuth, setPackagesOpen, enterAdmin, adminMode, setAdminMode: (v) => { setAdminMode(v); if (!v) setTab("today"); }, setAdminTab, setAdminSubRoute }} />
      </>
    );
  }

  // ── MEMBER SHELL ──────────────────────────────────────────
  return (
    <>
      {t.showStatusBar && <StatusBar />}
      <div style={{
        position: "absolute", left: 0, right: 0,
        top: t.showStatusBar ? 28 : 0,
        bottom: 0,
        display: "flex", flexDirection: "column",
        paddingBottom: "calc(var(--nav-h) + var(--safe-bot))",
      }}>
        {tab === "today" && <TodayScreen
          user={user}
          setUser={setUser}
          openClassSheet={(s) => setClassSheet(s)}
          setTab={setTab}
          openCheckout={() => setPackagesOpen(true)}
          showToast={showToast}
          onCancelBooking={onCancelBooking}
          upcomingBookings={upcomingBookings}
        />}
        {tab === "book" && <BookScreen user={user} openClassSheet={setClassSheet} setTab={setTab} upcomingBookings={upcomingBookings} />}
        {tab === "saved" && <SavedScreen
          user={user} openClassSheet={setClassSheet}
          toggleSavedClass={toggleSavedClass} toggleSavedCoach={toggleSavedCoach}
          setTab={setTab}
          openFindFriends={() => setFindFriendsOpen(true)}
          openFriendProfile={setFriendProfile}
          unfollowFriend={unfollowFriend}
        />}
        {tab === "me" && <MeScreen
          user={user}
          setUser={setUser}
          setTab={setTab}
          openCheckout={() => setPackagesOpen(true)}
          onSignOut={() => { localStorage.removeItem("nadi_token"); setUser(DEFAULT_USER); setSplash(true); }}
          openSettings={() => setSettingsOpen(true)}
          showToast={showToast}
          enterAdmin={user.kind === "admin" ? enterAdmin : null}
          upcomingBookings={upcomingBookings}
        />}
      </div>

      <TabBar tab={tab} setTab={setTab} badges={badges} />

      {/* Member sheets and overlays */}
      <ClassSheet session={classSheet} user={user} onClose={() => setClassSheet(null)}
        onBookConfirmed={onConfirmBooking}
        onWaitlist={(s) => { setClassSheet(null); setWaitlist(s); }}
        onBuyPack={() => { setClassSheet(null); setPackagesOpen(true); }}
        toggleSavedClass={toggleSavedClass} toggleSavedCoach={toggleSavedCoach}
        openFriendProfile={(f) => { setClassSheet(null); setFriendProfile(f); }}
      />
      <BookingConfirmed open={!!confirmed} session={confirmed} onClose={() => setConfirmed(null)} />
      <WaitlistSheet open={!!waitlist} session={waitlist} onClose={() => setWaitlist(null)} onConfirm={onJoinWaitlist} />
      <PackagesSheet open={packagesOpen} onClose={() => setPackagesOpen(false)} onChoose={onChoosePackage} />
      <CheckoutSheet pkg={checkoutPkg} onClose={() => setCheckoutPkg(null)} onConfirm={onConfirmCheckout} />
      <BankTransferSheet pkg={bankTransferPkg} onClose={() => setBankTransferPkg(null)} onSubmit={onSubmitBankTransfer} />
      <PurchaseSubmittedSheet open={!!purchaseSubmitted} pkg={purchaseSubmitted} onClose={() => setPurchaseSubmitted(null)} />
      <SettingsSheet
        open={settingsOpen}
        onClose={() => setSettingsOpen(false)}
        onSignOut={() => { localStorage.removeItem("nadi_token"); setSettingsOpen(false); setUser(DEFAULT_USER); setSplash(true); }}
        user={user} setUser={setUser} showToast={showToast}
      />

      <FindFriendsSheet
        open={findFriendsOpen}
        onClose={() => setFindFriendsOpen(false)}
        user={user}
        sendRequest={sendFriendRequest}
        openFriendProfile={(f) => { setFindFriendsOpen(false); setFriendProfile(f); }}
        showToast={showToast}
      />
      <FriendProfileSheet
        friend={friendProfile}
        user={user}
        onClose={() => setFriendProfile(null)}
        sendRequest={sendFriendRequest}
        acceptRequest={acceptFriendRequest}
        declineRequest={declineFriendRequest}
        unfollowFriend={unfollowFriend}
        showToast={showToast}
      />

      <Toast msg={toast} />

      <TweaksHost {...{ t, setTweak, setTab, setSplash, setAuth, setPackagesOpen, enterAdmin, adminMode, setAdminMode: (v) => { setAdminMode(v); if (!v) setTab("today"); }, setAdminTab, setAdminSubRoute }} />
    </>
  );
}

// ── Admin sub-routes (packages, classes, studios, accounts, payments, reports) ─
function AdminSubRoute({ route, onBack, openMember, openCoach, showToast }) {
  switch (route) {
    case "packages": return <AdminPackagesScreen onBack={onBack} showToast={showToast} />;
    case "classes":  return <AdminClassTypesScreen onBack={onBack} showToast={showToast} />;
    case "studios":  return <AdminStudiosScreen onBack={onBack} showToast={showToast} />;
    case "accounts": return <AdminAccountsScreen onBack={onBack} showToast={showToast} />;
    case "payments": return <AdminPaymentsScreen onBack={onBack} openMember={openMember} />;
    case "reports":  return <AdminReportsScreen onBack={onBack} openCoach={openCoach} openMember={openMember} />;
    case "banks":    return <AdminBankAccountsScreen onBack={onBack} showToast={showToast} />;
    case "purchases":return <AdminPackPurchasesScreen onBack={onBack} openMember={openMember} showToast={showToast} />;
    default: return null;
  }
}

function TweaksHost({ t, setTweak, setTab, setSplash, setAuth, setPackagesOpen, enterAdmin, adminMode, setAdminMode, setAdminTab, setAdminSubRoute }) {
  return (
    <TweaksPanel>
      <TweakSection label="Aesthetic" />
      <TweakColor
        label="Accent"
        value={t.accent}
        options={["#B5563C", "#9A3A22", "#5A6E47", "#D7864D", "#C26B22", "#3B6E8F"]}
        onChange={(v) => setTweak("accent", v)}
      />
      <TweakToggle label="Phone status bar" value={t.showStatusBar} onChange={(v) => setTweak("showStatusBar", v)} />
      <TweakToggle label="Show friends going" value={t.showFriends} onChange={(v) => setTweak("showFriends", v)} />

      <TweakSection label="Member tabs" />
      <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 6 }}>
        {[["today", "Today"], ["book", "Book"], ["saved", "Saved"], ["me", "Me"]].map(([k, l]) => (
          <button key={k} onClick={() => { setSplash(false); setAuth(false); if (setAdminMode) setAdminMode(false); setTab(k); }} style={{
            padding: "7px 10px", background: "transparent", color: "var(--ink)",
            border: "1px solid var(--rule)",
            fontFamily: "Geist, sans-serif", fontSize: 11,
            letterSpacing: "0.04em", textTransform: "uppercase", cursor: "pointer",
          }}>{l}</button>
        ))}
      </div>

      <TweakSection label="Staff mode" />
      {!adminMode ? (
        <TweakButton label="Enter staff mode →" onClick={enterAdmin} />
      ) : (
        <>
          <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 6 }}>
            {[["now", "Now"], ["schedule", "Schedule"], ["people", "People"], ["more", "More"]].map(([k, l]) => (
              <button key={k} onClick={() => { setAdminTab && setAdminTab(k); setAdminSubRoute && setAdminSubRoute(null); }} style={{
                padding: "7px 10px", background: "transparent", color: "var(--ink)",
                border: "1px solid var(--rule)",
                fontFamily: "Geist, sans-serif", fontSize: 11,
                letterSpacing: "0.04em", textTransform: "uppercase", cursor: "pointer",
              }}>{l}</button>
            ))}
          </div>
          <div style={{ marginTop: 6, display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 6 }}>
            {[["packages","Packs"],["classes","Class types"],["studios","Studios"],["accounts","Accounts"],["payments","Payments"],["reports","Reports"],["banks","Bank acct"],["purchases","Purchases"]].map(([k, l]) => (
              <button key={k} onClick={() => { setAdminTab && setAdminTab("more"); setAdminSubRoute && setAdminSubRoute(k); }} style={{
                padding: "5px 6px", background: "transparent", color: "var(--ink)",
                border: "1px solid var(--rule)",
                fontFamily: "Geist, sans-serif", fontSize: 10,
                letterSpacing: "0.02em", textTransform: "uppercase", cursor: "pointer",
              }}>{l}</button>
            ))}
          </div>
          <div style={{ marginTop: 6 }}>
            <TweakButton label="Exit to member view" onClick={() => setAdminMode && setAdminMode(false)} />
          </div>
        </>
      )}

      <TweakSection label="Flows" />
      <TweakButton label="Show splash" onClick={() => { setSplash(true); setAuth(false); }} />
      <TweakButton label="Open sign-in" onClick={() => { setSplash(false); setAuth(true); }} />
      <TweakButton label="Open packages sheet" onClick={() => setPackagesOpen(true)} />
    </TweaksPanel>
  );
}

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