// Shared UI primitives — buttons, cards, badges, sparkline, avatar, etc.
// All driven by CSS variables defined in theme.jsx.

const cx = (...xs) => xs.filter(Boolean).join(' ');

// ── Avatar ───────────────────────────────────────────────────────────
const Avatar = ({ person, size = 28, ring = false }) => {
  const p = typeof person === 'string' ? PERSON_BY_ID[person] : person;
  if (!p) return null;
  const palette = ['#C55A3C','#5B6F8F','#4A7C59','#A88E54','#7A4A6C','#3F6E78','#9A4A2E','#5C5C7E','#6B8E5A'];
  const idx = (p.id.charCodeAt(p.id.length-1) || 0) % palette.length;
  return (
    <div title={p.name + ' · ' + p.title} style={{
      width: size, height: size, borderRadius: '50%',
      background: palette[idx], color: '#fff',
      display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
      fontSize: size * 0.38, fontWeight: 600, letterSpacing: '0.02em',
      border: ring ? '2px solid var(--apm-card)' : 'none',
      boxShadow: ring ? '0 0 0 1px var(--apm-line-2)' : 'none',
      flex: '0 0 auto',
    }}>{p.initials}</div>
  );
};

const AvatarStack = ({ ids, max = 4, size = 24 }) => {
  const shown = ids.slice(0, max);
  const more  = ids.length - shown.length;
  return (
    <div style={{ display: 'inline-flex' }}>
      {shown.map((id, i) => (
        <div key={id} style={{ marginLeft: i === 0 ? 0 : -size * 0.28 }}>
          <Avatar person={id} size={size} ring />
        </div>
      ))}
      {more > 0 && (
        <div style={{
          width: size, height: size, borderRadius: '50%',
          background: 'var(--apm-bg-sunken)', color: 'var(--apm-muted)',
          display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
          fontSize: size * 0.36, fontWeight: 600,
          marginLeft: -size * 0.28, border: '2px solid var(--apm-card)',
        }}>+{more}</div>
      )}
    </div>
  );
};

// ── Card ─────────────────────────────────────────────────────────────
const Card = ({ children, style, pad = true, hoverable = false, onClick, accent = false }) => (
  <div onClick={onClick} style={{
    background: accent ? 'var(--apm-card-2)' : 'var(--apm-card)',
    border: '1px solid var(--apm-line)',
    borderRadius: 'var(--apm-radius-lg)',
    padding: pad ? 'var(--apm-card-pad)' : 0,
    boxShadow: 'var(--apm-shadow-sm)',
    cursor: onClick ? 'pointer' : 'default',
    transition: 'border-color .12s, box-shadow .12s, transform .12s',
    ...(hoverable && {}),
    ...style,
  }} onMouseEnter={hoverable ? e => {
    e.currentTarget.style.borderColor = 'var(--apm-line-2)';
    e.currentTarget.style.boxShadow = 'var(--apm-shadow-md)';
  } : undefined}
     onMouseLeave={hoverable ? e => {
    e.currentTarget.style.borderColor = 'var(--apm-line)';
    e.currentTarget.style.boxShadow = 'var(--apm-shadow-sm)';
  } : undefined}>
    {children}
  </div>
);

