/* Admin panel shell - login + sidebar nav + topbar. */

/* ---------- Admin session (sessionStorage) ---------- */
function useAdminSession() {
  const [user, setUser] = useState(() => {
    try {
      const raw = sessionStorage.getItem('sf_admin_session');
      return raw ? JSON.parse(raw) : null;
    } catch (e) { return null; }
  });
  const login = (username) => {
    const u = { username, since: Date.now() };
    sessionStorage.setItem('sf_admin_session', JSON.stringify(u));
    setUser(u);
  };
  const logout = () => {
    sessionStorage.removeItem('sf_admin_session');
    setUser(null);
  };
  return { user, login, logout };
}

/* ---------- Login ---------- */
function AdminLogin({ onLogin }) {
  const [username, setUsername] = useState('');
  const [password, setPassword] = useState('');
  const [err, setErr] = useState('');
  const submit = (e) => {
    e && e.preventDefault();
    if (username === 'penguin' && password === 'Penguin@2026foari') {
      setErr('');
      // Store for API auth headers
      sessionStorage.setItem('sf_admin_token', password);
      onLogin(username);
    } else {
      setErr('Invalid credentials.');
    }
  };
  return (
    <div style={{
      minHeight: '100vh', background: 'var(--grey-50)',
      display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 22,
      position: 'relative', overflow: 'hidden',
    }}>
      {/* dot grid + diagonal */}
      <div aria-hidden="true" className="dot-grid" style={{ position: 'absolute', inset: 0, opacity: 0.4 }} />
      <div aria-hidden="true" style={{
        position: 'absolute', left: -60, top: '30%', width: '70%', height: 8,
        background: 'var(--orange)', transform: 'skewX(-12deg)',
      }} />

      <form onSubmit={submit} style={{
        position: 'relative',
        background: '#fff',
        border: '1px solid var(--grey-200)',
        borderRadius: 12,
        boxShadow: '0 8px 32px rgba(17,6,24,0.14)',
        padding: 36, width: '100%', maxWidth: 420,
      }}>
        <SunFrontLogo height={32} />
        <div className="font-display" style={{
          fontSize: 28, marginTop: 22, letterSpacing: '-0.02em',
        }}>
          Admin Console
        </div>
        <div style={{ color: 'var(--grey-600)', fontSize: 13.5, marginTop: 6 }}>
          Sign in to manage the campaign.
        </div>

        <div style={{ marginTop: 24, display: 'grid', gap: 14 }}>
          <label>
            <div style={{ fontSize: 11, letterSpacing: '0.14em', textTransform: 'uppercase', fontWeight: 700, marginBottom: 6 }}>Username</div>
            <input value={username} onChange={(e) => setUsername(e.target.value)} autoFocus
              style={{ ...inputStyle }} />
          </label>
          <label>
            <div style={{ fontSize: 11, letterSpacing: '0.14em', textTransform: 'uppercase', fontWeight: 700, marginBottom: 6 }}>Password</div>
            <input value={password} onChange={(e) => setPassword(e.target.value)} type="password"
              placeholder="••••••••"
              style={{ ...inputStyle }} />
          </label>
        </div>

        {err && (
          <div style={{
            marginTop: 14, padding: '10px 12px', background: '#fee2e2', color: '#b91c1c',
            border: '1px solid #fecaca', fontSize: 13,
          }}>{err}</div>
        )}

        <button type="submit" className="font-display btn-press" style={{
          marginTop: 22, width: '100%',
          background: 'var(--orange)', color: '#fff', border: 'none',
          borderRadius: 6,
          padding: '16px 22px', fontSize: 15, letterSpacing: '0.06em', textTransform: 'uppercase',
          boxShadow: '0 4px 16px rgba(241,86,35,0.30)',
          display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: 10,
        }}>
          Sign in
          <Icon name="arrow" size={18} />
        </button>
      </form>
    </div>
  );
}

/* ---------- Sidebar nav ---------- */
const ADMIN_NAV = [
  { key: 'overview',     label: 'Overview',     icon: 'bolt' },
  { group: 'Matches' },
  { key: 'matches',      label: 'All matches',  icon: 'flag' },
  { key: 'create',       label: 'Schedule new', icon: 'calendar' },
  { key: 'settle',       label: 'Settle result',icon: 'check' },
  { key: 'draw',         label: 'Lucky draw',   icon: 'trophy' },
  { group: 'Data' },
  { key: 'predictions',  label: 'Predictions',  icon: 'receipt' },
  { key: 'outlets',      label: 'Outlets',      icon: 'pin' },
  { key: 'billdata',     label: 'Bill data',    icon: 'scale' },
  { key: 'advertising',  label: 'Advertising',  icon: 'chart' },
  { group: 'Site' },
  { key: 'flags',        label: 'Flag images',  icon: 'image' },
  { key: 'content',      label: 'Content & copy', icon: 'message' },
  { key: 'settings',     label: 'Settings',     icon: 'target' },
  { group: 'System' },
  { key: 'sms',          label: 'SMS Center',   icon: 'message' },
  { key: 'audit',        label: 'Audit log',    icon: 'receipt' },
];

