/* ============================================================
   TRELLIS — shared UI primitives
   Exports to window: Icon, Avatar, Badge, MaskedValue, Sparkline,
   BarRow, StatCard, Toasts, useToasts, EhcwLogo, PoweredBy
   ============================================================ */

// ---------- icon set (simple geometric strokes only) ----------
const ICON_PATHS = {
  dashboard: <g><rect x="3" y="3" width="7.5" height="7.5" rx="2" /><rect x="13.5" y="3" width="7.5" height="7.5" rx="2" /><rect x="3" y="13.5" width="7.5" height="7.5" rx="2" /><rect x="13.5" y="13.5" width="7.5" height="7.5" rx="2" /></g>,
  clients: <g><circle cx="9" cy="8" r="3.5" /><path d="M3.5 19.5c0-3 2.5-5 5.5-5s5.5 2 5.5 5" /><circle cx="17" cy="9" r="2.5" /><path d="M16.5 14.6c2.3.3 4 2 4 4.4" /></g>,
  sprout: <g><path d="M12 21v-8" /><path d="M12 13c0-3.5-2.7-6-6.5-6C5.5 10.5 8 13 12 13z" /><path d="M12 10c0-3 2.3-5.5 6.5-5.5C18.5 8.5 16 11 12 11z" /></g>,
  database: <g><ellipse cx="12" cy="5.5" rx="7.5" ry="2.8" /><path d="M4.5 5.5v13c0 1.5 3.4 2.8 7.5 2.8s7.5-1.3 7.5-2.8v-13" /><path d="M4.5 12c0 1.5 3.4 2.8 7.5 2.8s7.5-1.3 7.5-2.8" /></g>,
  import: <g><path d="M12 3v10" /><path d="M8 9.5l4 4 4-4" /><path d="M4 16v2.5A2.5 2.5 0 0 0 6.5 21h11a2.5 2.5 0 0 0 2.5-2.5V16" /></g>,
  report: <g><rect x="5" y="3" width="14" height="18" rx="2.5" /><path d="M9 8.5h6" /><path d="M9 12.5h6" /><path d="M9 16.5h3.5" /></g>,
  box: <g><path d="M3.5 8L12 3.5 20.5 8v8L12 20.5 3.5 16z" /><path d="M3.5 8L12 12.5 20.5 8" /><path d="M12 12.5v8" /></g>,
  sliders: <g><path d="M4 7h16" /><circle cx="9" cy="7" r="2.2" fill="var(--bg)" /><path d="M4 16h16" /><circle cx="15.5" cy="16" r="2.2" fill="var(--bg)" /></g>,
  lock: <g><rect x="5.5" y="10.5" width="13" height="9.5" rx="2.5" /><path d="M8.5 10.5V8a3.5 3.5 0 0 1 7 0v2.5" /></g>,
  unlock: <g><rect x="5.5" y="10.5" width="13" height="9.5" rx="2.5" /><path d="M8.5 10.5V8a3.5 3.5 0 0 1 6.8-1.2" /></g>,
  eye: <g><path d="M2.5 12s3.5-6 9.5-6 9.5 6 9.5 6-3.5 6-9.5 6-9.5-6-9.5-6z" /><circle cx="12" cy="12" r="2.8" /></g>,
  search: <g><circle cx="11" cy="11" r="6.5" /><path d="M16 16l4.5 4.5" /></g>,
  sun: <g><circle cx="12" cy="12" r="4" /><path d="M12 2.5v2.5M12 19v2.5M2.5 12H5M19 12h2.5M5.3 5.3l1.8 1.8M16.9 16.9l1.8 1.8M18.7 5.3l-1.8 1.8M7.1 16.9l-1.8 1.8" /></g>,
  moon: <g><path d="M20 14.5A8.5 8.5 0 0 1 9.5 4a8.5 8.5 0 1 0 10.5 10.5z" /></g>,
  plus: <g><path d="M12 5v14M5 12h14" /></g>,
  x: <g><path d="M6 6l12 12M18 6L6 18" /></g>,
  check: <g><path d="M4.5 12.5l5 5 10-11" /></g>,
  chevR: <g><path d="M9 5l7 7-7 7" /></g>,
  chevL: <g><path d="M15 5l-7 7 7 7" /></g>,
  chevD: <g><path d="M5 9l7 7 7-7" /></g>,
  mail: <g><rect x="3" y="5" width="18" height="14" rx="2.5" /><path d="M3.5 7l8.5 6 8.5-6" /></g>,
  calendar: <g><rect x="3.5" y="5" width="17" height="15.5" rx="2.5" /><path d="M3.5 10h17M8 2.8V7M16 2.8V7" /></g>,
  spark: <g><path d="M12 3l1.8 6 6.2 1.5-6.2 2L12 19l-1.8-6.5L4 10.5 10.2 9z" /></g>,
  refresh: <g><path d="M20 11.5A8 8 0 1 0 18 16" /><path d="M20 5v6.5h-6.5" /></g>,
  menu: <g><path d="M4 7h16M4 12h16M4 17h16" /></g>,
  logout: <g><path d="M14 4h4a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2h-4" /><path d="M10 8l-4 4 4 4M6 12h10" /></g>,
  shield: <g><path d="M12 3l7.5 3v5.5c0 4.5-3 8-7.5 9.5-4.5-1.5-7.5-5-7.5-9.5V6z" /><path d="M9 12l2.2 2.2L15.5 10" /></g>,
  table: <g><rect x="3" y="4.5" width="18" height="15" rx="2" /><path d="M3 9.5h18M9.5 9.5v10M15.5 9.5v10" /></g>,
  download: <g><path d="M12 4v11" /><path d="M8 11.5l4 4 4-4" /><path d="M4.5 19.5h15" /></g>,
  filter: <g><path d="M4 6h16M7.5 12h9M10.5 18h3" /></g>,
  bell: <g><path d="M6 10a6 6 0 0 1 12 0c0 4 1.5 5.5 1.5 5.5h-15S6 14 6 10z" /><path d="M10 19a2 2 0 0 0 4 0" /></g>,
  clock: <g><circle cx="12" cy="12" r="8.5" /><path d="M12 7.5V12l3.5 2" /></g>,
  alert: <g><path d="M12 3.5L2.5 19.5h19z" /><path d="M12 9.5v4.5" /><circle cx="12" cy="16.8" r="0.4" fill="currentColor" /></g>,
  users: <g><circle cx="9" cy="8" r="3.5" /><path d="M3.5 19.5c0-3 2.5-5 5.5-5s5.5 2 5.5 5" /><circle cx="17" cy="9" r="2.5" /><path d="M16.5 14.6c2.3.3 4 2 4 4.4" /></g>
};