// ── Button ───────────────────────────────────────────────────────────
const Button = ({ children, variant = 'ghost', size = 'md', onClick, icon, style, disabled, type = 'button' }) => {
  const variants = {
    primary: { bg: 'var(--apm-ink)',     fg: 'var(--apm-bg-2)', border: 'var(--apm-ink)' },
    accent:  { bg: 'var(--apm-accent)',  fg: '#fff',            border: 'var(--apm-accent)' },
    outline: { bg: 'transparent',        fg: 'var(--apm-ink)',  border: 'var(--apm-line-2)' },
    ghost:   { bg: 'transparent',        fg: 'var(--apm-ink-2)',border: 'transparent' },
    soft:    { bg: 'var(--apm-bg-sunken)', fg: 'var(--apm-ink)', border: 'var(--apm-bg-sunken)' },
    danger:  { bg: 'var(--apm-risk)',    fg: '#fff',            border: 'var(--apm-risk)' },
  }[variant];
  const sizes = {
    sm: { h: 28, px: 10, fs: 12.5 },
    md: { h: 'var(--apm-input-h)', px: 14, fs: 13.5 },
    lg: { h: 44, px: 18, fs: 14.5 },
  }[size];
  return (
    <button type={type} onClick={onClick} disabled={disabled} style={{
      display: 'inline-flex', alignItems: 'center', gap: 6,
      height: sizes.h, padding: `0 ${sizes.px}px`,
      background: variants.bg, color: variants.fg,
      border: `1px solid ${variants.border}`,
      borderRadius: 'var(--apm-radius)',
      fontFamily: 'var(--apm-font-body)', fontSize: sizes.fs, fontWeight: 500,
      letterSpacing: '0.005em',
      cursor: disabled ? 'not-allowed' : 'pointer',
      opacity: disabled ? 0.5 : 1,
      transition: 'background .12s, border-color .12s, opacity .12s',
      ...style,
    }}
      onMouseEnter={e => { if (!disabled && variant === 'ghost') e.currentTarget.style.background = 'var(--apm-bg-sunken)'; }}
      onMouseLeave={e => { if (!disabled && variant === 'ghost') e.currentTarget.style.background = 'transparent'; }}>
      {icon && <span style={{ marginRight: 2 }}>{icon}</span>}
      {children}
    </button>
  );
};

// ── Input ────────────────────────────────────────────────────────────
const Input = ({ value, onChange, placeholder, type = 'text', style, prefix, ...rest }) => (
  <div style={{
    display: 'flex', alignItems: 'center', gap: 8,
    height: 'var(--apm-input-h)', padding: '0 12px',
    background: 'var(--apm-bg-2)',
    border: '1px solid var(--apm-line)',
    borderRadius: 'var(--apm-radius)',
    ...style,
  }}>
    {prefix && <span style={{ color: 'var(--apm-muted)' }}>{prefix}</span>}
    <input type={type} value={value} onChange={e => onChange?.(e.target.value)} placeholder={placeholder}
      style={{
        flex: 1, border: 'none', outline: 'none', background: 'transparent',
        color: 'var(--apm-ink)', fontFamily: 'var(--apm-font-body)',
        fontSize: 'var(--apm-text-base)',
      }} {...rest} />
  </div>
);

const Textarea = ({ value, onChange, placeholder, rows = 3, style }) => (
  <textarea value={value} onChange={e => onChange?.(e.target.value)} placeholder={placeholder} rows={rows}
    style={{
      width: '100%', resize: 'vertical',
      padding: '10px 12px',
      background: 'var(--apm-bg-2)', color: 'var(--apm-ink)',
      border: '1px solid var(--apm-line)',
      borderRadius: 'var(--apm-radius)',
      fontFamily: 'var(--apm-font-body)', fontSize: 'var(--apm-text-base)',
      lineHeight: 1.5,
      ...style,
    }} />
);

