/* global React, ReactDOM */
/* JXM Brand Standards — Shell (sidebar, topbar, command palette, router) */

const { useState, useEffect, useRef, useMemo, useCallback } = React;

/* ---------------- Nav config ---------------- */
const NAV = [
  { group: 'Get started', items: [
    { id: 'overview',   n: '00', t: 'Overview' },
    { id: 'audiences',  n: '00.1', t: 'Partners - Start here ' },
  ]},
  { group: 'Foundations', items: [
    { id: 'logo',     n: '01', t: 'Logo & mark' },
    { id: 'pattern',  n: '01.1', t: 'Pattern' },
    { id: 'color',    n: '02', t: 'Color' },
    { id: 'type',     n: '03', t: 'Typography' },
    { id: 'spacing',  n: '04', t: 'Spacing & grid', tag: 'New' },
    { id: 'motion',   n: '05', t: 'Motion', tag: 'New' },
    { id: 'photography', n: '06', t: 'Photography', tag: 'New' },
    { id: 'moodboard', n: '07', t: 'Moodboard', tag: 'New' },
    { id: 'video',     n: '08', t: 'Video', tag: 'New' },
  ]},
  { group: 'Voice', items: [
    { id: 'voice',    n: '07', t: 'Principles' },
    { id: 'snippets', n: '07.1', t: 'Copy snippets' },
  ]},
  { group: 'Components', items: [
    { id: 'buttons',  n: '08', t: 'Buttons' },
    { id: 'forms',    n: '08.1', t: 'Forms' },
    { id: 'cards',    n: '08.2', t: 'Cards & nav' },
    { id: 'email-sig', n: '08.3', t: 'Email signature', tag: 'New' },
  ]},
  { group: 'AI prompts', items: [
    { id: 'ai',         n: '09', t: 'Primer', tag: 'AI' },
    { id: 'ai-claude',  n: '09.1', t: 'Claude' },
    { id: 'ai-gpt',     n: '09.2', t: 'ChatGPT' },
    { id: 'ai-mj',      n: '09.3', t: 'Midjourney' },
    { id: 'ai-stitch',  n: '09.4', t: 'Google Stitch' },
  ]},
  { group: 'Resources', items: [
    { id: 'press',    n: '10', t: 'Press kit' },
    { id: 'downloads',n: '11', t: 'Downloads' },
    { id: 'request',  n: '12', t: 'Request an asset' },
  ]},
];

const FLAT_NAV = NAV.flatMap(g => g.items.map(it => ({...it, group: g.group})));

