// ─────────────────────────────────────────────────────────────────────────────
// HIT ZERO WEB — App shell, router, auth gate
// Sidebar nav, topbar with role switcher + command search, routed main
// ─────────────────────────────────────────────────────────────────────────────
const { useState, useEffect, useRef, useMemo, useCallback } = React;

// ─── Role-aware nav config ───
const NAV_CONFIG = {
  coach: [
    { group: 'Practice' },
    { id: 'today',        label: 'Today',           icon: 'today' },
    { id: 'roster',       label: 'Roster',          icon: 'roster' },
    { id: 'skills',       label: 'Skill Matrix',    icon: 'skills' },
    { id: 'practice',     label: 'Practice Plans',  icon: 'routine' },
    { group: 'Routine' },
    { id: 'routine',      label: 'Routine Builder', icon: 'routine' },
    { id: 'score',        label: 'Mock Score',      icon: 'score' },
    { id: 'ai_judge',     label: 'AI Judge',        icon: 'bolt' },
    { id: 'forms',        label: 'Evaluations',     icon: 'skills' },
    { group: 'Program' },
    { id: 'schedule',     label: 'Schedule',        icon: 'calendar' },
    { id: 'messages',     label: 'Messages',        icon: 'megaphone' },
    { id: 'announcements',label: 'Announcements',   icon: 'megaphone' },
    { id: 'volunteers',   label: 'Volunteers',      icon: 'roster' },
    { id: 'medical',      label: 'Medical',         icon: 'bolt' },
  ],
  owner: [
    { group: 'Overview' },
    { id: 'today',        label: 'Today',           icon: 'today' },
    { id: 'profile',      label: 'My Account',      icon: 'home' },
    { id: 'admin',        label: 'Program',         icon: 'admin' },
    { id: 'billing',      label: 'Billing',         icon: 'billing' },
    { id: 'leads',        label: 'Leads',           icon: 'roster' },
    { group: 'Teams' },
    { id: 'roster',       label: 'Roster',          icon: 'roster' },
    { id: 'skills',       label: 'Skill Matrix',    icon: 'skills' },
    { id: 'routine',      label: 'Routine',         icon: 'routine' },
    { id: 'score',        label: 'Mock Score',      icon: 'score' },
    { id: 'ai_judge',     label: 'AI Judge',        icon: 'bolt' },
    { id: 'forms',        label: 'Evaluations',     icon: 'skills' },
    { id: 'uniforms',     label: 'Uniforms',        icon: 'roster' },
    { group: 'Communications' },
    { id: 'messages',     label: 'Messages',        icon: 'megaphone' },
    { id: 'announcements',label: 'Announcements',   icon: 'megaphone' },
    { id: 'schedule',     label: 'Schedule',        icon: 'calendar' },
    { id: 'volunteers',   label: 'Volunteers',      icon: 'roster' },
    { id: 'medical',      label: 'Medical',         icon: 'bolt' },
    { id: 'registration', label: 'Registration',    icon: 'plus' },
  ],
  athlete: [
    { group: 'My Cheer' },
    { id: 'reel',         label: 'My Reel',         icon: 'reel' },
    { id: 'pins',         label: 'Pins',            icon: 'star' },
    { id: 'skilltree',    label: 'Skill Tree',      icon: 'skills' },
    { id: 'routine',      label: 'My Routine',      icon: 'routine' },
    { id: 'ai_judge',     label: 'AI Judge',        icon: 'bolt' },
    { group: 'Team' },
    { id: 'schedule',     label: 'Schedule',        icon: 'calendar' },
    { id: 'messages',     label: 'Messages',        icon: 'megaphone' },
    { id: 'announcements',label: 'Team Feed',       icon: 'megaphone' },
    { id: 'volunteers',   label: 'Volunteers',      icon: 'roster' },
  ],
  parent: [
    { group: "Kid's World" },
    { id: 'parent',       label: 'Overview',        icon: 'home' },
    { id: 'reel',         label: 'Reel',            icon: 'reel' },
    { id: 'skilltree',    label: 'Skills',          icon: 'skills' },
    { id: 'ai_judge',     label: 'AI Judge',        icon: 'bolt' },
    { group: 'Family' },
    { id: 'billing',      label: 'Billing',         icon: 'billing' },
    { id: 'schedule',     label: 'Schedule',        icon: 'calendar' },
    { id: 'messages',     label: 'Messages',        icon: 'megaphone' },
    { id: 'announcements',label: 'Gym Feed',        icon: 'megaphone' },
    { id: 'uniforms',     label: 'Uniforms',        icon: 'roster' },
    { id: 'volunteers',   label: 'Volunteers',      icon: 'roster' },
    { id: 'medical',      label: 'Medical',         icon: 'bolt' },
  ],
};

// Map screen id → component name (resolved via window[name])
const SCREEN_MAP = {
  today: 'CoachToday',
  roster: 'Roster',
  skills: 'SkillMatrix',
  routine: 'RoutineBuilder',
  score: 'MockScore',
  sessions: 'Sessions',
  messages: 'Messages',
  announcements: 'Announcements',
  admin: 'AdminConsole',
  billing: 'Billing',
  profile: 'OwnerProfile',
  reel: 'AthleteReel',
  pins: 'PinsHub',
  skilltree: 'SkillTree',
  parent: 'ParentDashboard',
  // Tier 1 / Tier 2 additions
  schedule: 'Schedule',
  uniforms: 'Uniforms',
  leads: 'Leads',
  forms: 'Forms',
  volunteers: 'Volunteers',
  practice: 'PracticePlans',
  medical: 'MedicalHub',
  registration: 'Registration',
  ai_judge: 'AIJudge',
};

const ROLE_LABELS = {
  owner: 'Gym Owner',
  coach: 'Coach',
  parent: 'Parent',
  athlete: 'Athlete',
};
const WALKTHROUGH_VERSION = 'v2';

function roleNav(role) {
  return NAV_CONFIG[role] || NAV_CONFIG.coach;
}