// Signature style: duotone strokes + a gold "node" notch on feature icons —
// the Unstoppables icon family, exclusive to this app.
const NODE_ICONS = new Set(['dashboard', 'sprout', 'clients', 'box', 'report', 'import', 'sliders', 'database', 'table', 'spark', 'mail', 'calendar', 'shield', 'bell']);

// Live signed-in user (null in demo mode). Re-renders the consumer when
// Firebase auth state arrives — kills every hardcoded "June Park".
function useEhcwUser() {
  const [, setT] = React.useState(0);
  React.useEffect(() => {
    const b = () => setT(t => t + 1);
    document.addEventListener('ehcw:user', b);
    return () => document.removeEventListener('ehcw:user', b);
  }, []);
  return (window.EHCW_AUTH && window.EHCW_AUTH.getUser()) || null;
}

// Staff avatar: EHCW roster photo (ehcw.ca/contact) by default, then the
// Google account photo, then initials. Used wherever the signed-in person shows.
function PersonAvatar({ name, photo, size = 32, hue = 290 }) {
  const [err, setErr] = React.useState(false);
  const roster = window.TRELLIS_SCHEMA && window.TRELLIS_SCHEMA.photoFor ? window.TRELLIS_SCHEMA.photoFor(name) : null;
  const src = roster || photo || null;
  if (src && !err) {
    return <img src={src} alt={name || ''} onError={() => setErr(true)}
      style={{ width: size, height: size, borderRadius: '50%', objectFit: 'cover', border: '1px solid var(--hairline)', flexShrink: 0, display: 'block' }} />;
  }
  return <Avatar initials={(name || '??').split(' ').map(w => w[0]).join('').slice(0, 2).toUpperCase()} hue={hue} size={size} />;
}

function Icon({ name, size = 20, stroke = 1.7, style = {}, node }) {
  const showNode = node !== undefined ? node : NODE_ICONS.has(name);
  return (
    <svg viewBox="0 0 24 24" width={size} height={size} fill="none"
      stroke="currentColor" strokeWidth={stroke} strokeLinecap="round" strokeLinejoin="round"
      style={{ flexShrink: 0, ...style }} aria-hidden="true">
      {ICON_PATHS[name] || null}
      {showNode && (
        <g>
          <circle cx="20.2" cy="3.8" r="4.4" fill="var(--bg)" stroke="none" opacity="0.9" />
          <circle cx="20.2" cy="3.8" r="2.4" fill="var(--gold-deep)" stroke="none" />
        </g>
      )}
    </svg>
  );
}