/* ---------------- JXM logo & mark (real SVGs, currentColor for theme) ---------------- */
function JxmLogo({ color = 'currentColor', height = 32 }) {
  return (
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 105.87 42.04" style={{ height, width: 'auto', display: 'block' }} aria-label="JXM" fill={color}>
      <path d="M83.64,9.86c-.92-.38-1.95-.18-2.64.52l-7.11,7.13-7.11-7.13c-.69-.7-1.72-.9-2.64-.52-.92.38-1.5,1.26-1.5,2.24v17.69c0,1.32,1.08,2.42,2.42,2.42h17.67c1.32,0,2.42-1.08,2.42-2.42V12.1c0-.99-.58-1.86-1.5-2.24Z"/>
      <path d="M36.11,9.61h-8.9c-1.34,0-2.42,1.1-2.42,2.45v6.43h-6.82c-.96,0-1.84.58-2.22,1.48-.14.31-.2.65-.2,1.03.09,6.3,5.25,11.41,11.48,11.41v.02h.18c6.25,0,11.32-5.13,11.32-11.41v-8.97c0-1.35-1.1-2.45-2.42-2.45Z"/>
      <path d="M57.02,20.86l4.37-7.6c.43-.76.43-1.7,0-2.45-.45-.74-1.23-1.21-2.11-1.21h-17.37c-.87,0-1.68.47-2.11,1.21-.43.76-.43,1.68,0,2.45l4.37,7.6-4.37,7.6c-.43.76-.45,1.7,0,2.45s1.23,1.21,2.11,1.21h17.37c1.1,0,2.06-.74,2.35-1.8.16-.6.07-1.3-.27-1.88l-4.35-7.58Z"/>
      <path d="M98.56,42.04H7.31c-4.03,0-7.31-3.28-7.31-7.31V7.31C0,3.28,3.28,0,7.31,0h91.25c4.03,0,7.31,3.28,7.31,7.31v27.42c0,4.03-3.28,7.31-7.31,7.31ZM7.31,2c-2.93,0-5.31,2.38-5.31,5.31v27.42c0,2.93,2.38,5.31,5.31,5.31h91.25c2.93,0,5.31-2.38,5.31-5.31V7.31c0-2.93-2.38-5.31-5.31-5.31H7.31Z"/>
    </svg>
  );
}
function JxmMark({ color = 'currentColor', height = 22 }) {
  return (
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 69.59 22.83" style={{ height, width: 'auto', display: 'block' }} aria-label="JXM mark" fill={color}>
      <path d="M68.09.26c-.92-.38-1.95-.18-2.64.52l-7.11,7.13-7.11-7.13c-.69-.7-1.72-.9-2.64-.52-.92.38-1.5,1.26-1.5,2.24v17.69c0,1.32,1.08,2.42,2.42,2.42h17.67c1.32,0,2.42-1.08,2.42-2.42V2.5c0-.99-.58-1.86-1.5-2.24Z"/>
      <path d="M20.56,0h-8.9c-1.34,0-2.42,1.1-2.42,2.45v6.43H2.42c-.96,0-1.84.58-2.22,1.48-.14.31-.2.65-.2,1.03.09,6.3,5.25,11.41,11.48,11.41v.02h.18c6.25,0,11.32-5.13,11.32-11.41V2.45C22.98,1.1,21.88,0,20.56,0Z"/>
      <path d="M41.47,11.26l4.37-7.6c.43-.76.43-1.7,0-2.45-.45-.74-1.23-1.21-2.11-1.21h-17.37c-.87,0-1.68.47-2.11,1.21-.43.76-.43,1.68,0,2.45l4.37,7.6-4.37,7.6c-.43.76-.45,1.7,0,2.45s1.23,1.21,2.11,1.21h17.37c1.1,0,2.06-.74,2.35-1.8.16-.6.07-1.3-.27-1.88l-4.35-7.58Z"/>
    </svg>
  );
}
window.JxmLogo = JxmLogo;
window.JxmMark = JxmMark;

/* ---------------- Icon glyph ---------------- */
function Glyph({ name, size = 16, stroke = 'currentColor' }) {
  const props = { width: size, height: size, viewBox: '0 0 24 24', fill: 'none', stroke, strokeWidth: 1.5, strokeLinecap: 'round', strokeLinejoin: 'round', 'aria-hidden': true };
  switch (name) {
    case 'search': return <svg {...props}><circle cx="11" cy="11" r="7"/><path d="m20 20-3.5-3.5"/></svg>;
    case 'arr':    return <svg {...props}><path d="M5 12h14m-6-6 6 6-6 6"/></svg>;
    case 'arr-up': return <svg {...props}><path d="M5 19 19 5M8 5h11v11"/></svg>;
    case 'copy':   return <svg {...props}><rect x="8" y="8" width="12" height="12" rx="1.5"/><path d="M16 8V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h2"/></svg>;
    case 'check':  return <svg {...props}><path d="m5 12 5 5 9-11"/></svg>;
    case 'x':      return <svg {...props}><path d="M6 6l12 12M18 6 6 18"/></svg>;
    case 'menu':   return <svg {...props}><path d="M4 7h16M4 12h16M4 17h16"/></svg>;
    case 'dl':     return <svg {...props}><path d="M12 4v12m-4-4 4 4 4-4"/><path d="M4 20h16"/></svg>;
    case 'ext':    return <svg {...props}><path d="M14 4h6v6"/><path d="M14 10 20 4M19 13v6a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V6a1 1 0 0 1 1-1h6"/></svg>;
    case 'spark':  return <svg {...props}><path d="M12 3v6m0 6v6M3 12h6m6 0h6M6.5 6.5l4 4m3 3 4 4M6.5 17.5l4-4m3-3 4-4"/></svg>;
    case 'logo':   return <svg {...props}><rect x="3" y="5" width="18" height="14" rx="1"/><path d="M3 12h18M9 5v14"/></svg>;
    case 'palette':return <svg {...props}><path d="M12 3a9 9 0 0 0 0 18c1 0 2-1 2-2 0-2 1-3 3-3h2a4 4 0 0 0 4-4 9 9 0 0 0-11-9"/><circle cx="7" cy="11" r="1"/><circle cx="9" cy="7" r="1"/><circle cx="13" cy="6" r="1"/><circle cx="17" cy="9" r="1"/></svg>;
    case 'type':   return <svg {...props}><path d="M4 7V5h16v2M9 5v14h6V5"/></svg>;
    case 'grid':   return <svg {...props}><path d="M3 9h18M3 15h18M9 3v18M15 3v18"/></svg>;
    case 'motion': return <svg {...props}><circle cx="6" cy="12" r="2"/><path d="M9 12c4 0 6-6 9-6"/></svg>;
    case 'voice':  return <svg {...props}><path d="M4 12c0-4 3-7 8-7s8 3 8 7-3 7-8 7c-1 0-2 0-3-1l-4 1 1-3c-1-1-2-2-2-4Z"/></svg>;
    case 'cmp':    return <svg {...props}><rect x="3" y="3" width="8" height="8" rx="1"/><rect x="13" y="3" width="8" height="8" rx="1"/><rect x="3" y="13" width="8" height="8" rx="1"/><rect x="13" y="13" width="8" height="8" rx="1"/></svg>;
    case 'ai':     return <svg {...props}><path d="M12 3 4 7v6c0 4 3 7 8 8 5-1 8-4 8-8V7l-8-4Z"/><path d="M9 11h6M9 14h4"/></svg>;
    case 'press':  return <svg {...props}><path d="M4 5h12v14H4z"/><path d="M16 8h4v9a2 2 0 0 1-2 2h-2"/><path d="M7 9h6M7 12h6M7 15h4"/></svg>;
    case 'ask':    return <svg {...props}><circle cx="12" cy="12" r="9"/><path d="M9 9a3 3 0 0 1 6 0c0 2-3 2-3 4M12 17h.01"/></svg>;
    default: return null;
  }
}
window.Glyph = Glyph;