// ─── Mobile bottom-tab-bar config (4 thumb-reachable + "More") ───
const MOBILE_TABS = {
  owner:   [
    { id: 'today',    label: 'Today',    icon: 'today' },
    { id: 'admin',    label: 'Program',  icon: 'admin' },
    { id: 'roster',   label: 'Roster',   icon: 'roster' },
    { id: 'schedule', label: 'Schedule', icon: 'calendar' },
    { id: '__more',   label: 'More',     icon: 'skills' },
  ],
  coach:   [
    { id: 'today',    label: 'Today',    icon: 'today' },
    { id: 'roster',   label: 'Roster',   icon: 'roster' },
    { id: 'schedule', label: 'Schedule', icon: 'calendar' },
    { id: 'routine',  label: 'Routine',  icon: 'routine' },
    { id: '__more',   label: 'More',     icon: 'skills' },
  ],
  athlete: [
    { id: 'reel',      label: 'Reel',     icon: 'reel' },
    { id: 'skilltree', label: 'Skills',   icon: 'skills' },
    { id: 'pins',      label: 'Pins',     icon: 'star' },
    { id: 'schedule',  label: 'Schedule', icon: 'calendar' },
    { id: '__more',    label: 'More',     icon: 'skills' },
  ],
  parent:  [
    { id: 'parent',   label: 'Home',     icon: 'home' },
    { id: 'schedule', label: 'Schedule', icon: 'calendar' },
    { id: 'billing',  label: 'Billing',  icon: 'billing' },
    { id: 'reel',     label: 'Reel',     icon: 'reel' },
    { id: '__more',   label: 'More',     icon: 'skills' },
  ],
};

function useIsMobile(breakpoint = 768) {
  const [m, setM] = React.useState(() => typeof window !== 'undefined' && window.innerWidth <= breakpoint);
  React.useEffect(() => {
    const mq = window.matchMedia(`(max-width: ${breakpoint}px)`);
    const onChange = () => setM(mq.matches);
    mq.addEventListener ? mq.addEventListener('change', onChange) : mq.addListener(onChange);
    setM(mq.matches);
    return () => {
      mq.removeEventListener ? mq.removeEventListener('change', onChange) : mq.removeListener(onChange);
    };
  }, [breakpoint]);
  return m;
}
window.useIsMobile = useIsMobile;

function navIdsForRole(role) {
  return new Set(roleNav(role).filter(item => item.id).map(item => item.id));
}

function firstRouteForRole(role) {
  return roleNav(role).find(item => item.id)?.id || 'today';
}