function AdminSidebar({ active, onPick, openMobile, setOpenMobile }) {
  const Item = ({ item }) => {
    const isActive = active === item.key;
    return (
      <button onClick={() => { onPick(item.key); setOpenMobile(false); }} style={{
        background: isActive ? 'var(--orange)' : 'transparent',
        color: isActive ? '#fff' : '#d4d4d8',
        border: 'none',
        width: '100%', textAlign: 'left',
        padding: '12px 18px',
        display: 'flex', alignItems: 'center', gap: 12,
        fontSize: 13.5, fontWeight: isActive ? 700 : 500, letterSpacing: '0.02em',
        cursor: 'pointer',
        position: 'relative',
        transition: 'background 0.12s, color 0.12s',
      }}
      onMouseEnter={(e) => { if (!isActive) e.currentTarget.style.background = '#2a1f30'; }}
      onMouseLeave={(e) => { if (!isActive) e.currentTarget.style.background = 'transparent'; }}
      >
        {isActive && (
          <span style={{
            position: 'absolute', left: 0, top: 8, bottom: 8, width: 4, background: '#fff',
          }} />
        )}
        <Icon name={item.icon} size={17} color={isActive ? '#fff' : 'var(--orange)'} stroke={1.8} />
        {item.label}
      </button>
    );
  };

  return (
    <>
      {openMobile && (
        <div onClick={() => setOpenMobile(false)} style={{
          position: 'fixed', inset: 0, background: 'rgba(0,0,0,0.5)', zIndex: 39,
        }} />
      )}
      <aside className={`admin-sidebar ${openMobile ? 'open' : ''}`} style={{
        background: 'var(--ink)', color: '#fff',
        width: 240, flexShrink: 0,
        display: 'flex', flexDirection: 'column',
      }}>
        <div style={{ padding: '20px 18px 18px', borderBottom: '1px solid #2a1f30' }}>
          <SunFrontLogo height={28} onWhite={false} />
          <div style={{
            marginTop: 8, fontSize: 10, letterSpacing: '0.22em', textTransform: 'uppercase',
            color: 'var(--orange)', fontWeight: 700,
          }}>
            Admin Console
          </div>
        </div>
        <nav style={{ padding: '12px 0', flex: 1, overflowY: 'auto' }}>
          {ADMIN_NAV.map((item, i) =>
            item.group ? (
              <div key={`g-${i}`} style={{
                padding: '14px 18px 6px', fontSize: 10, letterSpacing: '0.22em',
                textTransform: 'uppercase', color: 'var(--grey-500)', fontWeight: 700,
              }}>{item.group}</div>
            ) : (
              <Item key={item.key} item={item} />
            )
          )}
        </nav>
        <div style={{
          padding: '14px 18px', borderTop: '1px solid #2a1f30',
          fontSize: 11, color: 'var(--grey-500)', letterSpacing: '0.06em',
        }}>
          v1.0 · campaign 2026
        </div>
      </aside>
    </>
  );
}

/* ---------- Topbar ---------- */
function AdminTopbar({ user, onLogout, onSync, syncing, title, onMenu }) {
  return (
    <header style={{
      background: '#fff', borderBottom: '1px solid var(--grey-200)',
      padding: '12px 22px',
      display: 'flex', alignItems: 'center', gap: 16, justifyContent: 'space-between',
      position: 'sticky', top: 0, zIndex: 20,
    }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 12, minWidth: 0 }}>
        <button className="only-mobile" onClick={onMenu} style={{
          background: 'none', border: '1.5px solid var(--grey-300)', borderRadius: 6, padding: 8, cursor: 'pointer',
        }} aria-label="Open menu">
          <svg width="18" height="18" viewBox="0 0 24 24" stroke="currentColor" fill="none" strokeWidth="2.4" strokeLinecap="round">
            <path d="M3 7h18M3 12h18M3 17h18"/>
          </svg>
        </button>
        <div className="font-display" style={{ fontSize: 20, letterSpacing: '-0.01em' }}>{title}</div>
      </div>
      <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
        <button onClick={onSync} disabled={syncing} className="font-display" style={{
          background: '#fff', color: 'var(--ink)', border: '1.5px solid var(--grey-300)', borderRadius: 6,
          padding: '9px 14px', fontSize: 12, letterSpacing: '0.06em', textTransform: 'uppercase',
          display: 'inline-flex', alignItems: 'center', gap: 8,
          cursor: syncing ? 'wait' : 'pointer', opacity: syncing ? 0.6 : 1,
        }} title="Manually run the SCHEDULED→OPEN→CLOSED transition logic">
          <Icon name="bolt" size={14} />
          {syncing ? 'Syncing…' : 'Sync statuses'}
        </button>
        <div className="hide-mobile" style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '0 8px', borderLeft: '1px solid var(--grey-200)' }}>
          <div style={{
            width: 30, height: 30, borderRadius: '50%',
            background: 'var(--ink)', color: 'var(--orange)',
            display: 'flex', alignItems: 'center', justifyContent: 'center', fontWeight: 800, fontSize: 13,
            fontFamily: "'Nunito', sans-serif",
          }}>
            {user.username.slice(0, 1).toUpperCase()}
          </div>
          <div>
            <div style={{ fontSize: 13, fontWeight: 700 }}>{user.username}</div>
            <div style={{ fontSize: 11, color: 'var(--grey-500)' }}>Administrator</div>
          </div>
        </div>
        <button onClick={onLogout} style={{
          background: 'none', border: '1.5px solid var(--grey-300)', borderRadius: 6,
          padding: '8px 12px', fontSize: 12, letterSpacing: '0.06em', textTransform: 'uppercase',
          fontWeight: 700, color: 'var(--grey-700)', cursor: 'pointer',
        }}>
          Log out
        </button>
      </div>
    </header>
  );
}

