/* ============================================================
   F2 UI — Storybook doc panels (window.SB.*)
   Canvas · Controls (knobs) · CodePanel · PropsTable ·
   VariantGallery · A11yPanel · Segmented · Block · highlight
   ============================================================ */
(function () {
  const { Icon, Switch, IconButton, Badge } = window.F2;
  const SB = window.SB;

  /* ---------- syntax highlight (light, on-brand) ---------- */
  function escapeHtml(s) {
    return String(s).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
  }
  function highlight(code) {
    const esc = escapeHtml(code);
    // SINGLE pass: one combined regex so inserted <span> markup is never rescanned
    // (a separate attr pass would otherwise match the ` class=` in our own spans
    // and emit malformed tags like `<span <span ...>`).
    const re = /("[^"]*"|'[^']*'|`[^`]*`)|(&lt;\/?)([A-Za-z][\w.]*)|([A-Za-z_$][\w-]*)(=)(?!=)|\b(const|let|var|function|return|import|from|export|default|new|await)\b/g;
    return esc.replace(re, (m, str, lt, tag, attr, eq, kw) => {
      if (str) return '<span class="tk-str">' + str + '</span>';
      if (lt) return lt + '<span class="tk-tag">' + tag + '</span>';
      if (attr) return '<span class="tk-attr">' + attr + '</span>' + eq;
      if (kw) return '<span class="tk-kw">' + kw + '</span>';
      return m;
    });
  }
  SB.highlight = highlight;

  SB.copy = async function (text, done) {
    try { await navigator.clipboard.writeText(text); done && done(true); }
    catch (e) {
      const ta = document.createElement('textarea');
      ta.value = text; document.body.appendChild(ta); ta.select();
      try { document.execCommand('copy'); done && done(true); } catch (_) { done && done(false); }
      document.body.removeChild(ta);
    }
  };

  /* ---------- mono label ---------- */
  function Mono({ children, style = {} }) {
    return (
      <span style={{
        fontFamily: 'var(--f2-font-mono)', fontSize: 11, fontWeight: 500,
        letterSpacing: '0.16em', textTransform: 'uppercase', color: 'var(--f2-text-muted)', ...style,
      }}>{children}</span>
    );
  }
  SB.Mono = Mono;

  /* ---------- segmented control ---------- */
  function Segmented({ options, value, onChange, size = 'md', 'aria-label': al }) {
    const opts = options.map((o) => (typeof o === 'string' ? { value: o, label: o } : o));
    const h = size === 'sm' ? 28 : 34;
    return (
      <div role="tablist" aria-label={al} style={{
        display: 'inline-flex', alignItems: 'center', gap: 2, padding: 2,
        background: 'var(--f2-surface-sunken)', border: '1px solid var(--f2-border)',
        borderRadius: 'var(--f2-radius-control)',
      }}>
        {opts.map((o) => {
          const on = o.value === value;
          return (
            <button key={o.value} role="tab" aria-selected={on} title={o.title || o.label}
              onClick={() => onChange(o.value)}
              style={{
                display: 'inline-flex', alignItems: 'center', gap: 6, height: h - 4,
                padding: o.icon && !o.label ? '0 8px' : '0 12px', border: 'none', cursor: 'pointer',
                background: on ? 'var(--f2-surface-card)' : 'transparent',
                color: on ? 'var(--f2-text)' : 'var(--f2-text-muted)',
                borderRadius: 7, fontFamily: 'var(--f2-font-mono)', fontSize: 11,
                letterSpacing: '0.08em', textTransform: 'uppercase', fontWeight: 500,
                boxShadow: on ? 'inset 0 0 0 1px var(--f2-border-strong)' : 'none',
                transition: 'background var(--f2-dur-fast) var(--f2-ease), color var(--f2-dur-fast) var(--f2-ease)',
              }}>
              {o.icon && <Icon name={o.icon} size={14} />}
              {o.label}
            </button>
          );
        })}
      </div>
    );
  }
  SB.Segmented = Segmented;

  /* ---------- generic doc block ---------- */
  function Block({ label, count, right, children, style = {} }) {
    return (
      <section style={{ display: 'flex', flexDirection: 'column', gap: 16, ...style }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
          <Mono>{label}</Mono>
          {count != null && <Mono style={{ color: 'var(--f2-text-faint)' }}>· {count}</Mono>}
          <div style={{ flex: 1, height: 1, background: 'var(--f2-border)' }} />
          {right}
        </div>
        {children}
      </section>
    );
  }
  SB.Block = Block;

  /* ---------- the live canvas ---------- */
  function Canvas({ story, values, theme, width }) {
    const isFull = width === 'full';
    const px = { xs: 390, sm: 768, md: 1024 }[width];
    let node = null;
    try { node = story.render ? story.render(values, window.F2) : null; }
    catch (e) { node = <div style={{ color: 'var(--f2-error)', fontFamily: 'var(--f2-font-mono)', fontSize: 13 }}>render error: {String(e.message || e)}</div>; }
    return (
      <div style={{
        border: '1px solid var(--f2-border)', borderRadius: 'var(--f2-radius-md)', overflow: 'hidden',
        background: 'var(--f2-surface)',
      }}>
        <div style={{
          display: 'flex', alignItems: 'center', gap: 10, padding: '9px 14px',
          borderBottom: '1px solid var(--f2-border)', background: 'var(--f2-surface-raised)',
        }}>
          <span style={{ width: 7, height: 7, borderRadius: 2, background: 'var(--f2-accent)' }} />
          <Mono>Preview</Mono>
          <div style={{ flex: 1 }} />
          <Mono style={{ color: 'var(--f2-text-faint)' }}>{isFull ? 'responsive' : `${px}px`} · {theme}</Mono>
        </div>
        <div className="sb-stage" style={{
          padding: story.fill ? 0 : 'clamp(24px, 4vw, 56px)',
          minHeight: story.minH || 300, display: 'flex', alignItems: story.align || 'center',
          justifyContent: 'center', overflow: 'auto',
        }}>
          <div data-theme={theme} style={{
            width: isFull ? '100%' : px, maxWidth: '100%', flex: isFull ? 1 : '0 1 auto',
            background: story.fill ? 'var(--f2-surface)' : 'transparent',
            color: 'var(--f2-text)',
            transition: 'width var(--f2-dur-base) var(--f2-ease)',
            display: 'flex', flexDirection: 'column', alignItems: story.fill ? 'stretch' : 'center',
            justifyContent: 'center', borderRadius: story.fill ? 'var(--f2-radius-sm)' : 0,
            overflow: story.fill ? 'hidden' : 'visible',
          }}>
            {node}
          </div>
        </div>
      </div>
    );
  }
  SB.Canvas = Canvas;

  /* ---------- controls / knobs ---------- */
  function Field({ label, children }) {
    return (
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 16, minHeight: 36 }}>
        <span style={{ fontFamily: 'var(--f2-font-mono)', fontSize: 12, color: 'var(--f2-text-secondary)', letterSpacing: '0.02em' }}>{label}</span>
        <div style={{ display: 'flex', alignItems: 'center', gap: 10, flexShrink: 0 }}>{children}</div>
      </div>
    );
  }

  function NativeSelect({ value, options, onChange }) {
    return (
      <select value={value} onChange={(e) => onChange(e.target.value)} style={{
        height: 32, padding: '0 28px 0 12px', appearance: 'none',
        background: 'var(--f2-surface-raised)', color: 'var(--f2-text)',
        border: '1px solid var(--f2-border-strong)', borderRadius: 'var(--f2-radius-control)',
        fontFamily: 'var(--f2-font-mono)', fontSize: 12, cursor: 'pointer',
        backgroundImage: 'url("data:image/svg+xml,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' width=\'12\' height=\'12\' viewBox=\'0 0 24 24\' fill=\'none\' stroke=\'%238B8F99\' stroke-width=\'2\'%3E%3Cpath d=\'m6 9 6 6 6-6\'/%3E%3C/svg%3E")',
        backgroundRepeat: 'no-repeat', backgroundPosition: 'right 9px center',
      }}>
        {options.map((o) => {
          const v = typeof o === 'string' ? o : o.value;
          const l = typeof o === 'string' ? o : (o.label || o.value);
          return <option key={v} value={v}>{l}</option>;
        })}
      </select>
    );
  }

  function Controls({ story, values, setValues }) {
    const fields = (story.props || []).filter((p) => p.control && p.control !== 'none');
    if (!fields.length) return null;
    const set = (k, v) => setValues((s) => ({ ...s, [k]: v }));
    const reset = () => { const d = {}; (story.props || []).forEach((p) => { if ('default' in p) d[p.name] = p.default; }); setValues(d); };
    return (
      <Block label="Controls" right={
        <button onClick={reset} title="Reset controls" style={{
          display: 'inline-flex', alignItems: 'center', gap: 6, background: 'transparent', border: 'none',
          color: 'var(--f2-text-muted)', cursor: 'pointer', fontFamily: 'var(--f2-font-mono)', fontSize: 11,
          letterSpacing: '0.08em', textTransform: 'uppercase',
        }}><Icon name="RotateCcw" size={13} /> Reset</button>
      }>
        <div style={{
          display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(260px, 1fr))', gap: '4px 40px',
          border: '1px solid var(--f2-border)', borderRadius: 'var(--f2-radius-md)', padding: '14px 20px',
          background: 'var(--f2-surface-card)',
        }}>
          {fields.map((p) => {
            const v = values[p.name];
            let control = null;
            if (p.control === 'boolean') {
              control = <Switch checked={!!v} onChange={(n) => set(p.name, n)} aria-label={p.name} />;
            } else if (p.control === 'select') {
              const opts = p.options || [];
              const short = opts.length <= 4 && opts.every((o) => String(typeof o === 'string' ? o : o.label || o.value).length <= 9);
              control = short
                ? <Segmented size="sm" options={opts} value={v} onChange={(n) => set(p.name, n)} aria-label={p.name} />
                : <NativeSelect value={v} options={opts} onChange={(n) => set(p.name, n)} />;
            } else if (p.control === 'number') {
              control = (
                <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
                  <input type="range" min={p.min ?? 0} max={p.max ?? 100} step={p.step ?? 1} value={v}
                    onChange={(e) => set(p.name, Number(e.target.value))}
                    style={{ width: 120, accentColor: 'var(--f2-accent)' }} />
                  <span style={{ fontFamily: 'var(--f2-font-mono)', fontSize: 12, color: 'var(--f2-text)', width: 34, textAlign: 'right' }}>{v}</span>
                </div>
              );
            } else if (p.control === 'color') {
              control = (
                <div style={{ display: 'flex', gap: 6 }}>
                  {(p.options || []).map((c) => {
                    const cv = typeof c === 'string' ? c : c.value;
                    const on = cv === v;
                    return <button key={cv} title={cv} onClick={() => set(p.name, cv)} style={{
                      width: 24, height: 24, borderRadius: 7, cursor: 'pointer', background: cv,
                      border: on ? '2px solid var(--f2-accent)' : '1px solid var(--f2-border-strong)',
                      outline: on ? '2px solid var(--f2-surface-card)' : 'none', outlineOffset: -3,
                    }} />;
                  })}
                </div>
              );
            } else { /* text */
              control = (
                <input value={v ?? ''} placeholder={p.placeholder || ''} onChange={(e) => set(p.name, e.target.value)} style={{
                  height: 32, width: 168, padding: '0 12px', background: 'var(--f2-surface-raised)',
                  color: 'var(--f2-text)', border: '1px solid var(--f2-border-strong)',
                  borderRadius: 'var(--f2-radius-control)', fontFamily: 'var(--f2-font-body)', fontSize: 14, outline: 'none',
                }} />
              );
            }
            return <Field key={p.name} label={p.name}>{control}</Field>;
          })}
        </div>
      </Block>
    );
  }
  SB.Controls = Controls;

  /* ---------- code panel ---------- */
  function CodePanel({ code }) {
    const [copied, setCopied] = React.useState(false);
    return (
      <Block label="Code" right={
        <button onClick={() => SB.copy(code, (ok) => { setCopied(ok); setTimeout(() => setCopied(false), 1400); })}
          style={{
            display: 'inline-flex', alignItems: 'center', gap: 6, background: 'transparent', border: 'none',
            color: copied ? 'var(--f2-accent-text)' : 'var(--f2-text-muted)', cursor: 'pointer',
            fontFamily: 'var(--f2-font-mono)', fontSize: 11, letterSpacing: '0.08em', textTransform: 'uppercase',
          }}>
          <Icon name={copied ? 'Check' : 'Copy'} size={13} /> {copied ? 'Copied' : 'Copy'}
        </button>
      }>
        <pre className="sb-code" style={{
          margin: 0, padding: '18px 20px', background: 'var(--f2-surface-sunken)',
          border: '1px solid var(--f2-border)', borderRadius: 'var(--f2-radius-md)', overflow: 'auto',
        }}>
          <code style={{ fontFamily: 'var(--f2-font-mono)', fontSize: 13, lineHeight: 1.7, color: 'var(--f2-text-secondary)' }}
            dangerouslySetInnerHTML={{ __html: highlight(code) }} />
        </pre>
      </Block>
    );
  }
  SB.CodePanel = CodePanel;

  /* ---------- props / API table ---------- */
  function PropsTable({ props }) {
    const rows = (props || []).filter((p) => !p.hidden);
    if (!rows.length) return null;
    const cell = { padding: '12px 16px', textAlign: 'left', verticalAlign: 'top', borderBottom: '1px solid var(--f2-border)' };
    const head = { ...cell, fontFamily: 'var(--f2-font-mono)', fontSize: 10.5, letterSpacing: '0.16em', textTransform: 'uppercase', color: 'var(--f2-text-faint)', fontWeight: 500, borderBottom: '1px solid var(--f2-border-strong)' };
    return (
      <Block label="Props" count={rows.length}>
        <div style={{ border: '1px solid var(--f2-border)', borderRadius: 'var(--f2-radius-md)', overflow: 'hidden' }}>
          <table style={{ width: '100%', borderCollapse: 'collapse', background: 'var(--f2-surface-card)' }}>
            <thead><tr>
              <th style={{ ...head, width: '22%' }}>Prop</th>
              <th style={{ ...head, width: '30%' }}>Type</th>
              <th style={{ ...head, width: '14%' }}>Default</th>
              <th style={head}>Description</th>
            </tr></thead>
            <tbody>
              {rows.map((p, i) => (
                <tr key={p.name} style={{ background: i % 2 ? 'transparent' : 'rgba(127,127,127,0.025)' }}>
                  <td style={{ ...cell, ...(i === rows.length - 1 ? { borderBottom: 'none' } : {}) }}>
                    <span style={{ display: 'inline-flex', alignItems: 'center', gap: 6 }}>
                      {p.required && <span title="required" style={{ width: 6, height: 6, borderRadius: 2, background: 'var(--f2-accent)' }} />}
                      <code style={{ fontFamily: 'var(--f2-font-mono)', fontSize: 13, color: 'var(--f2-text)' }}>{p.name}</code>
                    </span>
                  </td>
                  <td style={{ ...cell, ...(i === rows.length - 1 ? { borderBottom: 'none' } : {}) }}>
                    <code style={{ fontFamily: 'var(--f2-font-mono)', fontSize: 12.5, color: 'var(--f2-accent-text)', wordBreak: 'break-word' }}>{p.type}</code>
                  </td>
                  <td style={{ ...cell, ...(i === rows.length - 1 ? { borderBottom: 'none' } : {}) }}>
                    <code style={{ fontFamily: 'var(--f2-font-mono)', fontSize: 12.5, color: 'var(--f2-text-faint)' }}>{'default' in p && p.default !== '' ? String(JSON.stringify(p.default)).replace(/"/g, "'") : '—'}</code>
                  </td>
                  <td style={{ ...cell, ...(i === rows.length - 1 ? { borderBottom: 'none' } : {}), color: 'var(--f2-text-secondary)', fontSize: 14, lineHeight: 1.55 }}>{p.description}</td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      </Block>
    );
  }
  SB.PropsTable = PropsTable;

  /* ---------- variant gallery ---------- */
  function VariantGallery({ examples, theme }) {
    if (!examples || !examples.length) return null;
    return (
      <Block label="Variants & states" count={examples.length}>
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(240px, 1fr))', gap: 14 }}>
          {examples.map((ex, i) => {
            let node = null;
            try { node = ex.render(window.F2); } catch (e) { node = <span style={{ color: 'var(--f2-error)', fontSize: 12 }}>err</span>; }
            return (
              <div key={i} style={{ display: 'flex', flexDirection: 'column', border: '1px solid var(--f2-border)', borderRadius: 'var(--f2-radius-md)', overflow: 'hidden' }}>
                <div data-theme={theme} style={{
                  background: 'var(--f2-surface)', padding: ex.fill ? 0 : 28, minHeight: 120,
                  display: 'flex', alignItems: 'center', justifyContent: 'center', flex: 1, overflow: 'hidden',
                }}>{node}</div>
                <div style={{ padding: '10px 14px', borderTop: '1px solid var(--f2-border)', background: 'var(--f2-surface-card)' }}>
                  <div style={{ fontFamily: 'var(--f2-font-mono)', fontSize: 11.5, color: 'var(--f2-text)', letterSpacing: '0.02em' }}>{ex.name}</div>
                  {ex.note && <div style={{ fontSize: 12.5, color: 'var(--f2-text-muted)', marginTop: 3, lineHeight: 1.4 }}>{ex.note}</div>}
                </div>
              </div>
            );
          })}
        </div>
      </Block>
    );
  }
  SB.VariantGallery = VariantGallery;

  /* ---------- accessibility notes ---------- */
  function A11yPanel({ notes }) {
    if (!notes || !notes.length) return null;
    return (
      <Block label="Accessibility">
        <div style={{ display: 'flex', flexDirection: 'column', gap: 12, border: '1px solid var(--f2-border)', borderRadius: 'var(--f2-radius-md)', padding: '18px 20px', background: 'var(--f2-surface-card)' }}>
          {notes.map((n, i) => (
            <div key={i} style={{ display: 'flex', gap: 12, alignItems: 'flex-start' }}>
              <span style={{ marginTop: 2, color: 'var(--f2-success)', flex: '0 0 auto' }}><Icon name="Check" size={16} stroke={2} /></span>
              <span style={{ fontSize: 14.5, color: 'var(--f2-text-secondary)', lineHeight: 1.55 }} dangerouslySetInnerHTML={{ __html: n }} />
            </div>
          ))}
        </div>
      </Block>
    );
  }
  SB.A11yPanel = A11yPanel;
})();