// ─── Top-level App ───
function App() {
  const [session, setSession] = useState(() => window.HZdb.auth._getSession());
  const [authReady, setAuthReady] = useState(() => !window.HZdb.auth._init);
  const [snap, setSnap] = useState(null);
  const [route, setRoute] = useState(() => {
    const h = location.hash.slice(1);
    return h || 'today';
  });
  const [toasts, setToasts] = useState([]);
  const [cmdkOpen, setCmdkOpen] = useState(false);
  const [drawerAthleteId, setDrawerAthleteId] = useState(null);
  const [sidebarOpen, setSidebarOpen] = useState(false);
  const [moreSheetOpen, setMoreSheetOpen] = useState(false);
  const [walkthroughRole, setWalkthroughRole] = useState(null);
  const isMobile = useIsMobile(768);

  useEffect(() => {
    let live = true;
    if (!window.HZdb.auth._init) return undefined;
    window.HZdb.auth._init()
      .then((nextSession) => {
        if (!live) return;
        setSession(nextSession);
        setAuthReady(true);
      })
      .catch((err) => {
        console.warn('[HZ] auth boot failed', err);
        if (live) setAuthReady(true);
      });
    return () => { live = false; };
  }, []);

  // Auth subscribe
  useEffect(() => {
    const { data: sub } = window.HZdb.auth.onAuthStateChange((evt, s) => setSession(s));
    return () => sub.subscription.unsubscribe();
  }, []);

  // Snapshot DB → re-run on any mutation via realtime
  const refreshSnapshot = useCallback(async () => {
    const s = await window.HZsel.snapshot();
    setSnap({ ...s, _tick: Date.now() });
  }, []);

  useEffect(() => {
    refreshSnapshot();
    const onManualRefresh = () => refreshSnapshot();
    window.addEventListener('hz:refresh', onManualRefresh);
    const ch = window.HZdb.channel('app-all')
      .on('postgres_changes', { table: '*' }, () => refreshSnapshot())
      .subscribe();
    // subscribe to every table we care about
    ['athlete_skills','celebrations','attendance','routine_sections','sessions','billing_accounts','billing_charges','announcements','score_runs','program_tracks','program_classes','athletes','programs','program_payment_settings'].forEach(t => {
      window.HZdb.channel('t-' + t).on('postgres_changes', { table: t }, () => refreshSnapshot()).subscribe();
    });
    return () => {
      window.removeEventListener('hz:refresh', onManualRefresh);
      ch.unsubscribe();
    };
  }, [refreshSnapshot]);

  // Hash router
  useEffect(() => {
    const onHash = () => setRoute(location.hash.slice(1) || 'today');
    window.addEventListener('hashchange', onHash);
    return () => window.removeEventListener('hashchange', onHash);
  }, []);

  const effectiveRole = session?.profile?.role || 'coach';

  useEffect(() => {
    if (!session?.profile) return;
    const key = `hz_walkthrough_${WALKTHROUGH_VERSION}_${session.profile.id}_${effectiveRole}`;
    try {
      if (!localStorage.getItem(key)) setWalkthroughRole(effectiveRole);
    } catch {}
  }, [session?.profile?.id, effectiveRole]);

  const closeWalkthrough = useCallback((markDone = true) => {
    if (markDone && session?.profile?.id && walkthroughRole) {
      try { localStorage.setItem(`hz_walkthrough_${WALKTHROUGH_VERSION}_${session.profile.id}_${walkthroughRole}`, 'done'); } catch {}
    }
    setWalkthroughRole(null);
  }, [session?.profile?.id, walkthroughRole]);

  useEffect(() => {
    if (!session) return;
    // Public booking route is allowed for anyone (signed-in too — they can
    // still help a friend book). Don't bounce them out.
    if (route && (route.startsWith('book/') || route.startsWith('trial/'))) return;
    const allowed = navIdsForRole(effectiveRole);
    if (allowed.has(route)) return;
    const next = firstRouteForRole(effectiveRole);
    if (location.hash.slice(1) !== next) location.hash = '#' + next;
    else setRoute(next);
  }, [session, effectiveRole, route]);

  // First-login redirect: owners landing with must_change_password = true
  // get pushed to the Profile screen so they hit the password form + Square
  // wizard before anything else.
  useEffect(() => {
    if (!session?.user) return;
    if (effectiveRole !== 'owner') return;
    if (session.user.user_metadata?.must_change_password !== true) return;
    const key = `hz_first_login_redirect_${session.profile.id}`;
    try {
      if (localStorage.getItem(key)) return;
      localStorage.setItem(key, 'done');
    } catch {}
    if (location.hash.slice(1) !== 'profile') location.hash = '#profile';
  }, [session?.user?.id, effectiveRole]);

  // CmdK open
  useEffect(() => {
    const onKey = (e) => {
      if ((e.metaKey || e.ctrlKey) && e.key === 'k') { e.preventDefault(); setCmdkOpen(v => !v); }
      if (e.key === 'Escape') setCmdkOpen(false);
    };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, []);

  // Toast helper
  const pushToast = useCallback((t) => {
    const id = Math.random().toString(36).slice(2);
    setToasts(prev => [...prev, { ...t, id }]);
  }, []);
  window.HZToast = pushToast;

  // Celebration: when athlete_skills flips up, toast it
  useEffect(() => {
    if (!snap) return;
    const ch = window.HZdb.channel('celebrate-' + Date.now())
      .on('postgres_changes', { table: 'athlete_skills' }, (evt) => {
        if (evt.eventType !== 'UPDATE') return;
        const o = evt.old, n = evt.new;
        if (!o || !n) return;
        const order = ['none','working','got_it','mastered'];
        if (order.indexOf(n.status) <= order.indexOf(o.status)) return;
        const a = snap.athletes.find(x => x.id === n.athlete_id);
        const s = snap.skills.find(x => x.id === n.skill_id);
        if (!a || !s) return;
        pushToast({
          variant: n.status,
          eyebrow: n.status === 'mastered' ? 'Mastered' : 'Progress',
          title: `${a.display_name} → ${s.name}`,
          body: n.status === 'mastered' ? 'Added to program highlights' : 'Working → Got it',
        });
        // Also record celebration row
        window.HZdb.from('celebrations').insert({
          team_id: a.team_id,
          athlete_id: a.id,
          kind: 'skill_progress',
          skill_id: s.id,
          from_status: o.status,
          to_status: n.status,
          headline: `${a.display_name.split(' ')[0]} ${n.status === 'mastered' ? 'mastered' : 'got'} ${s.name}`,
          created_at: new Date().toISOString(),
        });
      })
      .subscribe();
    return () => ch.unsubscribe();
  }, [snap?.athletes?.length, pushToast]);

  // Public booking route — pre-auth, no session required.
  // Triggered when the marketing site sends a parent here via
  //   https://hit-zero.vercel.app/#book/<class_id>
  if (route && route.startsWith('book/')) {
    const bookingClassId = route.slice(5).split('?')[0];
    if (bookingClassId && window.PublicBooking) {
      return <window.PublicBooking classId={bookingClassId} />;
    }
  }

  // Public free-trial / lead-capture route. Same pattern, different shape:
  //   https://hit-zero.vercel.app/#trial/<gym_slug>
  if (route && route.startsWith('trial/')) {
    const gymSlug = route.slice(6).split('?')[0] || 'mca';
    if (window.PublicTrial) {
      return <window.PublicTrial gymSlug={gymSlug} />;
    }
  }

  if (!authReady) {
    return <div style={{ color: 'var(--hz-dim)', padding: 40 }}>Loading…</div>;
  }

  // Not signed in → login
  if (!session) return <Login onIn={() => {}} />;

  const role = effectiveRole;
  const nav = roleNav(role);
  const screenId = navIdsForRole(role).has(route) ? route : firstRouteForRole(role);
  const ScreenName = SCREEN_MAP[screenId] || 'CoachToday';
  const Screen = window[ScreenName];

  const navigate = (id) => { location.hash = '#' + id; };

  // Find the human-readable label for the current screen (used in mobile top bar).
  const currentNavItem = nav.find(it => it.id === screenId);
  const screenLabel = currentNavItem?.label || screenId;

  return (
    <div className={'app-shell' + (isMobile ? ' app-shell--mobile' : '')}>
      {!isMobile && (
        <>
          <Sidebar
            nav={nav} active={screenId} session={session}
            snap={snap}
            open={sidebarOpen}
            onNav={(id) => { location.hash = '#' + id; setSidebarOpen(false); }}
          />
          {sidebarOpen && <div className="sidebar-backdrop" onClick={() => setSidebarOpen(false)}/>}
          <Topbar
            session={session}
            onOpenCmdk={() => setCmdkOpen(true)}
            onSignOut={async () => { await window.HZdb.auth.signOut(); }}
            onHamburger={() => setSidebarOpen(true)}
            onHelp={() => setWalkthroughRole(effectiveRole)}
            snap={snap}
          />
        </>
      )}
      {isMobile && (
        <MobileTopBar
          title={screenLabel}
          onSignOut={async () => { await window.HZdb.auth.signOut(); }}
          session={session}
          snap={snap}
        />
      )}

      <div className="main hz-rise" key={screenId}>
        {Screen && snap ? (
          <ScreenErrorBoundary screenId={screenId} navigate={navigate}>
            <Screen
              session={session}
              snap={snap}
              pushToast={pushToast}
              openAthlete={setDrawerAthleteId}
              navigate={navigate}
            />
          </ScreenErrorBoundary>
        ) : (
          <div style={{ color: 'var(--hz-dim)', padding: 40 }}>Loading…</div>
        )}
      </div>

      {isMobile && (
        <MobileTabBar
          role={effectiveRole}
          active={screenId}
          onNav={(id) => {
            if (id === '__more') setMoreSheetOpen(true);
            else { navigate(id); setMoreSheetOpen(false); }
          }}
        />
      )}
      {isMobile && moreSheetOpen && (
        <MobileMoreSheet
          nav={nav}
          active={screenId}
          tabIds={(MOBILE_TABS[effectiveRole] || []).map(t => t.id)}
          onNav={(id) => { navigate(id); setMoreSheetOpen(false); }}
          onClose={() => setMoreSheetOpen(false)}
          onSignOut={async () => { await window.HZdb.auth.signOut(); setMoreSheetOpen(false); }}
        />
      )}

      {cmdkOpen && snap && <CommandK snap={snap} onClose={() => setCmdkOpen(false)} onNav={(id) => { location.hash = '#' + id; setCmdkOpen(false); }} openAthlete={(id) => { setDrawerAthleteId(id); setCmdkOpen(false); }} />}
      {drawerAthleteId && snap && <AthleteDrawer athleteId={drawerAthleteId} snap={snap} onClose={() => setDrawerAthleteId(null)} pushToast={pushToast}/>}
      {walkthroughRole && <RoleWalkthrough role={walkthroughRole} onClose={closeWalkthrough} navigate={(id) => { location.hash = '#' + id; closeWalkthrough(); }}/>}
      <div className="toast-stack">
        {toasts.map(t => <Toast key={t.id} toast={t} onClose={(id) => setToasts(prev => prev.filter(x => x.id !== id))} />)}
      </div>
    </div>
  );
}
window.App = App;

// ─── Mobile top bar (just title + account chip) ───
function MobileTopBar({ title, onSignOut, session, snap }) {
  return (
    <div className="mobile-topbar hz-nosel">
      <div className="mobile-topbar__title">{title}</div>
      <button className="mobile-topbar__account" onClick={onSignOut} title="Sign out" aria-label="Sign out">
        {session?.profile?.display_name?.[0]?.toUpperCase() || 'U'}
      </button>
    </div>
  );
}
window.MobileTopBar = MobileTopBar;

// ─── Mobile bottom tab bar ───
function MobileTabBar({ role, active, onNav }) {
  const tabs = MOBILE_TABS[role] || MOBILE_TABS.coach;
  return (
    <nav className="mobile-tabbar hz-nosel" aria-label="Primary">
      {tabs.map(t => {
        const isActive = active === t.id;
        return (
          <button
            key={t.id}
            className={'mobile-tabbar__tab' + (isActive ? ' is-active' : '')}
            onClick={() => onNav(t.id)}
            aria-current={isActive ? 'page' : undefined}
          >
            <span className="mobile-tabbar__icon"><HZIcon name={t.icon} size={20}/></span>
            <span className="mobile-tabbar__label">{t.label}</span>
          </button>
        );
      })}
    </nav>
  );
}
window.MobileTabBar = MobileTabBar;

// ─── Mobile "More" bottom sheet (everything not in the tab bar) ───
function MobileMoreSheet({ nav, active, tabIds, onNav, onClose, onSignOut }) {
  const tabSet = new Set(tabIds);
  return (
    <div className="mobile-sheet-backdrop" onClick={onClose}>
      <div className="mobile-sheet" onClick={(e) => e.stopPropagation()} role="dialog" aria-label="More">
        <div className="mobile-sheet__handle"/>
        <div className="mobile-sheet__title">More</div>
        <div className="mobile-sheet__list">
          {nav.filter(it => it.id && !tabSet.has(it.id)).map(it => (
            <button
              key={it.id}
              className={'mobile-sheet__item' + (active === it.id ? ' is-active' : '')}
              onClick={() => onNav(it.id)}
            >
              <span className="mobile-sheet__item-icon"><HZIcon name={it.icon} size={18}/></span>
              <span className="mobile-sheet__item-label">{it.label}</span>
              <HZIcon name="chev-right" size={14} color="var(--hz-dim)"/>
            </button>
          ))}
          <div className="mobile-sheet__divider"/>
          <button className="mobile-sheet__item" onClick={onSignOut}>
            <span className="mobile-sheet__item-icon"><HZIcon name="logout" size={18}/></span>
            <span className="mobile-sheet__item-label">Sign out</span>
          </button>
        </div>
      </div>
    </div>
  );
}
window.MobileMoreSheet = MobileMoreSheet;

// ─── Error boundary: a screen crash shouldn't blank the app ───
class ScreenErrorBoundary extends React.Component {
  constructor(props) { super(props); this.state = { err: null }; }
  static getDerivedStateFromError(err) { return { err }; }
  componentDidCatch(err, info) { console.error('[HZ] screen error', err, info); }
  componentDidUpdate(prev) { if (prev.screenId !== this.props.screenId && this.state.err) this.setState({ err: null }); }
  render() {
    if (this.state.err) {
      return (
        <div style={{ padding: 48, maxWidth: 640 }}>
          <div className="hz-eyebrow" style={{ color: 'var(--hz-pink)' }}>Something broke on this screen</div>
          <div className="hz-display" style={{ fontSize: 42, marginTop: 10 }}>We caught it.</div>
          <div style={{ color: 'var(--hz-dim)', marginTop: 12, fontSize: 13 }}>
            {String(this.state.err.message || this.state.err)}
          </div>
          <div style={{ display: 'flex', gap: 10, marginTop: 24 }}>
            <button className="hz-btn" onClick={() => this.setState({ err: null })}>Retry</button>
            <button className="hz-btn hz-btn-primary" onClick={() => this.props.navigate('today')}>Back to Today</button>
          </div>
        </div>
      );
    }
    return this.props.children;
  }
}
window.ScreenErrorBoundary = ScreenErrorBoundary;

// ─── Sidebar ───
function profileAvatarSource(snap, profileId) {
  return (snap?.athletes || []).find(a => a.profile_id === profileId)?.photo_url || null;
}

function Sidebar({ nav, active, session, onNav, open, snap }) {
  const role = session.profile.role;
  const src = profileAvatarSource(snap, session.profile.id);
  return (
    <aside className={'sidebar hz-nosel' + (open ? ' open' : '')}>
      <div style={{ padding: '4px 10px 20px', borderBottom: '1px solid var(--hz-line)', marginBottom: 14 }}>
        <HZWordmark size={28} />
        <div className="hz-eyebrow" style={{ marginTop: 8, color: 'var(--hz-dimmer)', fontSize: 9 }}>Magic City · Minot, ND</div>
      </div>
      <nav style={{ flex: 1, overflowY: 'auto' }} className="hz-scroll">
        {nav.map((item, i) => item.group ? (
          <div key={'g'+i} className="nav-group-label">{item.group}</div>
        ) : (
          <div
            key={item.id}
            className={`nav-item ${active === item.id ? 'active' : ''}`}
            onClick={() => onNav(item.id)}
          >
            <div className="nav-accent"></div>
            <HZIcon name={item.icon} size={17} />
            <span>{item.label}</span>
          </div>
        ))}
      </nav>
      <div style={{ borderTop: '1px solid var(--hz-line)', paddingTop: 14, marginTop: 14 }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '4px 10px' }}>
          <Avatar name={session.profile.display_name} src={src} color={role === 'coach' || role === 'owner' ? '#27CFD7' : '#F97FAC'} size={32}/>
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{ fontSize: 12.5, fontWeight: 600, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{session.profile.display_name}</div>
            <div style={{ fontSize: 10, color: 'var(--hz-dim)', textTransform: 'uppercase', letterSpacing: '0.12em', fontWeight: 600 }}>{role}</div>
          </div>
        </div>
      </div>
    </aside>
  );
}

// ─── Topbar ───
function Topbar({ session, onOpenCmdk, onSignOut, onHamburger, onHelp, snap }) {
  return (
    <div className="topbar hz-nosel">
      <div className="topbar-left">
        <button className="hamburger-btn" onClick={onHamburger} aria-label="Open menu">
          <HZIcon name="skills" size={18}/>
        </button>
        <button
          type="button"
          onClick={onOpenCmdk}
          className="topbar-search"
        >
          <HZIcon name="search" size={14} />
          <span className="topbar-search-label">Search athletes, skills, routine...</span>
          <span className="topbar-kbd">⌘K</span>
        </button>
      </div>
      <div className="topbar-actions">
        {session.canViewAs || session.mode === 'prototype'
          ? <RoleSwitcher session={session} snap={snap} />
          : <AccountBadge session={session} />}
        <button className="topbar-icon-btn" onClick={onHelp} title="Open walkthrough" aria-label="Open walkthrough">
          ?
        </button>
        <button className="topbar-icon-btn" onClick={onSignOut} title="Sign out" aria-label="Sign out">
          <HZIcon name="logout" size={14} />
        </button>
      </div>
    </div>
  );
}

function AccountBadge({ session }) {
  const role = session.profile.role;
  return (
    <div className="topbar-account" style={{ cursor: 'default' }}>
      <span className="topbar-account-name">{session.profile.display_name || session.user?.email || session.profile.email}</span>
      <span className="topbar-account-role">
        {ROLE_LABELS[role] || role}
      </span>
    </div>
  );
}

function RoleSwitcher({ session, snap }) {
  const [open, setOpen] = useState(false);
  const roles = ['coach','parent','athlete','owner'];
  const profiles = window.HZdb._raw().profiles;
  const liveViewAs = !!session.canViewAs;
  const currentRole = session.profile.role;
  const accountName = session.actualProfile?.display_name || session.profile.display_name || session.user?.email || session.profile.email;
  const switchRole = async (role) => {
    const action = liveViewAs ? window.HZdb.auth.viewAsRole(role) : window.HZdb.auth.signInAsRole(role);
    const { error } = await action;
    if (error) {
      console.warn('[HZ] role switch failed', error);
      return;
    }
    setOpen(false);
    location.hash = '#' + firstRouteForRole(role);
  };
  return (
    <div style={{ position: 'relative' }}>
      <button className="topbar-account" onClick={() => setOpen(v => !v)}>
        <span className="topbar-account-name">{accountName}</span>
        <span className="topbar-view-as">View as</span>
        <span className="topbar-account-role">{ROLE_LABELS[currentRole] || currentRole}</span>
        <HZIcon name="chev-down" size={13} />
      </button>
      {open && (
        <>
          <div style={{ position: 'fixed', inset: 0, zIndex: 50 }} onClick={() => setOpen(false)} />
          <div style={{
            position: 'absolute', top: 'calc(100% + 8px)', right: 0,
            background: 'var(--hz-ink-2)', border: '1px solid var(--hz-line-2)',
            borderRadius: 12, padding: 6, minWidth: 220, zIndex: 51,
            boxShadow: '0 20px 50px rgba(0,0,0,0.4)',
          }}>
            {roles.map(r => {
              const p = liveViewAs
                ? { display_name: accountName, role: r }
                : profiles.find(x => x.role === r);
              if (!p) return null;
              return (
                <div
                  key={r}
                  onClick={() => switchRole(r)}
                  style={{
                    display: 'flex', alignItems: 'center', gap: 10, padding: '8px 10px', borderRadius: 8,
                    cursor: 'pointer',
                    background: r === currentRole ? 'rgba(255,255,255,0.06)' : 'transparent',
                  }}
                  onMouseEnter={e => e.currentTarget.style.background = 'rgba(255,255,255,0.06)'}
                  onMouseLeave={e => e.currentTarget.style.background = r === currentRole ? 'rgba(255,255,255,0.06)' : 'transparent'}
                >
                  <Avatar name={p.display_name} src={profileAvatarSource(snap, p.id)} color={r === 'coach' || r === 'owner' ? '#27CFD7' : '#F97FAC'} size={28}/>
                  <div style={{ flex: 1 }}>
                    <div style={{ fontSize: 13, fontWeight: 600 }}>{p.display_name}</div>
                    <div style={{ fontSize: 10, color: 'var(--hz-dim)', textTransform: 'uppercase', letterSpacing: '0.12em', fontWeight: 700 }}>{ROLE_LABELS[r] || r}</div>
                  </div>
                  {r === currentRole && <HZIcon name="check" size={14} color="var(--hz-teal)"/>}
                </div>
              );
            })}
            {liveViewAs && (
              <div style={{ borderTop: '1px solid var(--hz-line)', marginTop: 6, padding: '9px 10px 4px', color: 'var(--hz-dim)', fontSize: 11, lineHeight: 1.35 }}>
                Preview only. Your real Supabase role stays {ROLE_LABELS[session.actualRole] || session.actualRole}.
              </div>
            )}
          </div>
        </>
      )}
    </div>
  );
}

// ─── Login / auth gate ───
function Login() {
  const liveAuth = window.HZdb.auth._supportsMagicLink?.();
  const [mode, setMode] = useState('password');
  const [email, setEmail] = useState(window.HZdb.auth._lastEmail?.() || '');
  const [identifier, setIdentifier] = useState(window.HZdb.auth._lastEmail?.() || '');
  const [password, setPassword] = useState('');
  const [role, setRole] = useState('owner');
  const [busy, setBusy] = useState(false);
  const [sent, setSent] = useState(false);
  const [err, setErr] = useState(null);
  const roles = [
    { id: 'coach', label: 'Coach', sub: 'Run practice, track skills, build routines' },
    { id: 'owner', label: 'Gym Owner', sub: 'Program health, billing, all teams' },
    { id: 'athlete', label: 'Athlete', sub: "My reel, my skills, what's next" },
    { id: 'parent', label: 'Parent', sub: "Kid's wins, billing, schedule" },
  ];

  async function submit(e) {
    e.preventDefault();
    setBusy(true);
    setErr(null);
    try {
      const { error } = mode === 'password'
        ? await window.HZdb.auth.signInWithPassword(identifier, password)
        : await window.HZdb.auth.signInWithMagicLink(email, role);
      if (error) throw error;
      if (mode !== 'password') setSent(true);
    } catch (cause) {
      setErr(cause?.message || (mode === 'password' ? 'We could not sign you in.' : 'We could not send the sign-in link.'));
    } finally {
      setBusy(false);
    }
  }

  if (sent) {
    return (
      <div style={{ minHeight: '100vh', display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 40 }}>
        <div style={{ maxWidth: 560, width: '100%' }}>
          <div style={{ textAlign: 'center', marginBottom: 32 }}>
            <HZWordmark size={80} stacked />
            <div className="hz-eyebrow" style={{ marginTop: 18, fontSize: 11 }}>Magic City Allstars · Minot, ND</div>
            <div className="hz-display" style={{ fontSize: 28, marginTop: 40 }}>Check your email.</div>
            <div style={{ color: 'var(--hz-dim)', marginTop: 14, fontSize: 14 }}>
              We sent a secure sign-in link to <b>{email}</b>. Open it on this device to continue.
            </div>
          </div>
        </div>
      </div>
    );
  }

  if (!liveAuth) {
    return (
      <div style={{ minHeight: '100vh', display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 40 }}>
        <div style={{ maxWidth: 900, width: '100%' }}>
          <div style={{ textAlign: 'center', marginBottom: 48 }}>
            <HZWordmark size={80} stacked />
            <div className="hz-eyebrow" style={{ marginTop: 18, fontSize: 11 }}>Magic City Allstars · Minot, ND</div>
            <div className="hz-display" style={{ fontSize: 28, marginTop: 40, color: 'var(--hz-dim)', fontWeight: 400, fontStyle: 'italic' }}>
              Sign in as…
            </div>
          </div>
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(220px, 1fr))', gap: 16 }}>
            {roles.map(r => (
              <div
                key={r.id}
                onClick={async () => { await window.HZdb.auth.signInAsRole(r.id); }}
                className="hz-card"
                style={{
                  cursor: 'pointer', textAlign: 'center', padding: '28px 20px',
                  transition: 'transform 120ms, border-color 120ms',
                }}
                onMouseEnter={e => { e.currentTarget.style.transform = 'translateY(-3px)'; e.currentTarget.style.borderColor = 'rgba(249,127,172,0.3)'; }}
                onMouseLeave={e => { e.currentTarget.style.transform = 'none'; e.currentTarget.style.borderColor = 'var(--hz-line)'; }}
              >
                <div className="hz-display" style={{ fontSize: 40, marginBottom: 8 }}>{r.label}</div>
                <div style={{ color: 'var(--hz-dim)', fontSize: 12.5 }}>{r.sub}</div>
              </div>
            ))}
          </div>
          <div style={{ textAlign: 'center', marginTop: 40, color: 'var(--hz-dimmer)', fontSize: 11 }}>
            Prototype fallback is active because the live auth client is unavailable.
          </div>
        </div>
      </div>
    );
  }

  return (
    <div style={{ minHeight: '100vh', display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 40 }}>
      <form onSubmit={submit} style={{ maxWidth: 720, width: '100%' }}>
        <div style={{ textAlign: 'center', marginBottom: 48 }}>
          <HZWordmark size={80} stacked />
          <div className="hz-eyebrow" style={{ marginTop: 18, fontSize: 11 }}>Magic City Allstars · Minot, ND</div>
          <div className="hz-display" style={{ fontSize: 28, marginTop: 40, color: 'var(--hz-dim)', fontWeight: 400, fontStyle: 'italic' }}>
            Sign in to your gym.
          </div>
        </div>
        <div className="hz-card" style={{ maxWidth: 560, margin: '0 auto', padding: 28 }}>
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 8, marginBottom: 20 }}>
            <button type="button" className={'hz-btn' + (mode === 'password' ? ' hz-btn-primary' : '')} onClick={() => setMode('password')}>Username + password</button>
            <button type="button" className={'hz-btn' + (mode === 'magic' ? ' hz-btn-primary' : '')} onClick={() => setMode('magic')}>Email link</button>
          </div>
          {mode === 'password' ? (
            <>
              <label className="hz-eyebrow" style={{ display: 'block', fontSize: 11, marginBottom: 8 }}>Username or email</label>
              <input
                className="hz-input"
                required
                autoFocus
                value={identifier}
                onChange={e => setIdentifier(e.target.value)}
                placeholder="arlowe"
                autoCapitalize="none"
                autoCorrect="off"
              />
              <label className="hz-eyebrow" style={{ display: 'block', fontSize: 11, marginTop: 18, marginBottom: 8 }}>Password</label>
              <input
                className="hz-input"
                type="password"
                required
                value={password}
                onChange={e => setPassword(e.target.value)}
                placeholder="••••••••"
              />
            </>
          ) : (
            <>
              <label className="hz-eyebrow" style={{ display: 'block', fontSize: 11, marginBottom: 8 }}>Email</label>
              <input
                className="hz-input"
                type="email"
                required
                autoFocus
                value={email}
                onChange={e => setEmail(e.target.value)}
                placeholder="you@gym.com"
              />
              <div className="hz-eyebrow" style={{ display: 'block', fontSize: 11, marginTop: 24, marginBottom: 10 }}>Role</div>
              <div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, minmax(0, 1fr))', gap: 12 }}>
                {roles.map(r => (
                  <button
                    key={r.id}
                    type="button"
                    className={'hz-btn' + (role === r.id ? ' hz-btn-primary' : '')}
                    style={{ justifyContent: 'flex-start', padding: '14px 16px' }}
                    onClick={() => setRole(r.id)}
                  >
                    <div style={{ textAlign: 'left' }}>
                      <div style={{ fontWeight: 700 }}>{r.label}</div>
                      <div style={{ color: role === r.id ? 'rgba(255,255,255,0.82)' : 'var(--hz-dim)', fontSize: 11, marginTop: 4 }}>{r.sub}</div>
                    </div>
                  </button>
                ))}
              </div>
            </>
          )}
          {err && <div style={{ color: 'var(--hz-pink)', marginTop: 18, fontSize: 13 }}>{err}</div>}
          <button className="hz-btn hz-btn-primary" type="submit" disabled={busy || (mode === 'password' ? (!identifier || !password) : !email)} style={{ width: '100%', marginTop: 22, justifyContent: 'center' }}>
            {busy ? (mode === 'password' ? 'Signing in…' : 'Sending…') : (mode === 'password' ? 'Sign in' : 'Send secure sign-in link')}
          </button>
          <div style={{ color: 'var(--hz-dimmer)', marginTop: 16, fontSize: 11, textAlign: 'center' }}>
            Athletes can use a simple username on iPad. Parents and staff can still use email links.
          </div>
        </div>
      </form>
    </div>
  );
}
window.Login = Login;

