// Shared UI primitives for Norwill scorecard
const { useState, useEffect, useMemo, useRef, useCallback } = React;

// ─── Responsive helper ───────────────────────────────────────
// useMedia('(max-width: 760px)') → boolean. Re-renders when the match flips.
function useMedia(query) {
  const [matches, setMatches] = useState(() =>
    typeof window !== 'undefined' && window.matchMedia ? window.matchMedia(query).matches : false
  );
  useEffect(() => {
    if (!window.matchMedia) return;
    const mq = window.matchMedia(query);
    const onChange = () => setMatches(mq.matches);
    onChange();
    if (mq.addEventListener) {
      mq.addEventListener('change', onChange);
      return () => mq.removeEventListener('change', onChange);
    }
    mq.addListener(onChange);
    return () => mq.removeListener(onChange);
  }, [query]);
  return matches;
}

// ─── Status helpers ──────────────────────────────────────────
function metricCadence(metric) {
  if (!metric) return 'weekly';
  if (metric.frequency) return metric.frequency;
  return metric.daily != null ? 'daily' : 'weekly';
}

function entryTarget(metric, period) {
  if (!metric) return null;
  if (period === 'day') return metric.dailyTarget ?? metric.daily ?? null;
  if (period === 'month') return metric.monthlyTarget ?? metric.monthly ?? metric.weeklyTarget ?? metric.weekly ?? null;
  return metric.weeklyTarget ?? metric.weekly ?? null;
}

function scorecardTarget(metric) {
  if (!metric) return null;
  if (metricCadence(metric) === 'monthly') {
    return metric.monthlyTarget ?? metric.monthly ?? metric.weeklyTarget ?? metric.weekly ?? null;
  }
  return metric.weeklyTarget ?? metric.weekly ?? null;
}

function metricAgg(metric) {
  if (!metric) return 'SUM';
  return metric.aggregationMethod ? metric.aggregationMethod.toUpperCase() : (metric.agg || 'SUM');
}

function metricStatus(metric, value) {
  if (value == null || isNaN(value)) return 'unknown';
  const goal = scorecardTarget(metric);
  if (goal == null || isNaN(goal)) return 'unknown';
  if (metric.dir === '>=') {
    if (value >= goal) return 'good';
    if (value >= goal * 0.85) return 'warn';
    return 'bad';
  } else {
    if (value <= goal) return 'good';
    if (value <= goal * 1.15) return 'warn';
    return 'bad';
  }
}

function fmtNum(n, metric) {
  if (n == null || isNaN(n)) return '—';
  if (!metric) return typeof n === 'number' ? n.toLocaleString() : n;
  if (metric.fn === 'Finance' || metric.id === 'cash' || metric.id === 'ar60') return '$' + Math.round(n).toLocaleString();
  if (metric.label.includes('%')) return Math.round(n * 10) / 10 + '%';
  return Math.round(n).toLocaleString();
}

// ─── Sparkline (SVG) ─────────────────────────────────────────
function Spark({ data, width = 120, height = 34, target = null, dir = '>=', fill = true }) {
  const clean = (data || []).filter(v => v != null && !isNaN(v));
  if (clean.length < 2) return null;
  const pad = 2;
  const min = Math.min(...clean, target ?? Infinity);
  const max = Math.max(...clean, target ?? -Infinity);
  const range = max - min || 1;
  const pts = clean.map((v, i) => {
    const x = pad + (i / (clean.length - 1)) * (width - pad * 2);
    const y = height - pad - ((v - min) / range) * (height - pad * 2);
    return [x, y];
  });
  const last = clean[clean.length - 1];
  const good = dir === '>=' ? last >= (target ?? last) : last <= (target ?? last);
  const strokeColor = good ? 'var(--good)' : 'var(--bad)';
  const fillColor = good ? 'rgba(30,158,106,0.10)' : 'rgba(201,52,44,0.10)';
  const d = pts.map((p, i) => (i === 0 ? 'M' : 'L') + p[0].toFixed(1) + ',' + p[1].toFixed(1)).join(' ');
  const area = d + ` L${pts[pts.length-1][0]},${height} L${pts[0][0]},${height} Z`;
  let targetY = null;
  if (target != null) {
    targetY = height - pad - ((target - min) / range) * (height - pad * 2);
  }
  return (
    <svg className="spark" width={width} height={height} viewBox={`0 0 ${width} ${height}`}>
      {fill && <path d={area} fill={fillColor} />}
      {targetY != null && <line x1={0} x2={width} y1={targetY} y2={targetY}
        stroke="var(--ink-300)" strokeDasharray="3,3" strokeWidth="1" />}
      <path d={d} fill="none" stroke={strokeColor} strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" />
      <circle cx={pts[pts.length-1][0]} cy={pts[pts.length-1][1]} r="2.6" fill={strokeColor} />
    </svg>
  );
}

// ─── Avatar ──────────────────────────────────────────────────
function Avatar({ person, size = 28, bordered = false }) {
  if (!person) return null;
  return (
    <div style={{
      width: size, height: size, borderRadius: '50%',
      background: person.color, color: '#fff',
      display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
      fontSize: size * 0.4, fontWeight: 600, letterSpacing: 0.3,
      flexShrink: 0,
      border: bordered ? '2px solid var(--card)' : 'none',
    }}>
      {person.initials}
    </div>
  );
}