/* ---------- Toast ---------- */
function AdminToast({ toast, onDone }) {
  useEffect(() => {
    if (!toast) return;
    const id = setTimeout(onDone, 3500);
    return () => clearTimeout(id);
  }, [toast, onDone]);
  if (!toast) return null;
  const tone = toast.tone || 'success';
  const palette = {
    success: { bg: 'var(--success-bg)', fg: '#0f5f2e', bd: 'var(--success)' },
    info:    { bg: 'var(--orange-50)',   fg: 'var(--orange-dark)', bd: 'var(--orange)' },
    error:   { bg: '#fee2e2',            fg: '#b91c1c', bd: '#ef4444' },
  }[tone];
  return (
    <div className="toast-in" style={{
      position: 'fixed', top: 22, left: '50%', zIndex: 50,
      background: palette.bg, color: palette.fg,
      border: `1px solid ${palette.bd}`,
      borderRadius: 8,
      boxShadow: '0 4px 20px rgba(17,6,24,0.12)',
      padding: '12px 18px', maxWidth: 520,
      display: 'flex', alignItems: 'center', gap: 12,
    }}>
      <Icon name={tone === 'error' ? 'bolt' : 'check'} size={18} stroke={3} />
      <div style={{ fontSize: 13.5, fontWeight: 600, lineHeight: 1.4 }}>{toast.message}</div>
    </div>
  );
}

/* ---------- Page section wrapper ---------- */
function AdminSection({ title, sub, right, children }) {
  return (
    <div>
      <div style={{
        display: 'flex', justifyContent: 'space-between', alignItems: 'end',
        gap: 16, flexWrap: 'wrap', marginBottom: 22,
      }}>
        <div>
          <div style={{ fontSize: 11, letterSpacing: '0.22em', textTransform: 'uppercase', color: 'var(--orange)', fontWeight: 700 }}>
            Admin
          </div>
          <h1 className="font-display" style={{ fontSize: 'clamp(24px, 4vw, 34px)', lineHeight: 1, margin: '6px 0 6px', letterSpacing: '-0.02em' }}>
            {title}
          </h1>
          {sub && <p style={{ margin: 0, color: 'var(--grey-600)', fontSize: 14 }}>{sub}</p>}
        </div>
        {right}
      </div>
      {children}
    </div>
  );
}

/* ---------- White card panel ---------- */
function Panel({ title, action, children, padding = 22 }) {
  return (
    <div style={{
      background: '#fff', border: '1px solid var(--grey-200)',
      borderRadius: 10,
      boxShadow: '0 2px 12px rgba(17,6,24,0.06)',
    }}>
      {(title || action) && (
        <div style={{
          padding: '14px 18px', borderBottom: '1px solid var(--grey-200)',
          display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: 12,
        }}>
          <div className="font-display" style={{ fontSize: 16, letterSpacing: '-0.01em' }}>{title}</div>
          {action}
        </div>
      )}
      <div style={{ padding }}>{children}</div>
    </div>
  );
}