function walkthroughStepsForRole(role) {
  const steps = {
    parent: [
      { title: "Your kid's week", body: 'Start on the family overview: readiness, attendance, wins, balances, and anything the gym needs from you.', action: 'Open Family', nav: 'parent' },
      { title: 'Skills and routines', body: 'Use Skills to see what Arlowe is working on, and AI Judge to review routine feedback with a coach or parent nearby.', action: 'Open Skills', nav: 'skilltree' },
      { title: 'The practical stuff', body: 'Billing, schedule, messages, uniforms, volunteers, and medical are grouped under Family so parent jobs are easy to find.', action: 'Open Schedule', nav: 'schedule' },
    ],
    athlete: [
      { title: 'Your reel', body: 'See wins, readiness, attendance, and what to work on next.', action: 'Open My Reel', nav: 'reel' },
      { title: 'Skill tracker', body: 'Open Skill Tree and mark each skill as Not yet, Working, Got it, or Mastered so your profile stays current.', action: 'Open Skill Tree', nav: 'skilltree' },
      { title: 'Pins', body: 'Create pins, keep them in your basket, and drop them on teammates when they do something cool.', action: 'Open Pins', nav: 'pins' },
      { title: 'AI Judge', body: 'Upload a routine when a parent or coach says it is okay, then review the scorecard together.', action: 'Open AI Judge', nav: 'ai_judge' },
    ],
    coach: [
      { title: 'Run the room', body: 'Today, Roster, Skill Matrix, and Practice Plans are the daily cockpit for coaching the team.', action: 'Open Today', nav: 'today' },
      { title: 'Build the routine', body: 'Routine Builder, Mock Score, and AI Judge connect reps to scoring and feedback.', action: 'Open AI Judge', nav: 'ai_judge' },
      { title: 'Keep everyone aligned', body: 'Schedule, messages, announcements, volunteers, and medical keep the whole gym moving together.', action: 'Open Schedule', nav: 'schedule' },
    ],
    owner: [
      { title: 'Operate the gym', body: 'Program, Billing, Leads, Teams, Registration, and communications are your ownership command center.', action: 'Open Program', nav: 'admin' },
      { title: 'Watch performance', body: 'Roster, Skill Matrix, Routine, Mock Score, and AI Judge show what is actually improving.', action: 'Open Roster', nav: 'roster' },
      { title: 'Switch perspectives', body: 'Use View as to sanity-check what coaches, parents, and athletes experience before rollout.', action: 'Open Today', nav: 'today' },
    ],
  };
  return steps[role] || steps.coach;
}

