// UI primitives for DAEV Arbiter
// All React components, no external CSS. Consumes window.DAEV tokens.

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

// ─── Wordmark ───────────────────────────────────────────────
// Canonical Aelethion wordmark — matches the marketing site exactly.
// `Aelethion.` (teal full-stop) with optional `· Arbiter` sub-mark.
// All call sites (TopBar, modals, error states, mobile fallback) should use this.
function Wordmark({ t, size = 20, sub = 'Arbiter', as = 'span' }) {
  const Tag = as;
  return (
    <Tag style={{
      display: 'inline-flex', alignItems: 'baseline', gap: 8,
      fontFamily: t.font.ui,
      letterSpacing: -0.025 * size + 0,
      color: t.fg0,
      lineHeight: 1,
    }}>
      <span style={{ fontSize: size, fontWeight: size >= 19 ? 800 : 700, letterSpacing: -0.025 * size }}>
        Aelethion<span style={{ color: t.accent.base }}>.</span>
      </span>
      {sub && (
        <span style={{
          fontFamily: t.font.mono, fontSize: Math.max(10, size * 0.55),
          fontWeight: 600,
          color: t.fg2,
          letterSpacing: 1.2, textTransform: 'uppercase',
        }}>· {sub}</span>
      )}
    </Tag>
  );
}

// ─── Chip ───────────────────────────────────────────────────
function Chip({ t, tone = 'neutral', children, size = 'md', style = {} }) {
  const palette = {
    neutral: { bg: t.bg2, fg: t.fg1, bd: t.line },
    accent:  { bg: `color-mix(in oklch, ${t.accent.base} 15%, ${t.bg1})`, fg: t.accent.base, bd: `color-mix(in oklch, ${t.accent.base} 35%, ${t.line})` },
    red:     { bg: t.semantic.redBg,   fg: t.semantic.red,   bd: `color-mix(in oklch, ${t.semantic.red} 35%, ${t.line})` },
    green:   { bg: t.semantic.greenBg, fg: t.semantic.green, bd: `color-mix(in oklch, ${t.semantic.green} 35%, ${t.line})` },
    amber:   { bg: t.semantic.amberBg, fg: t.semantic.amber, bd: `color-mix(in oklch, ${t.semantic.amber} 35%, ${t.line})` },
    ghost:   { bg: 'transparent', fg: t.fg2, bd: t.line },
  }[tone];
  const sz = size === 'sm' ? { pad:'2px 6px', fs:10 } : { pad:'3px 8px', fs:11 };
  return (
    <span style={{
      display:'inline-flex', alignItems:'center', gap:4,
      padding: sz.pad,
      background: palette.bg, color: palette.fg,
      border: `1px solid ${palette.bd}`,
      fontFamily: t.font.mono,
      fontSize: sz.fs,
      fontWeight: 500,
      letterSpacing: 0.2,
      textTransform:'uppercase',
      borderRadius: t.radius.sm,
      lineHeight: 1.3,
      ...style,
    }}>{children}</span>
  );
}