/* ---------- Primary / secondary admin buttons ---------- */
function AdminBtn({ kind = 'primary', icon, children, ...rest }) {
  const styles = {
    primary:   { bg: 'var(--orange)', fg: '#fff',         bd: 'transparent',     sh: '0 4px 12px rgba(241,86,35,0.28)' },
    ink:       { bg: 'var(--ink)',    fg: '#fff',         bd: 'transparent',     sh: '0 4px 12px rgba(17,6,24,0.20)' },
    outline:   { bg: '#fff',          fg: 'var(--ink)',   bd: 'var(--ink)',      sh: '0 2px 8px rgba(17,6,24,0.08)' },
    ghost:     { bg: '#fff',          fg: 'var(--ink)',   bd: 'var(--grey-300)', sh: 'none' },
    danger:    { bg: '#fff',          fg: '#b91c1c',      bd: '#fecaca',         sh: 'none' },
  }[kind];
  return (
    <button {...rest} className="font-display btn-press" style={{
      background: styles.bg, color: styles.fg,
      border: `1.5px solid ${styles.bd}`,
      borderRadius: 6,
      padding: '11px 16px',
      fontSize: 12.5, letterSpacing: '0.06em', textTransform: 'uppercase',
      display: 'inline-flex', alignItems: 'center', gap: 8,
      boxShadow: styles.sh,
      cursor: rest.disabled ? 'not-allowed' : 'pointer',
      opacity: rest.disabled ? 0.55 : 1,
      ...rest.style,
    }}>
      {icon && <Icon name={icon} size={14} />}
      {children}
    </button>
  );
}

/* ---------- Time-ago ---------- */
function timeAgo(ms) {
  const diff = Date.now() - ms;
  const min = Math.floor(diff / 60000);
  if (min < 1) return 'just now';
  if (min < 60) return `${min}m ago`;
  const h = Math.floor(min / 60);
  if (h < 24) return `${h}h ago`;
  return `${Math.floor(h / 24)}d ago`;
}

/* ---------- Admin figurine layer ---------- */
const ADMIN_FIGURINE_MAP = {
  overview:    ['messi',      'ronaldo'],
  matches:     ['mbappe',     'haaland'],
  create:      ['bellingham', 'yamal'],
  settle:      ['kane',       'pulisic'],
  draw:        ['vinicius',   'messi'],
  predictions: ['ronaldo',    'haaland'],
  outlets:     ['mbappe',     'vinicius'],
  billdata:    ['kane',       'bellingham'],
  advertising: ['messi',      'ronaldo'],
  flags:       ['yamal',      'pulisic'],
  content:     ['vinicius',   'bellingham'],
  settings:    ['kane',       'ronaldo'],
};

function AdminFigurineLayer({ tab }) {
  const pair = ADMIN_FIGURINE_MAP[tab];
  if (!pair) return null;
  const base = '/assets/figurines';
  return (
    <>
      <div className="figurine-layer figurine-admin figurine-admin-left">
        <video key={pair[0]} autoPlay loop muted playsInline>
          <source src={`${base}/webm/${pair[0]}.webm`} type="video/webm" />
          <img src={`${base}/gif/${pair[0]}.gif`} alt={pair[0]} />
        </video>
      </div>
      <div className="figurine-layer figurine-admin figurine-admin-right">
        <video key={pair[1]} autoPlay loop muted playsInline>
          <source src={`${base}/webm/${pair[1]}.webm`} type="video/webm" />
          <img src={`${base}/gif/${pair[1]}.gif`} alt={pair[1]} />
        </video>
      </div>
    </>
  );
}