function RoleWalkthrough({ role, onClose, navigate }) {
  const steps = walkthroughStepsForRole(role);
  const [i, setI] = useState(0);
  const step = steps[i];
  return (
    <div style={{ position: 'fixed', inset: 0, zIndex: 1000, background: 'rgba(0,0,0,0.72)', display: 'grid', placeItems: 'center', padding: 24 }}>
      <div className="hz-card" style={{ maxWidth: 640, width: '100%', borderColor: 'rgba(249,127,172,0.45)' }}>
        <div className="hz-eyebrow" style={{ color: 'var(--hz-pink)', marginBottom: 10 }}>Welcome to Hit Zero · {ROLE_LABELS[role] || role}</div>
        <div className="hz-display" style={{ fontSize: 44, lineHeight: 1 }}>{step.title}</div>
        <div style={{ color: 'var(--hz-dim)', fontSize: 15, lineHeight: 1.6, marginTop: 14 }}>{step.body}</div>
        <div style={{ marginTop: 18, padding: 14, borderRadius: 14, background: 'rgba(39,207,215,0.08)', color: 'var(--hz-dim)', fontSize: 13, lineHeight: 1.5 }}>
          Need this again later? Tap the ? in the header to reopen this walkthrough any time.
        </div>
        <div style={{ display: 'flex', gap: 10, justifyContent: 'space-between', alignItems: 'center', marginTop: 24 }}>
          <button className="hz-btn hz-btn-ghost" onClick={() => onClose(true)}>Skip</button>
          <div style={{ display: 'flex', gap: 8 }}>
            {steps.map((_, idx) => <span key={idx} style={{ width: 8, height: 8, borderRadius: 999, background: idx === i ? 'var(--hz-pink)' : 'rgba(255,255,255,0.18)' }}/>)}
          </div>
          <div style={{ display: 'flex', gap: 10 }}>
            {i > 0 && <button className="hz-btn" onClick={() => setI(v => v - 1)}>Back</button>}
            {i < steps.length - 1 ? (
              <button className="hz-btn hz-btn-primary" onClick={() => setI(v => v + 1)}>Next</button>
            ) : (
              <button className="hz-btn hz-btn-primary" onClick={() => navigate(step.nav)}>{step.action}</button>
            )}
          </div>
        </div>
      </div>
    </div>
  );
}
window.RoleWalkthrough = RoleWalkthrough;