// ── Badge ────────────────────────────────────────────────────────────
const Badge = ({ children, tone = 'neutral', size = 'md', icon, dot, style }) => {
  const tones = {
    neutral: { bg: 'var(--apm-bg-sunken)', fg: 'var(--apm-ink-2)', dot: 'var(--apm-muted)' },
    ok:      { bg: 'var(--apm-ok-soft)',   fg: 'var(--apm-ok)',    dot: 'var(--apm-ok)' },
    warn:    { bg: 'var(--apm-warn-soft)', fg: 'var(--apm-warn)',  dot: 'var(--apm-warn)' },
    risk:    { bg: 'var(--apm-risk-soft)', fg: 'var(--apm-risk)',  dot: 'var(--apm-risk)' },
    info:    { bg: 'var(--apm-info-soft)', fg: 'var(--apm-info)',  dot: 'var(--apm-info)' },
    accent:  { bg: 'var(--apm-accent-soft)', fg: 'var(--apm-accent-ink)', dot: 'var(--apm-accent)' },
    outline: { bg: 'transparent',          fg: 'var(--apm-muted)', dot: 'var(--apm-muted)' },
  }[tone];
  const sizes = { sm: { h: 20, px: 6, fs: 11 }, md: { h: 24, px: 8, fs: 12 }, lg: { h: 28, px: 10, fs: 13 } }[size];
  return (
    <span style={{
      display: 'inline-flex', alignItems: 'center', gap: 5,
      height: sizes.h, padding: `0 ${sizes.px}px`,
      background: tones.bg, color: tones.fg,
      border: tone === 'outline' ? '1px solid var(--apm-line-2)' : 'none',
      borderRadius: 999,
      fontSize: sizes.fs, fontWeight: 500, letterSpacing: '0.01em',
      whiteSpace: 'nowrap',
      ...style,
    }}>
      {dot && <span style={{ width: 6, height: 6, borderRadius: '50%', background: tones.dot }} />}
      {icon}
      {children}
    </span>
  );
};

// ── Phase pill ───────────────────────────────────────────────────────
const PhasePill = ({ phase, active = false }) => {
  const v = APM_PHASE_VAR[phase] || '--apm-phase-arch';
  return (
    <span style={{
      display: 'inline-flex', alignItems: 'center', gap: 5,
      padding: '2px 8px', height: 22,
      background: `color-mix(in oklab, var(${v}) 22%, var(--apm-bg-2))`,
      color: 'var(--apm-ink)',
      borderRadius: 4,
      border: '1px solid ' + `color-mix(in oklab, var(${v}) 50%, var(--apm-line))`,
      fontSize: 11.5, fontWeight: 500, letterSpacing: '0.02em',
    }}>
      <span style={{ width: 6, height: 6, borderRadius: '50%', background: `var(${v})` }} />
      {phase}
    </span>
  );
};

// ── Health bar ───────────────────────────────────────────────────────
const HealthBar = ({ value, height = 6 }) => {
  const tone = value >= 75 ? 'var(--apm-ok)' : value >= 50 ? 'var(--apm-warn)' : 'var(--apm-risk)';
  return (
    <div style={{ height, background: 'var(--apm-bg-sunken)', borderRadius: 999, overflow: 'hidden' }}>
      <div style={{ width: value + '%', height: '100%', background: tone, borderRadius: 999 }} />
    </div>
  );
};

// ── Mini sparkline ───────────────────────────────────────────────────
const Sparkline = ({ values, w = 80, h = 22, stroke = 'var(--apm-ink-2)', fill }) => {
  if (!values || values.length < 2) return null;
  const min = Math.min(...values), max = Math.max(...values), range = max - min || 1;
  const step = w / (values.length - 1);
  const pts = values.map((v, i) => [i * step, h - ((v - min) / range) * (h - 2) - 1]);
  const d = 'M ' + pts.map(([x,y]) => `${x.toFixed(1)},${y.toFixed(1)}`).join(' L ');
  const area = d + ` L ${w},${h} L 0,${h} Z`;
  return (
    <svg width={w} height={h} style={{ display: 'block' }}>
      {fill && <path d={area} fill={fill} opacity="0.5" />}
      <path d={d} stroke={stroke} strokeWidth="1.5" fill="none" strokeLinecap="round" />
    </svg>
  );
};

// ── Tabs ─────────────────────────────────────────────────────────────
const Tabs = ({ tabs, value, onChange, style }) => (
  <div style={{ display: 'flex', gap: 4, borderBottom: '1px solid var(--apm-line)', ...style }}>
    {tabs.map(t => {
      const active = t.id === value;
      return (
        <button key={t.id} onClick={() => onChange(t.id)} style={{
          background: 'transparent', border: 'none',
          padding: '10px 14px',
          fontFamily: 'var(--apm-font-body)', fontSize: 13.5, fontWeight: active ? 600 : 500,
          color: active ? 'var(--apm-ink)' : 'var(--apm-muted)',
          borderBottom: active ? '2px solid var(--apm-ink)' : '2px solid transparent',
          marginBottom: -1, cursor: 'pointer',
          letterSpacing: '0.01em',
        }}>
          {t.label}
          {t.count != null && (
            <span style={{ marginLeft: 6, color: 'var(--apm-muted-2)', fontWeight: 400 }}>{t.count}</span>
          )}
        </button>
      );
    })}
  </div>
);