/* ---------- Main admin app ---------- */
function AdminApp({ onLeave }) {
  const session = useAdminSession();
  const [tab, setTab] = useState('overview');
  const [openMobile, setOpenMobile] = useState(false);
  const [toast, setToast] = useState(null);
  const [syncing, setSyncing] = useState(false);
  const mascotRef = useRef(null);
  const isFirstTabRef = useRef(true);
  const prevPredCountRef = useRef(0);
  const clickChainRef = useRef({ count: 0, timer: null });
  const settleStreakRef = useRef(0);
  const zeroAlertedRef = useRef(new Set());
  const billGapAlertedRef = useRef(false);
  const teamStreakAlertedRef = useRef(null);
  const countdownAlertedRef = useRef(new Set());

  // Local mutable copies - in prod these are server state.
  const [matchesState, setMatchesState] = useState(() => [...MATCHES]);
  const [outletsState, setOutletsState] = useState(() => [...OUTLETS]);
  const [contentState, setContentState] = useState(() => ({ ...SITE_CONTENT_DEFAULTS }));

  // Live predictions from Supabase, shared across all admin tabs.
  const [livePredictions, setLivePredictions] = useState(null); // null = loading
  const [predictionsError, setPredictionsError] = useState('');
  const [billEntriesCount, setBillEntriesCount] = useState(0);

  const adminToken = (() => {
    try { return sessionStorage.getItem('sf_admin_token') || ''; } catch (e) { return ''; }
  })();

  // Load the full live match list (all enabled fixtures + settled overlay) from the API
  useEffect(() => {
    let active = true;
    fetch('/api/matches')
      .then(r => r.ok ? r.json() : null)
      .then(data => {
        if (!active || !data || !Array.isArray(data.matches) || data.matches.length === 0) return;
        const updated = data.matches.map(m => ({ ...m, kickoffAt: new Date(m.kickoffMs) }));
        setMatchesState(updated);
      })
      .catch(() => {});
    return () => { active = false; };
  }, []);

  // Load live predictions for overview stats, predictions browser, outlets, etc.
  // Polls every 60 s so all data-dependent tabs stay in sync.
  useEffect(() => {
    if (!session.user) return;
    let active = true;
    function loadPredictions() {
      fetch('/api/get-predictions', { headers: { 'x-admin-key': adminToken } })
        .then(r => r.json())
        .then(data => {
          if (!active) return;
          if (data.predictions) {
            setLivePredictions(data.predictions);
            if (data.billEntriesCount != null) setBillEntriesCount(data.billEntriesCount);
            setPredictionsError('');
          } else {
            setPredictionsError(data.error || 'Could not load predictions.');
            setLivePredictions([]);
          }
        })
        .catch(() => {
          if (!active) return;
          setPredictionsError('Network error while loading predictions.');
          setLivePredictions([]);
        });
    }
    loadPredictions();
    const id = setInterval(loadPredictions, 60000);
    return () => { active = false; clearInterval(id); };
  }, [session.user, adminToken]);

  // ── Pip effects ────────────────────────────────────────────────────────────

  // Smart greeting — first login of day gets special message
  useEffect(() => {
    const t = setTimeout(() => {
      if (!mascotRef.current) return;
      const today = new Date().toDateString();
      const lastLogin = localStorage.getItem('pip_last_login') || '';
      localStorage.setItem('pip_last_login', today);
      if (lastLogin !== today) {
        const h = new Date().getHours();
        const timeOfDay = h < 12 ? 'morning' : h < 17 ? 'afternoon' : 'evening';
        const daysSince = lastLogin ? Math.round((Date.now() - new Date(lastLogin)) / 86400000) : 0;
        const extra = daysSince > 1 ? ` — ${daysSince} days away! 👀` : ' — new day, fresh start! 🌅';
        mascotRef.current.celebrate(`Good ${timeOfDay}${extra}`);
      } else {
        mascotRef.current.greet();
      }
    }, 600);
    return () => clearTimeout(t);
  }, []);

  // Syncing pose
  useEffect(() => {
    if (!mascotRef.current) return;
    if (syncing) mascotRef.current.think(true, 'Syncing matches…');
    else mascotRef.current.think(false);
  }, [syncing]);

  // Toast reaction — settle detection + team-specific reactions + streak counter
  useEffect(() => {
    if (!toast || !mascotRef.current) return;
    const msg = (toast.message || '').toLowerCase();
    if (toast.tone === 'error') {
      mascotRef.current.error(toast.message);
    } else if (msg.includes('settled') || msg.includes('result') || msg.includes('winner')) {
      settleStreakRef.current++;
      const streak = settleStreakRef.current;

      // Extract winner from "Settled: TeamA 0-0 TeamB · WINNER · N/M correct"
      const parts = (toast.message || '').split(' · ');
      const winnerName = parts.length >= 2 ? parts[1].trim() : '';
      const winnerLower = winnerName.toLowerCase();

      let streakMsg = null;
      if (streak === 3) streakMsg = '3 settled! You\'re on a roll! 🎯';
      else if (streak === 5) streakMsg = '5 down! Admin MVP! 🏆';
      else if (streak > 5 && streak % 5 === 0) streakMsg = `${streak} matches settled! Legend! 🔥`;

      const TEAM_REACTIONS = {
        france:    ['France again?! 🇫🇷 Zizou vibes!', 'Les Bleus deliver! 💙'],
        brazil:    ['Samba time! 🇧🇷⚽', 'Brazil wins! Carnival!'],
        argentina: ['¡Vamos Argentina! 🇦🇷', 'Messi magic?! 🌟'],
        england:   ['It\'s coming home?? 🏴󠁧󠁢󠁥󠁮󠁧󠁿', '3 Lions roar!'],
        germany:   ['Efficient as always 🇩🇪', 'Das Mannschaft!'],
        spain:     ['¡Olé! Tiki-taka! 🇪🇸', 'Spain dominates!'],
        portugal:  ['Portugal deliver! 🇵🇹', 'Os Navegadores!'],
        morocco:   ['Morocco shocks again! 🇲🇦', 'Atlas Lions! 🦁'],
        usa:       ['USA! USA! USA! 🦅', 'The hosts deliver!'],
        japan:     ['Blue Samurai strike! 🇯🇵⚡', 'Japan surprises!'],
        draw:      ['A draw?! Nobody happy! 😅', 'All square!'],
      };

      let teamMsg = null;
      if (winnerLower === 'draw' || winnerLower.includes('draw')) {
        const d = TEAM_REACTIONS.draw;
        teamMsg = d[Math.floor(Math.random() * d.length)];
      } else {
        for (const [team, quips] of Object.entries(TEAM_REACTIONS)) {
          if (team !== 'draw' && winnerLower.includes(team)) {
            teamMsg = quips[Math.floor(Math.random() * quips.length)];
            break;
          }
        }
      }

      const fallbacks = ['Result in! 🏆', 'History made! ⚽', 'The refs have spoken!'];
      mascotRef.current.celebrate(streakMsg || teamMsg || fallbacks[Math.floor(Math.random() * fallbacks.length)]);
    } else {
      mascotRef.current.celebrate();
    }
  }, [toast]);

  // Tab quips — contextual insights when data available, generic quips otherwise
  const TAB_QUIPS = {
    overview:    ['Let\'s see those numbers! 📊', 'Campaign check! 👀', 'How are we doing?'],
    matches:     ['Any upsets today? ⚽', 'World Cup chaos!', 'The beautiful game!'],
    create:      ['Scheduling a banger! 📅', 'New match incoming!'],
    settle:      ['Who won? Who won? 🏆', 'Decision time!'],
    predictions: ['Bold picks out there! 😮', 'Checking the crowd...', 'People are brave!'],
    outlets:     ['Outlet check! 📍', 'Which branch is winning?'],
    billdata:    ['Show me the receipts! 🧾', 'Crunching numbers...'],
    advertising: ['Ad boss mode! 📢', 'Campaign manager!'],
    flags:       ['So many countries! 🌍', 'Vexillology time!'],
    content:     ['Words are power! ✏️', 'Making it sound good!'],
    settings:    ['Handle with care! ⚙️', 'Tread carefully...'],
    audit:       ['Nothing escapes the log! 🔍', 'Eyes on everything!'],
  };
  useEffect(() => {
    if (isFirstTabRef.current) { isFirstTabRef.current = false; return; }
    if (!mascotRef.current) return;
    if (tab === 'draw') { mascotRef.current.celebrate('Lucky draw time! 🎉'); return; }

    const preds = livePredictions || [];

    if (tab === 'predictions' && preds.length > 0) {
      const settled = preds.filter(p => p.isCorrect !== null);
      if (settled.length > 0) {
        const rate = Math.round(settled.filter(p => p.isCorrect).length / settled.length * 100);
        const msg = rate < 25 ? `Only ${rate}% correct… wild tournament! 🎲`
                  : rate > 70 ? `${rate}% accuracy! The crowd is smart! 🧠`
                  : `${rate}% of predictions correct so far 📊`;
        mascotRef.current.say(msg, 15000);
        return;
      }
    }

    if (tab === 'overview' && preds.length > 0) {
      const counts = {};
      for (const p of preds) { if (p.outlet) counts[p.outlet] = (counts[p.outlet] || 0) + 1; }
      const top = Object.entries(counts).sort((a, b) => b[1] - a[1])[0];
      if (top) { mascotRef.current.say(`${top[0]} leads with ${top[1]} predictions! 🏆`, 15000); return; }
    }

    if (tab === 'outlets' && preds.length > 0) {
      const outlets = new Set(preds.map(p => p.outlet).filter(Boolean));
      mascotRef.current.say(`${outlets.size} outlets have predictions so far 📍`, 15000);
      return;
    }

    const quips = TAB_QUIPS[tab];
    if (quips) mascotRef.current.say(quips[Math.floor(Math.random() * quips.length)], 15000);
  }, [tab]);

  // Prediction milestones + spike detection
  useEffect(() => {
    if (!livePredictions || !mascotRef.current) return;
    const count = livePredictions.length;
    const prev = prevPredCountRef.current;
    prevPredCountRef.current = count;
    if (prev === 0) return;
    const delta = count - prev;
    if (delta >= 15) {
      mascotRef.current.say(`+${delta} new predictions just rolled in! 🔥`, 15000);
      return;
    }
    for (const m of [50, 100, 200, 500, 1000]) {
      if (prev < m && count >= m) { mascotRef.current.celebrate(`${m} predictions! 🎉`); break; }
    }
  }, [livePredictions]);

  // Team pick dominance — if 80%+ of recent 10 picks are same team, Pip comments (once per team)
  useEffect(() => {
    if (!livePredictions || livePredictions.length < 5 || !mascotRef.current) return;
    const recent = livePredictions.slice(0, 10);
    const picks = {};
    for (const p of recent) { if (p.pick) picks[p.pick] = (picks[p.pick] || 0) + 1; }
    const top = Object.entries(picks).sort((a, b) => b[1] - a[1])[0];
    if (top && top[1] / recent.length >= 0.8 && teamStreakAlertedRef.current !== top[0]) {
      teamStreakAlertedRef.current = top[0];
      const pct = Math.round(top[1] / recent.length * 100);
      mascotRef.current.say(`${pct}% picked ${top[0]}! Brave or following the crowd? 🐑`, 15000);
    }
  }, [livePredictions]);

  // Bill-to-prediction gap — alerts once if activation rate < 40%
  useEffect(() => {
    if (!livePredictions || billEntriesCount === 0 || !mascotRef.current) return;
    if (billGapAlertedRef.current) return;
    const uniqueBills = new Set(livePredictions.map(p => p.billNumber).filter(Boolean)).size;
    const rate = Math.round(uniqueBills / billEntriesCount * 100);
    if (rate < 40) {
      billGapAlertedRef.current = true;
      mascotRef.current.say(`Only ${rate}% of bill holders predicted! Push it! 📢`, 15000);
    }
  }, [livePredictions, billEntriesCount]);

  // Zero-prediction match alert — once per match per session
  useEffect(() => {
    if (!livePredictions || !matchesState.length || !mascotRef.current) return;
    const predsByMatch = {};
    for (const p of livePredictions) { if (p.matchId) predsByMatch[p.matchId] = true; }
    const openEmpty = matchesState.filter(m => m.status === 'OPEN' && !predsByMatch[m.id] && !zeroAlertedRef.current.has(m.id));
    if (openEmpty.length > 0) {
      const m = openEmpty[0];
      zeroAlertedRef.current.add(m.id);
      const label = (m.teamA?.name && m.teamB?.name) ? `${m.teamA.name} vs ${m.teamB.name}` : (m.matchLabel || 'A match');
      mascotRef.current.say(`"${label}" has 0 predictions! Spread the word! 📢`, 15000);
    }
  }, [livePredictions, matchesState]);

  // Match countdown panic — warns 30 min before kickoff (once per match per session)
  useEffect(() => {
    const check = () => {
      const now = Date.now();
      for (const m of matchesState) {
        if (countdownAlertedRef.current.has(m.id)) continue;
        const kickoff = m.kickoffMs || (m.kickoffAt && m.kickoffAt.getTime());
        if (!kickoff) continue;
        const min = Math.round((kickoff - now) / 60000);
        if (min > 0 && min <= 30 && (m.status === 'OPEN' || m.status === 'SCHEDULED')) {
          countdownAlertedRef.current.add(m.id);
          const label = (m.teamA?.name && m.teamB?.name) ? `${m.teamA.name} vs ${m.teamB.name}` : (m.matchLabel || 'Match');
          if (mascotRef.current) mascotRef.current.error(`⚠️ ${label} in ${min} min!`);
          break;
        }
      }
    };
    check();
    const id = setInterval(check, 60000);
    return () => clearInterval(id);
  }, [matchesState]);

  // Quiet hour warning — once per session, checks every 15 min
  useEffect(() => {
    let warned = false;
    const check = () => {
      const h = new Date().getHours();
      if (h >= 0 && h < 5 && !warned) {
        warned = true;
        const timeStr = new Date().toLocaleTimeString('en-MV', { hour: '2-digit', minute: '2-digit' });
        if (mascotRef.current) mascotRef.current.say(`It's ${timeStr}! Go to bed!! 😴 I'll watch the data`, 15000);
      }
    };
    check();
    const id = setInterval(check, 15 * 60 * 1000);
    return () => clearInterval(id);
  }, []);

  // Inactivity sleep — nods off after 5 min, wakes on first move
  useEffect(() => {
    let idleTimer; let asleep = false;
    const resetIdle = () => {
      clearTimeout(idleTimer);
      if (asleep) { asleep = false; if (mascotRef.current) mascotRef.current.wave(); }
      idleTimer = setTimeout(() => {
        asleep = true;
        if (mascotRef.current) mascotRef.current.think(true, 'zzz… 😴');
      }, 5 * 60 * 1000);
    };
    window.addEventListener('mousemove', resetIdle, { passive: true });
    window.addEventListener('keydown', resetIdle, { passive: true });
    resetIdle();
    return () => {
      clearTimeout(idleTimer);
      window.removeEventListener('mousemove', resetIdle);
      window.removeEventListener('keydown', resetIdle);
    };
  }, []);

  // Keyboard shortcut: P → Pip waves
  useEffect(() => {
    const onKey = (e) => {
      if (e.key !== 'p' && e.key !== 'P') return;
      const t = e.target;
      if (t.tagName === 'INPUT' || t.tagName === 'TEXTAREA' || t.isContentEditable) return;
      if (mascotRef.current) mascotRef.current.wave();
    };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, []);

  // Idle quips — Pip gets chatty every 4–8 min
  useEffect(() => {
    const QUIPS = [
      'Still here! 👋', 'Go Maldives! 🇲🇻', 'Great work today! 🌟',
      'Need a coffee break? ☕', 'MVP admin right here! 🏆', 'Campaign looking strong! 💪',
      '*does a little dance* 🕺', 'Pip approves! ✅', 'World Cup is wild! ⚽',
      'You\'re on fire! 🔥', 'Keep it up! 🙌', 'Press P to say hi! 🐧',
    ];
    let timer;
    const schedule = () => {
      timer = setTimeout(() => {
        if (mascotRef.current) mascotRef.current.say(QUIPS[Math.floor(Math.random() * QUIPS.length)], 15000);
        schedule();
      }, (4 + Math.random() * 4) * 60 * 1000);
    };
    schedule();
    return () => clearTimeout(timer);
  }, []);

  // ── End Pip effects ─────────────────────────────────────────────────────────

  if (!session.user) return <AdminLogin onLogin={session.login} />;

  const titleMap = {
    overview: 'Overview',
    matches: 'All matches',
    create: 'Schedule a new match',
    settle: 'Settle a match',
    draw: 'Run the lucky draw',
    predictions: 'Predictions',
    outlets: 'Outlets',
    billdata: 'Bill data (read-only)',
    advertising: 'Advertising',
    flags: 'Flag images',
    content: 'Content & copy',
    settings: 'Settings',
    sms:      'SMS Center',
    audit:    'Audit log',
  };

  // Secret click chain — click Pip 5× fast for GOAAAL celebration
  function handlePipClick() {
    const chain = clickChainRef.current;
    clearTimeout(chain.timer);
    chain.count++;
    if (chain.count >= 5) {
      chain.count = 0;
      if (mascotRef.current) mascotRef.current.celebrate('GOAAAALLLL!! 🏆⚽🎉');
    } else {
      chain.timer = setTimeout(() => { chain.count = 0; }, 800);
    }
  }

  function doSync() {
    setSyncing(true);
    setTimeout(() => {
      setSyncing(false);
      setToast({ message: 'Match statuses synced. 0 transitions made.', tone: 'success' });
    }, 900);
  }

  const ctx = {
    user: session.user,
    adminToken,
    matchesState, setMatchesState,
    outletsState, setOutletsState,
    contentState, setContentState,
    livePredictions: livePredictions || [],
    predictionsLoading: livePredictions === null,
    predictionsError,
    setToast,
    goTab: setTab,
    mascotRef,
  };

  return (
    <div style={{ display: 'flex', minHeight: '100vh', background: 'var(--grey-50)' }}>
      <AdminToast toast={toast} onDone={() => setToast(null)} />
      <AdminSidebar active={tab} onPick={setTab} openMobile={openMobile} setOpenMobile={setOpenMobile} />
      <div style={{ flex: 1, minWidth: 0, display: 'flex', flexDirection: 'column' }}>
        <AdminTopbar
          user={session.user}
          onLogout={() => { session.logout(); onLeave && onLeave(); }}
          onSync={doSync}
          syncing={syncing}
          title={titleMap[tab] || 'Admin'}
          onMenu={() => setOpenMobile(true)}
        />
        <div className="admin-content-main" style={{
          flex: 1, padding: 22, paddingRight: 136, overflowX: 'hidden',
        }}>
          {tab === 'overview'    && <AdminOverview ctx={ctx} />}
          {tab === 'matches'     && <AdminMatches ctx={ctx} />}
          {tab === 'create'      && <AdminCreate ctx={ctx} />}
          {tab === 'settle'      && <AdminSettle ctx={ctx} />}
          {tab === 'draw'        && <AdminDraw ctx={ctx} />}
          {tab === 'predictions' && <AdminPredictions ctx={ctx} />}
          {tab === 'outlets'     && <AdminOutlets ctx={ctx} />}
          {tab === 'billdata'    && <AdminBillData ctx={ctx} />}
          {tab === 'advertising' && <AdminAdvertising ctx={ctx} />}
          {tab === 'flags'       && <AdminFlags ctx={ctx} />}
          {tab === 'content'     && <AdminContent ctx={ctx} />}
          {tab === 'settings'    && <AdminSettings ctx={ctx} />}
          {tab === 'sms'         && <AdminSMS ctx={ctx} />}
          {tab === 'audit'       && <AdminAuditLog ctx={ctx} />}
        </div>
      </div>

      {/* Pip the Penguin — fixed upper-right, 16px from edge, below topbar */}
      <div className="pip-mascot" style={{ position: 'fixed', right: 16, top: 66, zIndex: 51 }}>
        <PenguinMascot ref={mascotRef} size={110} bubbleBelow bubbleRight onClick={handlePipClick} />
      </div>

      <AdminFigurineLayer tab={tab} />

      <style>{`
        @media (max-width: 900px) {
          .admin-sidebar {
            position: fixed; left: 0; top: 0; bottom: 0; z-index: 40;
            transform: translateX(-100%);
            transition: transform 0.24s cubic-bezier(.2,.7,.2,1);
            box-shadow: 12px 0 24px rgba(0,0,0,0.2);
          }
          .admin-sidebar.open { transform: translateX(0); }
          .pip-mascot { display: none; }
          .admin-content-main { padding-right: 22px !important; }
        }
      `}</style>
    </div>
  );
}

Object.assign(window, {
  AdminApp, AdminLogin, AdminBtn, Panel, AdminSection, timeAgo, useAdminSession,
});