// ─── Button ─────────────────────────────────────────────────
function Button({ t, children, variant='ghost', onClick, disabled, icon, style={}, size='md', title }) {
  const [hover, setHover] = useState(false);
  const szs = size === 'lg' ? { pad:'10px 16px', fs:14 } : size === 'sm' ? { pad:'4px 8px', fs:12 } : { pad:'7px 12px', fs:13 };
  const variants = {
    primary: {
      bg: hover ? t.accent.base : t.accent.base,
      fg: t.mode === 'dark' ? 'oklch(0.12 0.01 240)' : 'oklch(0.98 0.005 85)',
      bd: t.accent.base,
      shadow: hover ? `0 0 0 3px ${t.accent.ghost}` : 'none',
    },
    ghost: {
      bg: hover ? t.bg2 : 'transparent',
      fg: t.fg1,
      bd: t.line,
      shadow: 'none',
    },
    solid: {
      bg: hover ? t.bg3 : t.bg2,
      fg: t.fg0,
      bd: t.line,
      shadow: 'none',
    },
    danger: {
      bg: hover ? t.semantic.red : 'transparent',
      fg: hover ? 'white' : t.semantic.red,
      bd: t.semantic.red,
      shadow: 'none',
    },
  }[variant];
  return (
    <button
      onClick={onClick}
      disabled={disabled}
      title={title}
      onMouseEnter={()=>setHover(true)}
      onMouseLeave={()=>setHover(false)}
      style={{
        display:'inline-flex', alignItems:'center', gap:8,
        padding: szs.pad,
        background: variants.bg,
        color: variants.fg,
        border: `1px solid ${variants.bd}`,
        borderRadius: t.radius.sm,
        fontFamily: t.font.ui,
        fontSize: szs.fs,
        fontWeight: variant==='primary' ? 600 : 500,
        letterSpacing: variant==='primary' ? 0.2 : 0,
        cursor: disabled ? 'not-allowed' : 'pointer',
        opacity: disabled ? 0.5 : 1,
        boxShadow: variants.shadow,
        transition: 'background 120ms ease, box-shadow 160ms ease, color 120ms ease',
        ...style,
      }}
    >{icon}{children}</button>
  );
}

// ─── Segmented control ──────────────────────────────────────
function Segmented({ t, options, value, onChange, style={} }) {
  return (
    <div style={{
      display:'inline-flex',
      background: t.bg1,
      border: `1px solid ${t.line}`,
      borderRadius: t.radius.sm,
      padding: 2,
      ...style,
    }}>
      {options.map(o => {
        const active = o.value === value;
        return (
          <button key={o.value}
            onClick={() => onChange(o.value)}
            title={o.title || undefined}
            style={{
              padding: '5px 10px',
              background: active ? t.bg3 : 'transparent',
              color: active ? t.fg0 : t.fg2,
              border: 'none',
              borderRadius: t.radius.sm - 1,
              fontFamily: t.font.ui,
              fontSize: 12,
              fontWeight: active ? 600 : 500,
              cursor: 'pointer',
              display: 'inline-flex', alignItems:'center', gap:6,
              transition:'color 120ms, background 120ms',
            }}>
            {o.icon}{o.label}
          </button>
        );
      })}
    </div>
  );
}

// ─── Panel ──────────────────────────────────────────────────
function Panel({ t, title, right, children, style={}, bodyStyle={} }) {
  return (
    <div style={{
      background: t.bg1,
      border: `1px solid ${t.line}`,
      borderRadius: t.radius.md,
      display:'flex', flexDirection:'column',
      overflow:'hidden',
      ...style,
    }}>
      {title !== undefined && (
        <div style={{
          display:'flex', alignItems:'center', justifyContent:'space-between',
          padding: '10px 14px',
          borderBottom: `1px solid ${t.line}`,
          background: t.bg1,
        }}>
          <div style={{
            fontFamily: t.font.mono, fontSize: 11, fontWeight: 600,
            color: t.fg2, letterSpacing: 0.8, textTransform:'uppercase',
          }}>{title}</div>
          {right}
        </div>
      )}
      <div style={{ flex:1, minHeight:0, ...bodyStyle }}>{children}</div>
    </div>
  );
}