// ── Section heading ──────────────────────────────────────────────────
const SectionHeading = ({ kicker, title, action, level = 2 }) => {
  const Tag = `h${level}`;
  return (
    <div style={{ display: 'flex', alignItems: 'flex-end', justifyContent: 'space-between', gap: 16, marginBottom: 20 }}>
      <div>
        {kicker && <div style={{
          fontSize: 11, textTransform: 'uppercase', letterSpacing: '0.12em',
          color: 'var(--apm-muted)', marginBottom: 8, fontWeight: 500,
        }}>{kicker}</div>}
        <Tag style={{
          margin: 0,
          fontFamily: 'var(--apm-font-display)',
          fontWeight: 400,
          fontSize: level === 1 ? 'var(--apm-text-3xl)' : 'var(--apm-text-2xl)',
          letterSpacing: '-0.01em', lineHeight: 1.1,
          color: 'var(--apm-ink)',
        }}>{title}</Tag>
      </div>
      {action}
    </div>
  );
};

// ── Stat ─────────────────────────────────────────────────────────────
const Stat = ({ label, value, sub, tone = 'ink', spark }) => {
  const colors = {
    ink:  'var(--apm-ink)', ok: 'var(--apm-ok)', warn: 'var(--apm-warn)', risk: 'var(--apm-risk)',
    accent: 'var(--apm-accent)',
  };
  return (
    <div>
      <div style={{ fontSize: 11.5, color: 'var(--apm-muted)', textTransform: 'uppercase', letterSpacing: '0.1em', fontWeight: 500, marginBottom: 8 }}>{label}</div>
      <div style={{ display: 'flex', alignItems: 'baseline', gap: 8 }}>
        <div style={{ fontFamily: 'var(--apm-font-display)', fontSize: 'var(--apm-text-2xl)', lineHeight: 1, color: colors[tone] }}>{value}</div>
        {sub && <div style={{ fontSize: 12.5, color: 'var(--apm-muted)' }}>{sub}</div>}
      </div>
      {spark && <div style={{ marginTop: 6 }}>{spark}</div>}
    </div>
  );
};

// ── Empty / Hint row ─────────────────────────────────────────────────
const EmptyState = ({ title, body, action, icon }) => (
  <div style={{
    padding: '40px 24px', textAlign: 'center',
    background: 'var(--apm-bg-2)', border: '1px dashed var(--apm-line-2)',
    borderRadius: 'var(--apm-radius-lg)',
  }}>
    {icon && <div style={{ fontSize: 28, marginBottom: 8, color: 'var(--apm-muted)' }}>{icon}</div>}
    <div style={{ fontFamily: 'var(--apm-font-display)', fontSize: 'var(--apm-text-lg)', marginBottom: 4 }}>{title}</div>
    {body && <div style={{ color: 'var(--apm-muted)', fontSize: 13, marginBottom: 16, maxWidth: 440, marginLeft: 'auto', marginRight: 'auto' }}>{body}</div>}
    {action}
  </div>
);