// ---------- avatar ----------
function Avatar({ initials, hue = 310, size = 34 }) {
  return (
    <div style={{
      width: size, height: size, borderRadius: '50%', display: 'grid', placeItems: 'center',
      fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: size * 0.36,
      color: `oklch(0.35 0.09 ${hue})`,
      background: `linear-gradient(135deg, oklch(0.88 0.06 ${hue}), oklch(0.8 0.09 ${hue + 40}))`,
      border: '1px solid var(--hairline)', flexShrink: 0
    }}>{initials}</div>
  );
}

// ---------- badge ----------
function Badge({ children, tone = 'neutral' }) {
  const tones = {
    neutral: { bg: 'var(--hover)', c: 'var(--ink-soft)' },
    plum: { bg: 'var(--accent-soft)', c: 'var(--accent)' },
    blue: { bg: 'var(--blue-soft)', c: 'var(--blue)' },
    gold: { bg: 'var(--gold-soft)', c: 'var(--gold-deep)' },
    leaf: { bg: 'var(--leaf-soft)', c: 'var(--leaf)' },
    coral: { bg: 'var(--coral-soft)', c: 'var(--coral)' }
  };
  const t = tones[tone] || tones.neutral;
  return (
    <span style={{
      display: 'inline-flex', alignItems: 'center', gap: 5, padding: '3px 10px',
      borderRadius: 99, fontSize: 12, fontWeight: 600, letterSpacing: '.02em',
      background: t.bg, color: t.c, whiteSpace: 'nowrap'
    }}>{children}</span>
  );
}

// ---------- masked PII value ----------
function MaskedValue({ value, revealed, mono = true }) {
  if (revealed) {
    return <span className={mono ? 'mono' : ''} style={{ fontSize: 13.5 }}>{value}</span>;
  }
  return (
    <span style={{
      display: 'inline-flex', alignItems: 'center', gap: 6, color: 'var(--ink-faint)',
      fontFamily: 'var(--font-mono)', fontSize: 13, letterSpacing: '.12em', userSelect: 'none'
    }}>
      <Icon name="lock" size={12} stroke={2} />••••••••
    </span>
  );
}

// ---------- sparkline ----------
function Sparkline({ data, w = 96, h = 30, hue = 330 }) {
  const min = Math.min(...data), max = Math.max(...data);
  const pts = data.map((v, i) => {
    const x = (i / (data.length - 1)) * (w - 4) + 2;
    const y = h - 3 - ((v - min) / (max - min || 1)) * (h - 8);
    return `${x},${y}`;
  });
  const id = 'sg' + hue + w + data[0];
  return (
    <svg width={w} height={h} viewBox={`0 0 ${w} ${h}`} aria-hidden="true">
      <defs>
        <linearGradient id={id} x1="0" y1="0" x2="0" y2="1">
          <stop offset="0%" stopColor={`oklch(0.7 0.12 ${hue})`} stopOpacity="0.35" />
          <stop offset="100%" stopColor={`oklch(0.7 0.12 ${hue})`} stopOpacity="0" />
        </linearGradient>
      </defs>
      <polygon points={`2,${h} ${pts.join(' ')} ${w - 2},${h}`} fill={`url(#${id})`} />
      <polyline points={pts.join(' ')} fill="none" stroke={`oklch(0.62 0.13 ${hue})`} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
    </svg>
  );
}

// ---------- horizontal bar row ----------
function BarRow({ label, value, max, hue }) {
  return (
    <div style={{ display: 'grid', gridTemplateColumns: '110px 1fr 36px', alignItems: 'center', gap: 12 }}>
      <span style={{ fontSize: 13, fontWeight: 600, color: 'var(--ink-soft)' }}>{label}</span>
      <div style={{ height: 8, borderRadius: 99, background: 'var(--hover)', overflow: 'hidden' }}>
        <div style={{
          width: `${(value / max) * 100}%`, height: '100%', borderRadius: 99,
          background: `linear-gradient(90deg, oklch(0.72 0.11 ${hue}), oklch(0.62 0.13 ${hue + 25}))`,
          transition: 'width .8s var(--ease-spring)'
        }}></div>
      </div>
      <span className="mono" style={{ fontSize: 12.5, color: 'var(--ink-faint)', textAlign: 'right' }}>{value}</span>
    </div>
  );
}