// ─── Code editor (Monaco-style) ─────────────────────────────
function CodeEditor({ t, lines, highlightLine, language = 'python' }) {
  // Single-pass tokenizer — avoids re-matching previously-colored output
  const colors = {
    kw:  t.mode === 'dark' ? 'oklch(0.78 0.12 305)' : 'oklch(0.45 0.15 305)',
    str: t.mode === 'dark' ? 'oklch(0.80 0.12 140)' : 'oklch(0.42 0.15 140)',
    num: t.mode === 'dark' ? 'oklch(0.80 0.13 55)'  : 'oklch(0.50 0.15 55)',
    dec: t.mode === 'dark' ? 'oklch(0.75 0.12 55)'  : 'oklch(0.55 0.13 55)',
    fn:  t.accent.base,
    def: t.fg0,
  };
  const KW = new Set(['from','import','def','return','if','not','for','in','class','as','with','try','except','lambda','True','False','None','else','elif','and','or','is']);
  const esc = (ch) => ch === '<' ? '&lt;' : ch === '>' ? '&gt;' : ch === '&' ? '&amp;' : ch;
  const tok = (s) => {
    let out = '';
    let i = 0;
    while (i < s.length) {
      const c = s[i];
      // strings (f-strings too)
      if (c === '"' || c === "'" || (c === 'f' && (s[i+1]==='"' || s[i+1]==="'"))) {
        const hasF = c === 'f';
        const q = hasF ? s[i+1] : c;
        let j = i + (hasF?2:1);
        while (j < s.length && s[j] !== q) j++;
        const text = s.slice(i, j+1).split('').map(esc).join('');
        out += `<span style="color:${colors.str}">${text}</span>`;
        i = j + 1;
        continue;
      }
      // decorator
      if (c === '@' && /[A-Za-z_]/.test(s[i+1]||'')) {
        let j = i+1;
        while (j < s.length && /[\w.]/.test(s[j])) j++;
        out += `<span style="color:${colors.dec}">${s.slice(i,j)}</span>`;
        i = j; continue;
      }
      // number
      if (/\d/.test(c) && (i===0 || !/[A-Za-z_]/.test(s[i-1]))) {
        let j = i;
        while (j < s.length && /[\d.]/.test(s[j])) j++;
        out += `<span style="color:${colors.num}">${s.slice(i,j)}</span>`;
        i = j; continue;
      }
      // identifier
      if (/[A-Za-z_]/.test(c)) {
        let j = i;
        while (j < s.length && /[\w]/.test(s[j])) j++;
        const word = s.slice(i, j);
        if (KW.has(word)) {
          out += `<span style="color:${colors.kw}">${word}</span>`;
        } else if (s[j] === '(') {
          out += `<span style="color:${colors.fn}">${word}</span>`;
        } else {
          out += word;
        }
        i = j; continue;
      }
      out += esc(c);
      i++;
    }
    return out;
  };
  return (
    <div style={{
      fontFamily: t.font.mono, fontSize: 13, lineHeight: '22px',
      color: t.fg0, background: t.bg1, height:'100%',
      display:'flex', flexDirection:'column',
    }}>
      <div style={{ flex: 1, overflow:'auto', padding:'12px 0' }}>
        {lines.map((ln, i) => {
          const hl = highlightLine === i+1;
          return (
            <div key={i} style={{
              display:'flex',
              background: hl ? `color-mix(in oklch, ${t.semantic.red} 14%, transparent)` : 'transparent',
              borderLeft: hl ? `3px solid ${t.semantic.red}` : `3px solid transparent`,
              padding: '0 16px 0 13px',
              minHeight: 22,
              position:'relative',
            }}>
              <span style={{
                color: hl ? t.semantic.red : t.fg3,
                width: 28, flexShrink:0, textAlign:'right',
                marginRight: 16, userSelect:'none',
                fontVariantNumeric:'tabular-nums',
                fontWeight: hl ? 700 : 400,
              }}>{i+1}</span>
              <span style={{ whiteSpace:'pre', flex:1 }}
                dangerouslySetInnerHTML={{ __html: tok(ln) || '&nbsp;' }} />
              {hl && (
                <span style={{
                  marginLeft: 'auto',
                  fontSize: 9, fontWeight: 700,
                  color: t.semantic.red,
                  letterSpacing: 0.6, textTransform: 'uppercase',
                  alignSelf: 'center',
                  background: `color-mix(in oklch, ${t.semantic.red} 22%, transparent)`,
                  padding: '1px 6px',
                  borderRadius: t.radius.sm,
                  border: `1px solid ${t.semantic.red}`,
                  flexShrink: 0,
                }}>finding</span>
              )}
            </div>
          );
        })}
      </div>
    </div>
  );
}