// ─── Norwill mark — client logo ──────────────────────────────
function NorwillMark({ size = 28 }) {
  return (
    <img
      src="Logo.png"
      alt="Norwill"
      width={size}
      height={size}
      style={{ width: size, height: size, objectFit: 'contain', display: 'block' }}
    />
  );
}

// ─── Icons ───────────────────────────────────────────────────
const Icon = {
  home:   () => <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M3 12L12 4l9 8v8a2 2 0 0 1-2 2h-4v-6h-6v6H5a2 2 0 0 1-2-2v-8z"/></svg>,
  pulse:  () => <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M3 12h4l3-8 4 16 3-8h4"/></svg>,
  grid:   () => <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><rect x="3" y="3" width="7" height="7" rx="1"/><rect x="14" y="3" width="7" height="7" rx="1"/><rect x="3" y="14" width="7" height="7" rx="1"/><rect x="14" y="14" width="7" height="7" rx="1"/></svg>,
  alert:  () => <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M10.3 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>,
  rock:   () => <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M12 2l3 6 6 1-4.5 4.5 1 6-5.5-3-5.5 3 1-6L3 9l6-1z"/></svg>,
  map:    () => <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><polygon points="1 6 1 22 8 18 16 22 23 18 23 2 16 6 8 2 1 6"/><line x1="8" y1="2" x2="8" y2="18"/><line x1="16" y1="6" x2="16" y2="22"/></svg>,
  bell:   () => <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M18 8a6 6 0 0 0-12 0c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.73 21a2 2 0 0 1-3.46 0"/></svg>,
  chat:   () => <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>,
  sparkle: () => <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M12 3v4M12 17v4M3 12h4M17 12h4M5.6 5.6l2.8 2.8M15.6 15.6l2.8 2.8M5.6 18.4l2.8-2.8M15.6 8.4l2.8-2.8"/></svg>,
  check:  () => <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round"><polyline points="20 6 9 17 4 12"/></svg>,
  arrow:  () => <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.3" strokeLinecap="round" strokeLinejoin="round"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg>,
  up:     () => <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.6" strokeLinecap="round" strokeLinejoin="round"><polyline points="18 15 12 9 6 15"/></svg>,
  down:   () => <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.6" strokeLinecap="round" strokeLinejoin="round"><polyline points="6 9 12 15 18 9"/></svg>,
  close:  () => <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>,
  send:   () => <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><line x1="22" y1="2" x2="11" y2="13"/><polygon points="22 2 15 22 11 13 2 9 22 2"/></svg>,
  mic:    () => <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z"/><path d="M19 10v2a7 7 0 0 1-14 0v-2"/><line x1="12" y1="19" x2="12" y2="23"/></svg>,
  target: () => <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="10"/><circle cx="12" cy="12" r="6"/><circle cx="12" cy="12" r="2"/></svg>,
  sun:    () => <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M4.93 19.07l1.41-1.41M17.66 6.34l1.41-1.41"/></svg>,
  calendar: () => <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><rect x="3" y="4" width="18" height="18" rx="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/></svg>,
  link:   () => <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg>,
  users:  () => <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg>,
  key:    () => <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M21 2l-2 2m-7.61 7.61a5.5 5.5 0 1 1-7.778 7.778 5.5 5.5 0 0 1 7.777-7.777zm0 0L15.5 7.5m0 0l3 3L22 7l-3-3m-3.5 3.5L19 4"/></svg>,
  trash:  () => <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><polyline points="3 6 5 6 21 6"/><path d="M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"/><path d="M10 11v6M14 11v6"/><path d="M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/></svg>,
  plus:   () => <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>,
  book:   () => <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>,
};

// ─── Pill helpers ────────────────────────────────────────────
function StatusDot({ status, size = 8 }) {
  const colors = { good: 'var(--good)', bad: 'var(--bad)', warn: 'var(--warn)', unknown: 'var(--ink-300)' };
  return <span className="dot" style={{ background: colors[status] || colors.unknown, width: size, height: size }} />;
}

function Pct({ value, dim }) {
  return <span className="tnum" style={{ fontVariantNumeric: 'tabular-nums', fontWeight: 600, color: dim ? 'var(--ink-500)' : 'inherit' }}>{value}%</span>;
}

// ─── Delta arrow ─────────────────────────────────────────────
function Delta({ value, good }) {
  if (value === 0 || value == null) return <span style={{ color: 'var(--ink-400)', fontSize: 12 }}>—</span>;
  const up = value > 0;
  const isGood = good === 'up' ? up : !up;
  return (
    <span style={{ color: isGood ? 'var(--good)' : 'var(--bad)', fontSize: 12, fontWeight: 600,
      display: 'inline-flex', alignItems: 'center', gap: 2 }}>
      {up ? <Icon.up/> : <Icon.down/>}
      {Math.abs(value).toFixed(0)}%
    </span>
  );
}

Object.assign(window, {
  metricStatus,
  fmtNum,
  Spark,
  Avatar,
  NorwillMark,
  Icon,
  StatusDot,
  Pct,
  Delta,
  useMedia,
  metricCadence,
  entryTarget,
  scorecardTarget,
  metricAgg,
});