/* ---------------- Router (hash) ---------------- */
function useHashRoute() {
  const [route, setRoute] = useState(() => (window.location.hash.replace('#', '') || 'overview'));
  useEffect(() => {
    const onHash = () => {
      const r = window.location.hash.replace('#', '') || 'overview';
      setRoute(r);
      window.scrollTo({ top: 0, behavior: 'instant' });
    };
    window.addEventListener('hashchange', onHash);
    return () => window.removeEventListener('hashchange', onHash);
  }, []);
  const go = useCallback((id) => {
    window.location.hash = id;
  }, []);
  return [route, go];
}
window.useHashRoute = useHashRoute;

/* ---------------- Sidebar ---------------- */
function Sidebar({ route, onNav, onOpenSearch }) {
  return (
    <aside className="sb">
      <div className="sb-head">
        <a href="#overview" onClick={(e) => { e.preventDefault(); onNav('overview'); }} className="sb-mark" aria-label="JXM home">
          <JxmMark height={20} />
        </a>
        <span className="sb-ver">v 2.6</span>
      </div>
      <button className="sb-search-trigger" onClick={onOpenSearch} aria-label="Open search">
        <Glyph name="search" size={13} />
        <span className="flex1">Search the system…</span>
        <span className="kbd">⌘K</span>
      </button>
      <nav className="sb-nav" aria-label="Sections">
        {NAV.map(group => (
          <div className="sb-group" key={group.group}>
            <div className="sb-group-label">{group.group}</div>
            {group.items.map(it => (
              <a
                href={'#' + it.id}
                key={it.id}
                className={'sb-link' + (route === it.id ? ' active' : '')}
                onClick={(e) => { e.preventDefault(); onNav(it.id); }}
              >
                <span className="sb-link-n">{it.n}</span>
                <span>{it.t}</span>
                {it.tag === 'AI' ? (
                  <span className="sb-tag sb-tag-ai" aria-label="AI">
                    <svg width="14" height="14" viewBox="0 0 24 24" fill="var(--ink)" aria-hidden="true">
                      <path d="M12 2.5l2.1 6.4 6.4 2.1-6.4 2.1L12 19.5l-2.1-6.4-6.4-2.1 6.4-2.1L12 2.5z"/>
                      <path d="M19 3l.7 2.3L22 6l-2.3.7L19 9l-.7-2.3L16 6l2.3-.7L19 3z" opacity="0.7"/>
                    </svg>
                  </span>
                ) : it.tag && <span className="sb-tag">{it.tag}</span>}
              </a>
            ))}
          </div>
        ))}
      </nav>
      <div className="sb-foot">
        <a href="mailto:hi@getjxm.com">hi@getjxm.com ↗</a>
        <a href="https://getjxm.com" target="_blank" rel="noopener">getjxm.com ↗</a>
        <span>© JXM 2026</span>
      </div>
    </aside>
  );
}
window.Sidebar = Sidebar;