// ─── Icons (lucide-style, inline SVG) ───────────────────────
const Icon = ({ name, size=14, color='currentColor', stroke=1.75 }) => {
  const paths = {
    play: <polygon points="6 4 20 12 6 20 6 4" fill={color} stroke="none"/>,
    zap: <polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2" fill="none" stroke={color} strokeWidth={stroke} strokeLinejoin="round"/>,
    brain: <g fill="none" stroke={color} strokeWidth={stroke} strokeLinecap="round" strokeLinejoin="round"><path d="M12 5a3 3 0 1 0-5.997.142 4 4 0 0 0-2.526 5.77 4 4 0 0 0 .556 6.588A4 4 0 1 0 12 18Z"/><path d="M12 5a3 3 0 1 1 5.997.142 4 4 0 0 1 2.526 5.77 4 4 0 0 1-.556 6.588A4 4 0 1 1 12 18Z"/></g>,
    chevR: <polyline points="9 6 15 12 9 18" fill="none" stroke={color} strokeWidth={stroke} strokeLinecap="round" strokeLinejoin="round"/>,
    chevD: <polyline points="6 9 12 15 18 9" fill="none" stroke={color} strokeWidth={stroke} strokeLinecap="round" strokeLinejoin="round"/>,
    chevU: <polyline points="18 15 12 9 6 15" fill="none" stroke={color} strokeWidth={stroke} strokeLinecap="round" strokeLinejoin="round"/>,
    plus: <g stroke={color} strokeWidth={stroke} strokeLinecap="round"><line x1="5" y1="12" x2="19" y2="12"/><line x1="12" y1="5" x2="12" y2="19"/></g>,
    search: <g fill="none" stroke={color} strokeWidth={stroke}><circle cx="11" cy="11" r="7"/><line x1="21" y1="21" x2="16" y2="16" strokeLinecap="round"/></g>,
    shield: <path d="M12 3l8 3v5c0 5-3.5 9-8 10-4.5-1-8-5-8-10V6l8-3z" fill="none" stroke={color} strokeWidth={stroke} strokeLinejoin="round"/>,
    x: <g stroke={color} strokeWidth={stroke} strokeLinecap="round"><line x1="6" y1="6" x2="18" y2="18"/><line x1="18" y1="6" x2="6" y2="18"/></g>,
    check: <polyline points="5 12 10 17 19 7" fill="none" stroke={color} strokeWidth={stroke} strokeLinecap="round" strokeLinejoin="round"/>,
    warn: <g fill="none" stroke={color} strokeWidth={stroke} strokeLinejoin="round" strokeLinecap="round"><path d="M12 3L2 20h20L12 3z"/><line x1="12" y1="10" x2="12" y2="14"/><circle cx="12" cy="17" r="0.5" fill={color} stroke="none"/></g>,
    copy: <g fill="none" stroke={color} strokeWidth={stroke} strokeLinejoin="round"><rect x="8" y="8" width="12" height="12" rx="1"/><path d="M16 4H5a1 1 0 0 0-1 1v11"/></g>,
    download: <g fill="none" stroke={color} strokeWidth={stroke} strokeLinecap="round" strokeLinejoin="round"><path d="M12 3v13"/><polyline points="6 11 12 17 18 11"/><line x1="4" y1="21" x2="20" y2="21"/></g>,
    share: <g fill="none" stroke={color} strokeWidth={stroke} strokeLinecap="round" strokeLinejoin="round"><path d="M4 12v7a1 1 0 0 0 1 1h14a1 1 0 0 0 1-1v-7"/><polyline points="16 6 12 2 8 6"/><line x1="12" y1="2" x2="12" y2="15"/></g>,
    filter: <polygon points="3 4 21 4 14 12 14 20 10 17 10 12 3 4" fill="none" stroke={color} strokeWidth={stroke} strokeLinejoin="round"/>,
    dot: <circle cx="12" cy="12" r="3" fill={color} stroke="none"/>,
    settings: <g fill="none" stroke={color} strokeWidth={stroke}><circle cx="12" cy="12" r="3"/><path d="M19 12a7 7 0 0 0-.1-1.2l2-1.5-2-3.4-2.4 1a7 7 0 0 0-2.1-1.2l-.4-2.6h-4l-.4 2.6a7 7 0 0 0-2.1 1.2l-2.4-1-2 3.4 2 1.5a7 7 0 0 0 0 2.4l-2 1.5 2 3.4 2.4-1a7 7 0 0 0 2.1 1.2l.4 2.6h4l.4-2.6a7 7 0 0 0 2.1-1.2l2.4 1 2-3.4-2-1.5c.07-.4.1-.8.1-1.2z" strokeLinejoin="round"/></g>,
    clock: <g fill="none" stroke={color} strokeWidth={stroke} strokeLinecap="round"><circle cx="12" cy="12" r="9"/><polyline points="12 7 12 12 15 14"/></g>,
    hash: <g fill="none" stroke={color} strokeWidth={stroke} strokeLinecap="round"><line x1="5" y1="9" x2="20" y2="9"/><line x1="4" y1="15" x2="19" y2="15"/><line x1="11" y1="3" x2="8" y2="21"/><line x1="16" y1="3" x2="13" y2="21"/></g>,
    history: <g fill="none" stroke={color} strokeWidth={stroke} strokeLinecap="round" strokeLinejoin="round"><path d="M3 12a9 9 0 1 0 3-6.7"/><polyline points="3 4 3 9 8 9"/><polyline points="12 7 12 12 15 14"/></g>,
    home: <g fill="none" stroke={color} strokeWidth={stroke} strokeLinejoin="round"><path d="M3 11l9-8 9 8v9a1 1 0 0 1-1 1h-5v-7h-6v7H4a1 1 0 0 1-1-1z"/></g>,
    arrow_r: <g fill="none" stroke={color} strokeWidth={stroke} strokeLinecap="round" strokeLinejoin="round"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="13 6 19 12 13 18"/></g>,
    circle: <circle cx="12" cy="12" r="8" fill="none" stroke={color} strokeWidth={stroke}/>,
    // entity glyphs
    e_source: <g><circle cx="12" cy="12" r="7" fill="none" stroke={color} strokeWidth={stroke}/><circle cx="12" cy="12" r="2" fill={color} stroke="none"/></g>,
    e_sink:   <circle cx="12" cy="12" r="7" fill={color} stroke={color} strokeWidth={stroke}/>,
    e_sanitizer: <g><circle cx="12" cy="12" r="7" fill="none" stroke={color} strokeWidth={stroke}/><circle cx="12" cy="12" r="3.5" fill="none" stroke={color} strokeWidth={stroke}/></g>,
    e_gate:   <rect x="5" y="5" width="14" height="14" rx="1" fill="none" stroke={color} strokeWidth={stroke}/>,
    e_transform: <polygon points="12 4 20 12 12 20 4 12" fill="none" stroke={color} strokeWidth={stroke} strokeLinejoin="round"/>,
    e_passthrough: <g fill="none" stroke={color} strokeWidth={stroke}><rect x="5" y="9" width="14" height="6" rx="1"/></g>,
    e_use:    <g fill="none" stroke={color} strokeWidth={stroke}><circle cx="12" cy="12" r="7" strokeDasharray="2 2"/></g>,
    e_definition: <polygon points="12 5 19 19 5 19" fill="none" stroke={color} strokeWidth={stroke} strokeLinejoin="round"/>,
  };
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" style={{ display:'inline-block', flexShrink:0 }}>
      {paths[name] || null}
    </svg>
  );
};

Object.assign(window, {
  Wordmark, Chip, Button, Segmented, Panel, CodeEditor, Icon,
});