// ─── Command-K palette ───
function CommandK({ snap, onClose, onNav, openAthlete }) {
  const [q, setQ] = useState('');
  const results = useMemo(() => {
    if (!q.trim()) return [
      { kind: 'nav', id: 'today', label: 'Go to Today', icon: 'today' },
      { kind: 'nav', id: 'roster', label: 'Open Roster', icon: 'roster' },
      { kind: 'nav', id: 'skills', label: 'Skill Matrix', icon: 'skills' },
      { kind: 'nav', id: 'routine', label: 'Routine Builder', icon: 'routine' },
      { kind: 'nav', id: 'score', label: 'Mock Score', icon: 'score' },
    ];
    const needle = q.toLowerCase();
    const out = [];
    snap.athletes.forEach(a => {
      if (a.display_name.toLowerCase().includes(needle)) out.push({ kind: 'athlete', id: a.id, label: a.display_name, sub: a.role, icon: 'users' });
    });
    snap.skills.forEach(s => {
      if (s.name.toLowerCase().includes(needle)) out.push({ kind: 'skill', id: s.id, label: s.name, sub: `${s.category.replace('_',' ')} · L${s.level}`, icon: 'skills' });
    });
    ['today','roster','skills','routine','score','sessions','billing','messages'].forEach(r => {
      if (r.includes(needle)) out.push({ kind: 'nav', id: r, label: 'Go to ' + r, icon: 'arrow-right' });
    });
    return out.slice(0, 10);
  }, [q, snap]);

  const pick = (r) => {
    if (r.kind === 'nav') onNav(r.id);
    else if (r.kind === 'athlete') openAthlete(r.id);
    else if (r.kind === 'skill') onNav('skills');
  };

  return (
    <div className="cmdk-backdrop" onClick={onClose}>
      <div className="cmdk-panel" onClick={e => e.stopPropagation()}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 12, padding: 16, borderBottom: '1px solid var(--hz-line)' }}>
          <HZIcon name="search" size={18} color="var(--hz-dim)"/>
          <input autoFocus className="hz-input" value={q} onChange={e => setQ(e.target.value)} placeholder="Search athletes, skills, screens…" style={{ border: 'none', background: 'transparent', padding: 0, fontSize: 16 }}/>
          <span style={{ fontSize: 10, color: 'var(--hz-dimmer)', fontFamily: 'var(--hz-mono)' }}>ESC</span>
        </div>
        <div style={{ maxHeight: 400, overflowY: 'auto', padding: 6 }} className="hz-scroll">
          {results.length === 0 && <div style={{ padding: 20, color: 'var(--hz-dim)', textAlign: 'center', fontSize: 13 }}>No matches</div>}
          {results.map((r, i) => (
            <div
              key={i}
              onClick={() => pick(r)}
              style={{
                padding: '10px 12px', borderRadius: 8, cursor: 'pointer',
                display: 'flex', alignItems: 'center', gap: 12,
              }}
              onMouseEnter={e => e.currentTarget.style.background = 'rgba(255,255,255,0.06)'}
              onMouseLeave={e => e.currentTarget.style.background = 'transparent'}
            >
              <div style={{ width: 28, height: 28, borderRadius: 6, background: 'rgba(255,255,255,0.05)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
                <HZIcon name={r.icon} size={14} color="var(--hz-dim)"/>
              </div>
              <div style={{ flex: 1 }}>
                <div style={{ fontSize: 13.5 }}>{r.label}</div>
                {r.sub && <div style={{ fontSize: 11, color: 'var(--hz-dim)', textTransform: 'capitalize' }}>{r.sub}</div>}
              </div>
              <span className="hz-pill" style={{ fontSize: 9 }}>{r.kind}</span>
            </div>
          ))}
        </div>
      </div>
    </div>
  );
}
window.CommandK = CommandK;