/* ---------------- Topbar ---------------- */
function Topbar({ route }) {
  const item = FLAT_NAV.find(i => i.id === route) || FLAT_NAV[0];
  return (
    <div className="tb">
      <div className="tb-crumb">
        Brand <span className="tb-crumb-sep">/</span> {item.group} <span className="tb-crumb-sep">/</span> <b>{item.t}</b>
      </div>
      <div className="tb-actions">
        <div className="tb-meta">
          <span>Updated 12 May 2026</span>
          <span className="tb-status">Public</span>
        </div>
        <a href="#request" className="tb-btn" onClick={(e) => { e.preventDefault(); window.location.hash = 'request'; }}>Request asset →</a>
      </div>
    </div>
  );
}
window.Topbar = Topbar;

/* ---------------- Command palette ---------------- */
function CommandPalette({ open, onClose, onNav }) {
  const [q, setQ] = useState('');
  const [idx, setIdx] = useState(0);
  const inputRef = useRef(null);

  // Extra entries that aren't in nav but are searchable
  const EXTRA = useMemo(() => [
    { id: 'color', t: 'Abyss #221F32', sub: 'Primary dark · Color', kind: 'Hex', kw: 'abyss 221F32 dark navy' },
    { id: 'color', t: 'Tusk #F7F2EB', sub: 'Reading ground · Color', kind: 'Hex', kw: 'tusk F7F2EB cream' },
    { id: 'color', t: 'Kermit #49E385', sub: 'Signal accent · Color', kind: 'Hex', kw: 'kermit 49E385 green accent' },
    { id: 'color', t: 'Gator #2EB36A', sub: 'Hover for Kermit & Compassed · Color', kind: 'Hex', kw: 'gator 2EB36A hover green' },
    { id: 'color', t: 'Compassed #FF6464', sub: 'Alert / destructive · Color', kind: 'Hex', kw: 'compassed FF6464 red error' },
    { id: 'color', t: 'Blurple #5E4FF5', sub: 'Restricted · Color', kind: 'Hex', kw: 'blurple 5E4FF5 purple' },
    { id: 'color', t: 'Fly #BDDEED', sub: 'Restricted · Color', kind: 'Hex', kw: 'fly BDDEED sky blue' },
    { id: 'type', t: 'Inter — Display', sub: 'Typography', kind: 'Font', kw: 'inter display headline' },
    { id: 'type', t: 'DM Sans — Body', sub: 'Typography', kind: 'Font', kw: 'dm sans body paragraph' },
    { id: 'type', t: 'IBM Plex Mono — Spec', sub: 'Typography', kind: 'Font', kw: 'plex mono eyebrow' },
    { id: 'ai-claude', t: 'Claude system prompt', sub: 'AI · Primer', kind: 'Prompt', kw: 'claude system prompt anthropic' },
    { id: 'ai-gpt', t: 'ChatGPT system prompt', sub: 'AI · Primer', kind: 'Prompt', kw: 'chatgpt gpt openai system prompt' },
    { id: 'ai-mj', t: 'Midjourney style string', sub: 'AI · Primer', kind: 'Prompt', kw: 'midjourney mj style image' },
    { id: 'snippets', t: 'Boilerplate · 50 words', sub: 'Voice · Copy snippets', kind: 'Snippet', kw: 'boilerplate bio company' },
    { id: 'snippets', t: 'One-liner · "We sell outcomes."', sub: 'Voice · Copy snippets', kind: 'Snippet', kw: 'tagline one-liner' },
    { id: 'voice', t: 'Do / Don\u2019t', sub: 'Voice', kind: 'Guide', kw: 'do dont rules voice writing' },
    { id: 'buttons', t: 'Button hover states', sub: 'Components · Buttons', kind: 'Component', kw: 'button hover gator kermit compassed' },
    { id: 'spacing', t: '8-pt spacing scale', sub: 'Foundations · Spacing', kind: 'Token', kw: 'spacing 8pt scale grid' },
    { id: 'motion', t: 'Easing tokens', sub: 'Foundations · Motion', kind: 'Token', kw: 'motion easing duration' },
    { id: 'press', t: 'Press contact', sub: 'Press kit', kind: 'Contact', kw: 'press media contact' },
    { id: 'downloads', t: 'Brand assets ZIP', sub: 'Downloads', kind: 'Download', kw: 'download zip assets' },
  ], []);

  const results = useMemo(() => {
    const term = q.trim().toLowerCase();
    const sections = FLAT_NAV.map(n => ({ id: n.id, t: n.t, sub: n.group, kind: 'Section', kw: (n.t + ' ' + n.group).toLowerCase() }));
    const all = [...sections, ...EXTRA];
    if (!term) return all.slice(0, 14);
    return all.filter(r => (r.t + ' ' + r.sub + ' ' + r.kw + ' ' + r.kind + ' ' + r.id).toLowerCase().includes(term)).slice(0, 20);
  }, [q, EXTRA]);

  useEffect(() => { if (open) setTimeout(() => inputRef.current?.focus(), 30); }, [open]);
  useEffect(() => { setIdx(0); }, [q, open]);

  useEffect(() => {
    if (!open) return;
    const onKey = (e) => {
      if (e.key === 'Escape') { onClose(); }
      else if (e.key === 'ArrowDown') { e.preventDefault(); setIdx(i => Math.min(i + 1, results.length - 1)); }
      else if (e.key === 'ArrowUp')   { e.preventDefault(); setIdx(i => Math.max(i - 1, 0)); }
      else if (e.key === 'Enter')     { e.preventDefault(); const r = results[idx]; if (r) { onNav(r.id); onClose(); } }
    };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [open, results, idx, onClose, onNav]);

  if (!open) return null;
  return (
    <div className="cp-backdrop" onClick={onClose}>
      <div className="cp" onClick={(e) => e.stopPropagation()}>
        <div className="cp-input">
          <Glyph name="search" size={16} />
          <input
            ref={inputRef}
            value={q}
            onChange={(e) => setQ(e.target.value)}
            placeholder="Search standards, prompts, hex, snippets…"
          />
          <span className="kbd">ESC</span>
        </div>
        <div className="cp-list">
          {results.length === 0 && (
            <div style={{ padding: '24px 18px', fontFamily: 'var(--ff-body)', fontSize: 13, color: 'var(--ink-mute)' }}>
              No matches. Try "hex", "voice", "midjourney"…
            </div>
          )}
          {results.map((r, i) => (
            <div key={i} className={'cp-row' + (i === idx ? ' active' : '')} onMouseEnter={() => setIdx(i)} onClick={() => { onNav(r.id); onClose(); }}>
              <span className="cp-row-icon">
                <Glyph name={r.kind === 'Hex' ? 'palette' : r.kind === 'Font' ? 'type' : r.kind === 'Prompt' ? 'spark' : r.kind === 'Snippet' ? 'voice' : r.kind === 'Component' ? 'cmp' : r.kind === 'Token' ? 'grid' : r.kind === 'Contact' ? 'press' : r.kind === 'Download' ? 'dl' : 'arr'} size={14} />
              </span>
              <span>
                <div className="cp-row-title">{r.t}</div>
                <div className="cp-row-sub">{r.sub}</div>
              </span>
              <span className="cp-row-meta">{r.kind}</span>
            </div>
          ))}
        </div>
        <div className="cp-foot">
          <span><span className="kbd">↑↓</span> navigate <span className="kbd">↵</span> open</span>
          <span><span className="kbd">⌘K</span> toggle</span>
        </div>
      </div>
    </div>
  );
}
window.CommandPalette = CommandPalette;

/* ---------------- CopyButton — small reusable ---------------- */
function CopyButton({ text, label = 'Copy', size = 'sm' }) {
  const [done, setDone] = useState(false);
  const copy = () => {
    if (navigator.clipboard) navigator.clipboard.writeText(text).catch(() => {});
    setDone(true);
    setTimeout(() => setDone(false), 1200);
  };
  return (
    <button className={'copy'} onClick={copy} aria-label={label}>
      <span style={{ display: 'inline-flex', alignItems: 'center', gap: 5 }}>
        <Glyph name={done ? 'check' : 'copy'} size={11} />
        {done ? 'Copied' : label}
      </span>
    </button>
  );
}
window.CopyButton = CopyButton;

/* ---------------- Page header helper ---------------- */
function PageHeader({ eyebrow, title, lede }) {
  return (
    <header>
      <div className="ph-eyebrow">{eyebrow}</div>
      <h1 className="ph-title">{title}</h1>
      {lede && <p className="ph-lede">{lede}</p>}
    </header>
  );
}
window.PageHeader = PageHeader;

function SectionHead({ label, title, meta }) {
  return (
    <div className="sh">
      <div>
        <div className="sh-l">{label}</div>
        <div className="sh-title">{title}</div>
      </div>
      {meta && <div className="sh-meta">{meta}</div>}
    </div>
  );
}
window.SectionHead = SectionHead;
