// Shared chrome: TopRail, CommandPalette, Sparkline, a tiny useAsync hook.

function useAsync(loader, deps) {
  const [data, setData] = React.useState(null);
  const [error, setError] = React.useState(null);
  const [loading, setLoading] = React.useState(true);
  const reload = React.useCallback(() => {
    let live = true;
    setLoading(true);
    Promise.resolve()
      .then(loader)
      .then(d => { if (live) { setData(d); setError(null); } })
      .catch(e => { if (live) { setError(e); } })
      .finally(() => { if (live) setLoading(false); });
    return () => { live = false; };
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, deps || []);
  React.useEffect(() => reload(), [reload]);
  return { data, error, loading, reload };
}

function useMediaQuery(query) {
  const [matches, setMatches] = React.useState(() =>
    typeof window !== 'undefined' ? window.matchMedia(query).matches : false
  );
  React.useEffect(() => {
    const mql = window.matchMedia(query);
    const handler = (e) => setMatches(e.matches);
    mql.addEventListener('change', handler);
    return () => mql.removeEventListener('change', handler);
  }, [query]);
  return matches;
}

const EVENT_LABEL = {
  contact_created:       { label: 'New lead',           ico: '✳' },
  day_pass_booked:       { label: 'Day pass booked',    ico: '◆' },
  appointment_booked:    { label: 'Appointment booked', ico: '◆' },
  appointment_cancelled: { label: 'Appointment cancelled', ico: '✕' },
  appointment_updated:   { label: 'Appointment updated',  ico: '↻' },
  tommy_escalation:      { label: 'Tommy needs review', ico: '◩' },
  tommy_sent:            { label: 'SMS sent',           ico: '→' },
  sms_inbound:           { label: 'Inbound SMS',        ico: '←' },
};
function eventMeta(t) {
  return EVENT_LABEL[t] || { label: String(t || 'event').replace(/_/g, ' '), ico: '•' };
}

function NotificationBell({ onNavigate }) {
  const [count, setCount] = React.useState(0);
  const [open, setOpen] = React.useState(false);
  const [events, setEvents] = React.useState([]);
  const [loading, setLoading] = React.useState(false);
  const wrapRef = React.useRef(null);

  const refreshCount = React.useCallback(async () => {
    try {
      const j = await api.get('/api/v2/events/unread-count');
      setCount(Number(j.count) || 0);
    } catch {}
  }, []);

  React.useEffect(() => {
    refreshCount();
    const onEv = (e) => {
      const d = e.detail || {};
      if (d.event_type || d.kind) refreshCount();
    };
    window.addEventListener('raw:event', onEv);
    const t = setInterval(refreshCount, 60000);
    return () => { clearInterval(t); window.removeEventListener('raw:event', onEv); };
  }, [refreshCount]);

  // Fetch events when dropdown opens
  React.useEffect(() => {
    if (!open) return;
    let live = true;
    setLoading(true);
    api.get('/api/v2/events?limit=30')
      .then(r => { if (live) setEvents(r.events || []); })
      .catch(() => { if (live) setEvents([]); })
      .finally(() => { if (live) setLoading(false); });
    return () => { live = false; };
  }, [open]);

  // Close on outside click / Escape
  React.useEffect(() => {
    if (!open) return;
    function onClick(e) {
      if (!wrapRef.current?.contains(e.target)) setOpen(false);
    }
    function onKey(e) { if (e.key === 'Escape') setOpen(false); }
    document.addEventListener('mousedown', onClick);
    document.addEventListener('keydown', onKey);
    return () => {
      document.removeEventListener('mousedown', onClick);
      document.removeEventListener('keydown', onKey);
    };
  }, [open]);

  const markAll = async () => {
    try {
      await api.post('/api/v2/events/mark-all-read', {});
      setEvents(es => es.map(ev => ({...ev, is_read: true, read_at: new Date().toISOString()})));
      setCount(0);
    } catch {}
  };

  const onEventClick = async (ev) => {
    if (!ev.is_read) {
      try { await api.post(`/api/v2/events/${ev.id}/read`, {}); } catch {}
      setEvents(es => es.map(x => x.id === ev.id ? {...x, is_read: true} : x));
      setCount(c => Math.max(0, c - 1));
    }
    setOpen(false);
    if (ev.contact_id && onNavigate) {
      onNavigate({view:'lead', id: ev.contact_id});
    }
  };

  return (
    <div className="bell-wrap" ref={wrapRef}>
      <button
        className="btn ghost sm bell-btn"
        onClick={() => setOpen(v => !v)}
        title="Notifications"
        aria-label={count > 0 ? `Notifications (${count} unread)` : 'Notifications'}
        aria-expanded={open}
      >
        <svg
          width="16" height="16" viewBox="0 0 24 24" fill="none"
          stroke="currentColor" strokeWidth="1.6"
          strokeLinecap="round" strokeLinejoin="round"
          aria-hidden="true"
        >
          <path d="M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9" />
          <path d="M10.3 21a1.94 1.94 0 0 0 3.4 0" />
        </svg>
        {count > 0 && (
          <span className="bell-badge">{count > 99 ? '99+' : count}</span>
        )}
      </button>

      {open && (
        <div className="bell-dropdown" role="dialog" aria-label="Notifications">
          <div className="bell-hd">
            <span className="bell-hd-title">Notifications</span>
            {count > 0 && (
              <button type="button" className="bell-markall" onClick={markAll}>
                Mark all read
              </button>
            )}
          </div>
          <div className="bell-list">
            {loading && <div className="bell-empty">Loading…</div>}
            {!loading && events.length === 0 && (
              <div className="bell-empty">No recent events</div>
            )}
            {!loading && events.map(ev => {
              const meta = eventMeta(ev.event_type);
              return (
                <button
                  key={ev.id}
                  type="button"
                  className={'bell-item' + (ev.is_read ? '' : ' unread')}
                  onClick={() => onEventClick(ev)}
                >
                  <span className="bell-ico">{meta.ico}</span>
                  <div className="bell-body">
                    <div className="bell-title">
                      {meta.label}
                      {ev.contact_name && <span className="bell-contact"> · {ev.contact_name}</span>}
                    </div>
                    {ev.title && ev.title !== meta.label && (
                      <div className="bell-sub">{ev.title}</div>
                    )}
                  </div>
                  <span className="bell-time">{fmtAgoFrom(ev.created_at)}</span>
                </button>
              );
            })}
          </div>
        </div>
      )}
    </div>
  );
}

function TopRail({ view, onNavigate, contactName, onOpenCmd, user, onSignOut }) {
  const u = user || window.CURRENT_USER || { name: 'Staff', email: '' };
  const badge = staffBadge(u.name || u.email || 'Staff');
  const openMobileNav = () => window.dispatchEvent(new CustomEvent('raw:mobile-nav-open'));
  return (
    <div className="rail">
      <div className="rail-inner">
      <button
        type="button"
        className="mobile-nav-btn"
        onClick={openMobileNav}
        aria-label="Open navigation"
      >
        <span />
        <span />
        <span />
      </button>
      <button
        type="button"
        className="mobile-rail-brand"
        onClick={() => onNavigate({view:'home'})}
        aria-label="Go to dashboard"
      >
        <img src="/app/brand/logos/R-orange.svg" alt="RAW" />
      </button>
      <div className="crumbs">
        <span className="sep">/</span>
        {view === 'home' && <b>Dashboard</b>}
        {view === 'leads' && <>
          <span onClick={() => onNavigate({view:'home'})} style={{cursor:'pointer'}}>Dashboard</span>
          <span className="sep">/</span><b>Leads</b>
        </>}
        {view === 'lead' && <>
          <span onClick={() => onNavigate({view:'home'})} style={{cursor:'pointer'}}>Dashboard</span>
          <span className="sep">/</span>
          <span onClick={() => onNavigate({view:'leads'})} style={{cursor:'pointer'}}>Leads</span>
          <span className="sep">/</span><b>{contactName || '—'}</b>
        </>}
        {view === 'tommy' && <>
          <span onClick={() => onNavigate({view:'home'})} style={{cursor:'pointer'}}>Dashboard</span>
          <span className="sep">/</span><b>Tommy</b>
        </>}
        {view === 'calendar' && <>
          <span onClick={() => onNavigate({view:'home'})} style={{cursor:'pointer'}}>Dashboard</span>
          <span className="sep">/</span><b>Calendar</b>
        </>}
        {view === 'analytics' && <>
          <span onClick={() => onNavigate({view:'home'})} style={{cursor:'pointer'}}>Dashboard</span>
          <span className="sep">/</span><b>Analytics</b>
        </>}
        {view === 'growth' && <>
          <span onClick={() => onNavigate({view:'home'})} style={{cursor:'pointer'}}>Dashboard</span>
          <span className="sep">/</span><b>Growth</b>
        </>}
        {view === 'staff' && <>
          <span onClick={() => onNavigate({view:'home'})} style={{cursor:'pointer'}}>Dashboard</span>
          <span className="sep">/</span><b>Staff</b>
        </>}
        {view === 'settings' && <>
          <span onClick={() => onNavigate({view:'home'})} style={{cursor:'pointer'}}>Dashboard</span>
          <span className="sep">/</span><b>Settings</b>
        </>}
        {view === 'system' && <>
          <span onClick={() => onNavigate({view:'home'})} style={{cursor:'pointer'}}>Dashboard</span>
          <span className="sep">/</span><b>System</b>
        </>}
      </div>
      <div className="spacer" />
      <div className="search-pill" onClick={onOpenCmd}>
        <span style={{fontSize:13}}>Search members, bookings, commands…</span>
        <span className="kbd">
          <span className="kbd-key">⌘</span>
          <span className="kbd-key">K</span>
        </span>
      </div>
      <NotificationBell onNavigate={onNavigate} />
      <div className="user-chip" onClick={() => onNavigate({view:'settings'})} style={{cursor:'pointer'}} title="Account settings">
        <span className="avatar" style={{background: badge.color}}>{badge.initials}</span>
        <span>{(u.name || u.email || 'Staff').split(' ')[0]}</span>
      </div>
      </div>
    </div>
  );
}

function CommandPalette({ open, onClose, onNavigate, onSignOut }) {
  const [q, setQ] = React.useState('');
  const [idx, setIdx] = React.useState(0);
  const [members, setMembers] = React.useState([]);
  const inputRef = React.useRef(null);

  React.useEffect(() => {
    if (open) {
      setQ(''); setIdx(0);
      setTimeout(() => inputRef.current?.focus(), 30);
      // Lazy load members when palette opens. Cheap: 50 at a time.
      const cached = cachedContacts();
      if (cached.length) { setMembers(cached); }
      api.get('/api/v2/leads?limit=50')
        .then(r => { const list = (r?.leads || []).map(adaptLead); cacheContacts(list); setMembers(list); })
        .catch(() => {});
    }
  }, [open]);

  const allItems = React.useMemo(() => {
    const navItems = [
      { group:'Navigate', ico:'◻', label:'Go to Dashboard',   hint:'G H', action:()=> onNavigate({view:'home'}) },
      { group:'Navigate', ico:'◼', label:'Open Leads',         hint:'G L', action:()=> onNavigate({view:'leads'}) },
      { group:'Navigate', ico:'◩', label:'Tommy inbox',        hint:'G T', action:()=> onNavigate({view:'tommy'}) },
      { group:'Navigate', ico:'▦', label:'Calendar',           hint:'G C', action:()=> onNavigate({view:'calendar'}) },
      { group:'Navigate', ico:'⎈', label:'Analytics',          hint:'G A', action:()=> onNavigate({view:'analytics'}) },
      { group:'Navigate', ico:'↗', label:'Growth',             hint:'G G', action:()=> onNavigate({view:'growth'}) },
      { group:'Navigate', ico:'⚙', label:'Settings',           hint:'G ,', action:()=> onNavigate({view:'settings'}) },
    ];
    const memberItems = (members || []).slice(0, 40).map(c => ({
      group:'Members',
      ico: initialsOf(c.name),
      label: c.name, hint: c.stage,
      action: () => onNavigate({view:'lead', id:c.id}),
    }));
    const actions = [
      { group:'Actions', ico:'↻', label:'Sync contacts from GHL', hint:'R', action: async ()=>{
          try { await api.post('/api/v2/admin/sync-contacts', {}); } catch {}
      }},
      { group:'Actions', ico:'⎋', label:'Sign out', hint:'', action: () => onSignOut && onSignOut() },
    ];
    return [...navItems, ...memberItems, ...actions];
  }, [onNavigate, members, onSignOut]);

  const filtered = React.useMemo(() => {
    const n = q.trim().toLowerCase();
    if (!n) return allItems;
    return allItems.filter(i => i.label.toLowerCase().includes(n) || i.group.toLowerCase().includes(n));
  }, [q, allItems]);

  const grouped = React.useMemo(() => {
    const g = {};
    filtered.forEach(i => { (g[i.group] = g[i.group] || []).push(i); });
    return g;
  }, [filtered]);

  const flat = React.useMemo(() => {
    const out = [];
    Object.entries(grouped).forEach(([, items]) => items.forEach(i => out.push(i)));
    return out;
  }, [grouped]);

  React.useEffect(() => { setIdx(0); }, [q]);

  function handleKey(e) {
    if (e.key === 'Escape') { e.preventDefault(); onClose(); return; }
    if (e.key === 'ArrowDown') { e.preventDefault(); setIdx(i => Math.min(flat.length-1, i+1)); return; }
    if (e.key === 'ArrowUp')   { e.preventDefault(); setIdx(i => Math.max(0, i-1)); return; }
    if (e.key === 'Enter')     { e.preventDefault(); flat[idx]?.action(); onClose(); return; }
  }

  if (!open) return null;

  let runningIdx = 0;
  return (
    <div className="cmd-scrim" onClick={onClose}>
      <div className="cmd" onClick={e => e.stopPropagation()}>
        <input
          ref={inputRef}
          className="cmd-input"
          placeholder="Search members, bookings, commands…"
          value={q}
          onChange={e => setQ(e.target.value)}
          onKeyDown={handleKey}
        />
        <div className="cmd-list">
          {flat.length === 0 && <div className="empty">No results</div>}
          {Object.entries(grouped).map(([group, items]) => (
            <div key={group}>
              <div className="cmd-group">{group}</div>
              {items.map(item => {
                const myIdx = runningIdx++;
                return (
                  <div
                    key={group + '·' + item.label + '·' + myIdx}
                    className={'cmd-item' + (myIdx === idx ? ' active' : '')}
                    onMouseEnter={() => setIdx(myIdx)}
                    onClick={() => { item.action(); onClose(); }}
                  >
                    <span className="cmd-ico">{item.ico}</span>
                    <span className="cmd-label">{item.label}</span>
                    <span className="cmd-hint">{item.hint}</span>
                  </div>
                );
              })}
            </div>
          ))}
        </div>
        <div className="cmd-foot">
          <span className="g"><span className="kbd-key">↑</span><span className="kbd-key">↓</span> navigate</span>
          <span className="g"><span className="kbd-key">↵</span> open</span>
          <span className="g"><span className="kbd-key">esc</span> close</span>
          <span style={{marginLeft:'auto'}}>RAW · v2.1.0</span>
        </div>
      </div>
    </div>
  );
}

function Sparkline({ data, color='currentColor', width=96, height=32 }) {
  if (!data || data.length < 2) {
    return <svg className="spark" width={width} height={height} style={{color}} />;
  }
  const max = Math.max(...data), min = Math.min(...data);
  const range = Math.max(1, max - min);
  const step = width / (data.length - 1);
  const points = data.map((v, i) => [i*step, height - ((v - min)/range) * (height-4) - 2]);
  const d = points.map((p, i) => (i===0?'M':'L') + p[0].toFixed(1) + ' ' + p[1].toFixed(1)).join(' ');
  const last = points[points.length-1];
  return (
    <svg className="spark" width={width} height={height} viewBox={`0 0 ${width} ${height}`} style={{color}}>
      <path d={d} fill="none" stroke="currentColor" strokeWidth="1.2" strokeLinecap="round" strokeLinejoin="round" opacity="0.7"/>
      <circle cx={last[0]} cy={last[1]} r="2" fill="currentColor" />
    </svg>
  );
}

// Sidebar icons: 18px stroked SVGs, Lucide-inspired. Colour inherits via
// currentColor so .sb-item.active flips them to var(--signal) with no JS.
const SB_ICON_PROPS = {
  viewBox: '0 0 24 24',
  width: 18,
  height: 18,
  fill: 'none',
  stroke: 'currentColor',
  strokeWidth: 1.75,
  strokeLinecap: 'round',
  strokeLinejoin: 'round',
};
const NAV_ICONS = {
  home: (
    <svg {...SB_ICON_PROPS}>
      <path d="M3 10.5 12 3l9 7.5V20a1 1 0 0 1-1 1h-5v-7h-6v7H4a1 1 0 0 1-1-1v-9.5Z" />
    </svg>
  ),
  leads: (
    <svg {...SB_ICON_PROPS}>
      <path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2" />
      <circle cx="9" cy="7" r="4" />
      <path d="M22 21v-2a4 4 0 0 0-3-3.87" />
      <path d="M16 3.13a4 4 0 0 1 0 7.75" />
    </svg>
  ),
  analytics: (
    <svg {...SB_ICON_PROPS}>
      <line x1="3" y1="20" x2="21" y2="20" />
      <line x1="6" y1="20" x2="6" y2="14" />
      <line x1="12" y1="20" x2="12" y2="6" />
      <line x1="18" y1="20" x2="18" y2="10" />
    </svg>
  ),
  growth: (
    <svg {...SB_ICON_PROPS}>
      <polyline points="23 6 13.5 15.5 8.5 10.5 1 18" />
      <polyline points="17 6 23 6 23 12" />
    </svg>
  ),
  calendar: (
    <svg {...SB_ICON_PROPS}>
      <rect x="3" y="4" width="18" height="18" rx="2" />
      <line x1="16" y1="2" x2="16" y2="6" />
      <line x1="8" y1="2" x2="8" y2="6" />
      <line x1="3" y1="10" x2="21" y2="10" />
    </svg>
  ),
  tommy: (
    <svg {...SB_ICON_PROPS}>
      <path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" />
    </svg>
  ),
  settings: (
    <svg {...SB_ICON_PROPS}>
      <circle cx="12" cy="12" r="3" />
      <path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z" />
    </svg>
  ),
  signout: (
    <svg {...SB_ICON_PROPS}>
      <path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4" />
      <polyline points="16 17 21 12 16 7" />
      <line x1="21" y1="12" x2="9" y2="12" />
    </svg>
  ),
};

// Manual-entry modal for staff to add a lead they met in person or on the
// phone. POSTs to /api/v2/leads (which also round-trips to GHL if the PIT
// is configured). On success, fires a `raw:lead-created` CustomEvent so
// the Sidebar pipeline counts and the Home KPIs refresh.
const LEAD_SOURCES = [
  { value: 'walk-in',     label: 'Walk-in' },
  { value: 'referral',    label: 'Referral' },
  { value: 'facebook-ad', label: 'Paid social' },
  { value: 'website',     label: 'Website' },
  { value: 'manual',      label: 'Other' },
];

function LeadRegistrationModal({ open, onClose }) {
  const [name, setName] = React.useState('');
  const [phone, setPhone] = React.useState('');
  const [email, setEmail] = React.useState('');
  const [source, setSource] = React.useState('walk-in');
  const [notes, setNotes] = React.useState('');
  const [submitting, setSubmitting] = React.useState(false);
  const [error, setError] = React.useState(null);
  const firstFieldRef = React.useRef(null);

  // Reset form and focus name field each time the modal opens
  React.useEffect(() => {
    if (!open) return;
    setName(''); setPhone(''); setEmail('');
    setSource('walk-in'); setNotes('');
    setError(null); setSubmitting(false);
    setTimeout(() => firstFieldRef.current?.focus(), 0);
  }, [open]);

  // Esc closes
  React.useEffect(() => {
    if (!open) return;
    function onKey(e) { if (e.key === 'Escape' && !submitting) onClose(); }
    document.addEventListener('keydown', onKey);
    return () => document.removeEventListener('keydown', onKey);
  }, [open, submitting, onClose]);

  if (!open) return null;

  const canSubmit = name.trim() && phone.trim() && !submitting;

  async function submit(e) {
    e?.preventDefault();
    if (!canSubmit) return;
    setSubmitting(true);
    setError(null);
    try {
      const payload = {
        name: name.trim(),
        phone: phone.trim(),
        email: email.trim() || undefined,
        source,
        notes: notes.trim() || undefined,
      };
      const res = await api.post('/api/v2/leads', payload);
      if (res?.error) throw new Error(res.error);
      window.dispatchEvent(new CustomEvent('raw:lead-created', { detail: res }));
      onClose();
    } catch (err) {
      setError(err?.message || 'Failed to create lead');
      setSubmitting(false);
    }
  }

  return (
    <div
      className="lead-modal-backdrop"
      onMouseDown={(e) => { if (e.target === e.currentTarget && !submitting) onClose(); }}
      role="dialog"
      aria-modal="true"
      aria-labelledby="lead-modal-title"
    >
      <form className="lead-modal-card" onSubmit={submit}>
        <div className="lead-modal-hd">
          <div id="lead-modal-title" className="lead-modal-title">— New Lead</div>
          <button
            type="button"
            className="lead-modal-close"
            onClick={onClose}
            disabled={submitting}
            aria-label="Close"
          >×</button>
        </div>

        <div className="lead-modal-bd">
          <label className="lead-modal-field">
            <span className="lead-modal-lbl">Name <span className="req">*</span></span>
            <input
              ref={firstFieldRef}
              type="text"
              value={name}
              onChange={(e) => setName(e.target.value)}
              placeholder="Jane Doe"
              required
              disabled={submitting}
            />
          </label>

          <label className="lead-modal-field">
            <span className="lead-modal-lbl">Phone <span className="req">*</span></span>
            <input
              type="tel"
              value={phone}
              onChange={(e) => setPhone(e.target.value)}
              placeholder="+1 555 000 1234"
              required
              disabled={submitting}
            />
          </label>

          <label className="lead-modal-field">
            <span className="lead-modal-lbl">Email</span>
            <input
              type="email"
              value={email}
              onChange={(e) => setEmail(e.target.value)}
              placeholder="jane@example.com"
              disabled={submitting}
            />
          </label>

          <label className="lead-modal-field">
            <span className="lead-modal-lbl">Source</span>
            <select
              value={source}
              onChange={(e) => setSource(e.target.value)}
              disabled={submitting}
            >
              {LEAD_SOURCES.map(s => (
                <option key={s.value} value={s.value}>{s.label}</option>
              ))}
            </select>
          </label>

          <label className="lead-modal-field">
            <span className="lead-modal-lbl">Notes</span>
            <textarea
              rows={3}
              value={notes}
              onChange={(e) => setNotes(e.target.value)}
              placeholder="Mentioned wanting to try a day pass next week…"
              disabled={submitting}
            />
          </label>

          {error && <div className="lead-modal-err">{error}</div>}
        </div>

        <div className="lead-modal-ft">
          <button
            type="button"
            className="btn ghost sm"
            onClick={onClose}
            disabled={submitting}
          >Cancel</button>
          <button
            type="submit"
            className="btn primary"
            disabled={!canSubmit}
          >{submitting ? 'Saving…' : 'Create lead'}</button>
        </div>
      </form>
    </div>
  );
}

function Sidebar({ view, onNavigate, onSignOut, onOpenLead }) {
  const pipeline = useAsync(() => api.get('/api/v2/pipeline-counts'), []);
  const pending = useAsync(() => api.get('/api/v2/tommy/pending-approvals').catch(() => ({ approvals: [] })), []);
  const [mobileOpen, setMobileOpen] = React.useState(false);
  const isMobile = useMediaQuery('(max-width: 768px)');
  const drawerRef = React.useRef(null);
  const lastFocusRef = React.useRef(null);

  // Refresh pipeline counts when a new lead is created from the modal.
  React.useEffect(() => {
    function onLead() { pipeline.reload(); }
    window.addEventListener('raw:lead-created', onLead);
    return () => window.removeEventListener('raw:lead-created', onLead);
  }, [pipeline.reload]);
  const [tommyActive, setTommyActive] = React.useState(true);

  React.useEffect(() => {
    function onOpen() { setMobileOpen(true); }
    function onKey(e) { if (e.key === 'Escape') setMobileOpen(false); }
    window.addEventListener('raw:mobile-nav-open', onOpen);
    window.addEventListener('keydown', onKey);
    return () => {
      window.removeEventListener('raw:mobile-nav-open', onOpen);
      window.removeEventListener('keydown', onKey);
    };
  }, []);

  React.useEffect(() => {
    if (!mobileOpen) return;
    const prev = document.body.style.overflow;
    document.body.style.overflow = 'hidden';
    return () => { document.body.style.overflow = prev; };
  }, [mobileOpen]);

  React.useEffect(() => {
    if (!isMobile || !mobileOpen) return;
    lastFocusRef.current = document.activeElement;
    const drawer = drawerRef.current;
    if (drawer) {
      const firstFocusable = drawer.querySelector(
        'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
      );
      (firstFocusable || drawer).focus();
    }

    const onKeyDown = (e) => {
      if (e.key !== 'Tab' || !drawer) return;
      const focusables = drawer.querySelectorAll(
        'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
      );
      if (!focusables.length) return;
      const first = focusables[0];
      const last = focusables[focusables.length - 1];
      if (e.shiftKey && document.activeElement === first) {
        e.preventDefault();
        last.focus();
      } else if (!e.shiftKey && document.activeElement === last) {
        e.preventDefault();
        first.focus();
      }
    };

    document.addEventListener('keydown', onKeyDown);
    return () => {
      document.removeEventListener('keydown', onKeyDown);
      if (lastFocusRef.current && lastFocusRef.current.focus) {
        lastFocusRef.current.focus();
      }
    };
  }, [isMobile, mobileOpen]);

  const go = (next) => {
    onNavigate(next);
    setMobileOpen(false);
  };

  const navItems = [
    { view: 'home',      label: 'Home',      ico: NAV_ICONS.home      },
    { view: 'leads',     label: 'Leads',     ico: NAV_ICONS.leads     },
    { view: 'analytics', label: 'Analytics', ico: NAV_ICONS.analytics },
    { view: 'growth',    label: 'Growth',    ico: NAV_ICONS.growth    },
    { view: 'calendar',  label: 'Calendar',  ico: NAV_ICONS.calendar  },
    { view: 'tommy',     label: 'Tommy',     ico: NAV_ICONS.tommy     },
    { view: 'settings',  label: 'Settings',  ico: NAV_ICONS.settings  },
  ];

  const counts   = pipeline.data?.counts || {};
  const total    = pipeline.data?.total;
  const pending_ = (pending.data?.approvals || pending.data?.pending || []).length;

  const pipelineRows = [
    { label: 'New Lead',           n: counts['NEW LEAD']           || 0, color: 'var(--muted-2)' },
    { label: 'First Touch',        n: counts['FIRST TOUCH']        || 0, color: 'var(--blue)' },
    { label: 'Interested',         n: counts['INTERESTED']         || 0, color: 'var(--warn)' },
    { label: 'Day Pass Scheduled', n: counts['DAY PASS SCHEDULED'] || 0, color: 'var(--signal)' },
    { label: 'Showed',             n: counts['SHOWED']             || 0, color: 'var(--green)' },
  ];

  return (
    <>
    <div
      className={'mobile-scrim' + (mobileOpen ? ' open' : '')}
      onClick={() => setMobileOpen(false)}
      aria-hidden="true"
    />
    <aside
      ref={drawerRef}
      tabIndex={isMobile ? -1 : undefined}
      role={isMobile ? 'dialog' : undefined}
      aria-modal={isMobile && mobileOpen ? 'true' : undefined}
      aria-label={isMobile ? 'Navigation' : undefined}
      className={'sidebar' + (mobileOpen ? ' mobile-open' : '')}
    >
      <button
        type="button"
        className="mobile-nav-close"
        onClick={() => setMobileOpen(false)}
        aria-label="Close navigation"
      >
        <span />
        <span />
      </button>
      <div className="sb-brand" onClick={() => go({view:'home'})} role="button" tabIndex={0}>
        <img src="/app/brand/logos/wordmark-red.svg" alt="RAW" className="sb-brand-img" />
        <span className="sb-brand-sub">Athletic Club, Stuart FL</span>
      </div>

      <div className="sb-section-label">Navigation</div>
      <nav className="sb-nav">
        {navItems.map(item => (
          <button
            key={item.view}
            type="button"
            className={'sb-item' + (view === item.view ? ' active' : '')}
            onClick={() => go({view: item.view})}
          >
            <span className="sb-ico">{item.ico}</span>
            <span className="sb-label">{item.label}</span>
            {item.view === 'tommy' && pending_ > 0 && <span className="sb-ndot" />}
          </button>
        ))}
      </nav>

      <div className="sb-pipeline">
        <div className="sb-pipeline-total">
          <span>Total Contacts</span>
          <b>{total == null ? '—' : Number(total).toLocaleString()}</b>
        </div>
        <div className="sb-pipeline-rows">
          {pipelineRows.map(r => (
            <div key={r.label} className="sb-pipeline-row">
              <span className="sb-pipeline-dot" style={{background: r.color}} />
              <span className="sb-pipeline-label">{r.label}</span>
              <span className="sb-pipeline-n">{r.n}</span>
            </div>
          ))}
        </div>
      </div>

      <div className="sb-bottom">
        <button
          type="button"
          className="sb-lead-btn"
          onClick={() => { onOpenLead?.(); setMobileOpen(false); }}
        >
          + Lead
        </button>

        <button
          type="button"
          className={'sb-tommy' + (tommyActive ? ' on' : '')}
          onClick={() => setTommyActive(v => !v)}
          title="Local UI toggle (server-side Tommy flag is unchanged until this is wired to /api/v2/system/tommy-config)"
        >
          <span className="sb-tommy-dot" />
          <span className="sb-tommy-label">Tommy {tommyActive ? 'Active' : 'Paused'}</span>
          <span className="sb-tommy-toggle-word">Toggle</span>
        </button>

        <button type="button" className="sb-signout" onClick={() => { setMobileOpen(false); onSignOut?.(); }}>
          <span className="sb-signout-ico">{NAV_ICONS.signout}</span>
          <span>Sign out</span>
        </button>
      </div>
    </aside>
    </>
  );
}

Object.assign(window, { Sidebar, TopRail, CommandPalette, LeadRegistrationModal, Sparkline, useAsync, useMediaQuery });