// ---------- toasts ----------
function useToasts() {
  const [toasts, setToasts] = React.useState([]);
  const push = React.useCallback((msg, tone = 'plum') => {
    const id = Date.now() + Math.random();
    setToasts(t => [...t, { id, msg, tone }]);
    setTimeout(() => setToasts(t => t.filter(x => x.id !== id)), 3400);
  }, []);
  return [toasts, push];
}
function Toasts({ toasts }) {
  return (
    <div style={{ position: 'fixed', bottom: 24, left: '50%', transform: 'translateX(-50%)', zIndex: 400, display: 'flex', flexDirection: 'column', gap: 8, alignItems: 'center', pointerEvents: 'none' }}>
      {toasts.map(t => (
        <div key={t.id} className="glass-strong" style={{
          padding: '11px 20px', borderRadius: 99, fontSize: 13.5, fontWeight: 600,
          boxShadow: 'var(--shadow-pop)', animation: 'trellis-rise .35s var(--ease-spring)',
          display: 'flex', alignItems: 'center', gap: 8
        }}>
          <span style={{ width: 7, height: 7, borderRadius: 99, background: 'var(--accent)' }}></span>
          {t.msg}
        </div>
      ))}
    </div>
  );
}

// ---------- EHCW logo ----------
function EhcwLogo({ height = 30, chip = true }) {
  const img = <img src="trellis/assets/ehcw-logo.png" alt="EHCW — Elspeth Heyworth Centre for Women" style={{ height, display: 'block' }} />;
  if (!chip) return img;
  return (
    <div style={{ background: 'oklch(0.99 0.003 95 / 0.92)', padding: '5px 10px', borderRadius: 10, border: '1px solid var(--hairline)', display: 'inline-flex' }}>
      {img}
    </div>
  );
}

// ---------- Powered by Google Cloud + Claude ----------
function GoogleCloudMark({ h = 18 }) {
  return (
    <svg viewBox="0 0 40 32" height={h} aria-label="Google Cloud" style={{ display: 'block' }}>
      <defs>
        <clipPath id="gc-cloud">
          <path d="M20 5.5c5 0 9.2 3.3 10.6 7.8 4 .5 7.4 3.7 7.4 7.9 0 4.6-3.7 8.3-8.3 8.3H10.3C5.7 29.5 2 25.8 2 21.2c0-4.1 3-7.5 7-8.2C10.4 8.6 14.8 5.5 20 5.5z" />
        </clipPath>
      </defs>
      <g clipPath="url(#gc-cloud)">
        <polygon points="0,0 26,0 13,15 0,15" fill="#EA4335" />
        <polygon points="26,0 40,0 40,18 22,18 13,15" fill="#4285F4" />
        <polygon points="0,15 13,15 20,32 0,32" fill="#FBBC05" />
        <polygon points="13,15 22,18 40,18 40,32 20,32" fill="#34A853" />
      </g>
    </svg>
  );
}
function ClaudeMark({ h = 16 }) {
  // radial starburst
  const spokes = [];
  for (let i = 0; i < 12; i++) {
    const a = (i / 12) * Math.PI * 2;
    const r1 = 3.4, r2 = i % 2 === 0 ? 14 : 11.5;
    spokes.push(<line key={i}
      x1={16 + Math.cos(a) * r1} y1={16 + Math.sin(a) * r1}
      x2={16 + Math.cos(a) * r2} y2={16 + Math.sin(a) * r2}
      stroke="#D97757" strokeWidth="3.4" strokeLinecap="round" />);
  }
  return <svg viewBox="0 0 32 32" height={h} aria-label="Claude" style={{ display: 'block' }}>{spokes}</svg>;
}
function PoweredBy({ compact = false }) {
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 14, flexWrap: 'wrap', justifyContent: 'center' }}>
      <span style={{ fontSize: 11.5, fontWeight: 600, letterSpacing: '.14em', textTransform: 'uppercase', color: 'var(--ink-faint)' }}>Powered by</span>
      <span style={{ display: 'inline-flex', alignItems: 'center', gap: 7 }}>
        <GoogleCloudMark h={compact ? 16 : 20} />
        <span style={{ fontFamily: 'var(--font-display)', fontWeight: 600, fontSize: compact ? 13 : 14.5, color: 'var(--ink-soft)', letterSpacing: '-.01em' }}>Google Cloud</span>
      </span>
      <span style={{ width: 1, height: 16, background: 'var(--hairline-strong)' }}></span>
      <span style={{ display: 'inline-flex', alignItems: 'center', gap: 7 }}>
        <ClaudeMark h={compact ? 15 : 18} />
        <span style={{ fontFamily: 'var(--font-display)', fontWeight: 600, fontSize: compact ? 13 : 14.5, color: 'var(--ink-soft)', letterSpacing: '-.01em' }}>Claude</span>
      </span>
    </div>
  );
}

Object.assign(window, { useEhcwUser, PersonAvatar, Icon, Avatar, Badge, MaskedValue, Sparkline, BarRow, useToasts, Toasts, EhcwLogo, PoweredBy });