// ── Drawer / Modal ───────────────────────────────────────────────────
const Drawer = ({ open, onClose, children, width = 520, side = 'right' }) => {
  if (!open) return null;
  return (
    <div style={{ position: 'fixed', inset: 0, zIndex: 50 }}>
      <div onClick={onClose} style={{ position: 'absolute', inset: 0, background: 'var(--apm-overlay)' }} />
      <div style={{
        position: 'absolute', top: 0, bottom: 0,
        [side]: 0, width,
        background: 'var(--apm-card)', borderLeft: side === 'right' ? '1px solid var(--apm-line)' : 'none',
        borderRight: side === 'left' ? '1px solid var(--apm-line)' : 'none',
        boxShadow: 'var(--apm-shadow-lg)',
        display: 'flex', flexDirection: 'column',
        animation: 'apm-slide-' + side + ' .18s ease-out',
      }}>{children}</div>
    </div>
  );
};

const Modal = ({ open, onClose, children, width = 640 }) => {
  if (!open) return null;
  return (
    <div style={{ position: 'fixed', inset: 0, zIndex: 60, display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 24 }}>
      <div onClick={onClose} style={{ position: 'absolute', inset: 0, background: 'var(--apm-overlay)' }} />
      <div style={{
        position: 'relative', width: '100%', maxWidth: width,
        maxHeight: '90vh', overflow: 'auto',
        background: 'var(--apm-card)', border: '1px solid var(--apm-line)',
        borderRadius: 'var(--apm-radius-xl)', boxShadow: 'var(--apm-shadow-lg)',
      }}>{children}</div>
    </div>
  );
};

// ── Sensitivity tags ─────────────────────────────────────────────────
const SensitivityTag = ({ id }) => {
  const t = APM_SENSITIVITY.find(s => s.id === id);
  if (!t) return null;
  const tone = id === 'phi' || id === 'pii' ? 'risk' : id === 'srcdata' ? 'warn' : id === 'finint' ? 'info' : 'neutral';
  return <Badge tone={tone} size="sm">{t.label}</Badge>;
};

// ── Health text ──────────────────────────────────────────────────────
const HealthDot = ({ value }) => {
  const m = value === 'on-track' ? { tone: 'ok', label: 'On track' }
          : value === 'at-risk'  ? { tone: 'warn', label: 'At risk' }
          : value === 'blocked'  ? { tone: 'risk', label: 'Blocked' }
          : value === 'done'     ? { tone: 'info', label: 'Done' }
          : { tone: 'neutral', label: value };
  return <Badge tone={m.tone} dot size="sm">{m.label}</Badge>;
};

// ── KBD ──────────────────────────────────────────────────────────────
const Kbd = ({ children }) => (
  <span style={{
    display: 'inline-block', padding: '1px 6px',
    fontFamily: 'var(--apm-font-mono)', fontSize: 11,
    background: 'var(--apm-bg-2)', color: 'var(--apm-muted)',
    border: '1px solid var(--apm-line-2)', borderBottomWidth: 2,
    borderRadius: 4, lineHeight: 1.4,
  }}>{children}</span>
);

// keyframes — injected once
if (typeof document !== 'undefined' && !document.getElementById('apm-keyframes')) {
  const s = document.createElement('style');
  s.id = 'apm-keyframes';
  s.textContent = `
    @keyframes apm-slide-right { from { transform: translateX(20px); opacity: 0; } to { transform: none; opacity: 1; } }
    @keyframes apm-slide-left  { from { transform: translateX(-20px); opacity: 0; } to { transform: none; opacity: 1; } }
    @keyframes apm-fade        { from { opacity: 0; } to { opacity: 1; } }
    @keyframes apm-pop         { from { transform: scale(.96); opacity: 0; } to { transform: none; opacity: 1; } }
    *::-webkit-scrollbar { width: 10px; height: 10px; }
    *::-webkit-scrollbar-thumb { background: var(--apm-line-2); border-radius: 999px; border: 2px solid transparent; background-clip: padding-box; }
    *::-webkit-scrollbar-track { background: transparent; }
  `;
  document.head.appendChild(s);
}

Object.assign(window, {
  cx, Avatar, AvatarStack, Card, Button, Input, Textarea, Badge, PhasePill, HealthBar,
  Sparkline, Tabs, SectionHeading, Stat, EmptyState, Drawer, Modal,
  SensitivityTag, HealthDot, Kbd,
});
