/* ===========================================================
   Shared UI primitives, icons, charts, helpers
   =========================================================== */

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

/* ---------- Icons (inline SVG, currentColor) ---------- */
const I = {
  layout: (p) => <svg {...p} width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><rect x="3" y="3" width="7" height="9" /><rect x="14" y="3" width="7" height="5" /><rect x="14" y="12" width="7" height="9" /><rect x="3" y="16" width="7" height="5" /></svg>,
  funnel: (p) => <svg {...p} width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><polygon points="22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3" /></svg>,
  list: (p) => <svg {...p} width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><line x1="8" y1="6" x2="21" y2="6" /><line x1="8" y1="12" x2="21" y2="12" /><line x1="8" y1="18" x2="21" y2="18" /><line x1="3" y1="6" x2="3.01" y2="6" /><line x1="3" y1="12" x2="3.01" y2="12" /><line x1="3" y1="18" x2="3.01" y2="18" /></svg>,
  terminal: (p) => <svg {...p} width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><polyline points="4 17 10 11 4 5" /><line x1="12" y1="19" x2="20" y2="19" /></svg>,
  trophy: (p) => <svg {...p} width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M6 9H4a2 2 0 0 1-2-2V5h4" /><path d="M18 9h2a2 2 0 0 0 2-2V5h-4" /><path d="M6 2h12v7a6 6 0 0 1-12 0V2z" /><path d="M9 22h6" /><path d="M12 17v5" /></svg>,
  swords: (p) => <svg {...p} width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><polyline points="14.5 17.5 3 6 3 3 6 3 17.5 14.5" /><line x1="13" y1="19" x2="19" y2="13" /><line x1="16" y1="16" x2="20" y2="20" /><line x1="19" y1="21" x2="21" y2="19" /><polyline points="14.5 6.5 18 3 21 3 21 6 17.5 9.5" /><line x1="5" y1="14" x2="9" y2="18" /><line x1="7" y1="17" x2="4" y2="20" /><line x1="3" y1="19" x2="5" y2="21" /></svg>,
  retry: (p) => <svg {...p} width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><polyline points="23 4 23 10 17 10" /><polyline points="1 20 1 14 7 14" /><path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15" /></svg>,
  newspaper: (p) => <svg {...p} width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M4 22h16a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2H8a2 2 0 0 0-2 2v16a2 2 0 0 1-2 2zm0 0a2 2 0 0 1-2-2v-9c0-1.1.9-2 2-2h2" /><path d="M18 14h-8" /><path d="M15 18h-5" /><path d="M10 6h8v4h-8V6Z" /></svg>,
  settings: (p) => <svg {...p} width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="3" /><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z" /></svg>,
  bell: (p) => <svg {...p} width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9" /><path d="M13.73 21a2 2 0 0 1-3.46 0" /></svg>,
  moon: (p) => <svg {...p} width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z" /></svg>,
  sun: (p) => <svg {...p} width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="4" /><line x1="12" y1="2" x2="12" y2="4" /><line x1="12" y1="20" x2="12" y2="22" /><line x1="4.93" y1="4.93" x2="6.34" y2="6.34" /><line x1="17.66" y1="17.66" x2="19.07" y2="19.07" /><line x1="2" y1="12" x2="4" y2="12" /><line x1="20" y1="12" x2="22" y2="12" /><line x1="4.93" y1="19.07" x2="6.34" y2="17.66" /><line x1="17.66" y1="6.34" x2="19.07" y2="4.93" /></svg>,
  check: (p) => <svg {...p} width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><polyline points="20 6 9 17 4 12" /></svg>,
  x: (p) => <svg {...p} width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><line x1="18" y1="6" x2="6" y2="18" /><line x1="6" y1="6" x2="18" y2="18" /></svg>,
  alert: (p) => <svg {...p} width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M10.29 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>,
  arrowUp: (p) => <svg {...p} width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><line x1="12" y1="19" x2="12" y2="5" /><polyline points="5 12 12 5 19 12" /></svg>,
  arrowDown: (p) => <svg {...p} width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><line x1="12" y1="5" x2="12" y2="19" /><polyline points="19 12 12 19 5 12" /></svg>,
  ext: (p) => <svg {...p} width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" /><polyline points="15 3 21 3 21 9" /><line x1="10" y1="14" x2="21" y2="3" /></svg>,
  chevron: (p) => <svg {...p} width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><polyline points="9 18 15 12 9 6" /></svg>,
  search: (p) => <svg {...p} width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="11" cy="11" r="8" /><line x1="21" y1="21" x2="16.65" y2="16.65" /></svg>,
  back: (p) => <svg {...p} width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><line x1="19" y1="12" x2="5" y2="12" /><polyline points="12 19 5 12 12 5" /></svg>,
  menu: (p) => <svg {...p} width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><line x1="3" y1="12" x2="21" y2="12" /><line x1="3" y1="6" x2="21" y2="6" /><line x1="3" y1="18" x2="21" y2="18" /></svg>,
  spark: (p) => <svg {...p} width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M12 2v6m0 8v6M5 12H1m22 0h-4M6.34 6.34L4.22 4.22m15.56 15.56l-2.12-2.12M6.34 17.66l-2.12 2.12M19.78 4.22l-2.12 2.12" /></svg>,
  link: (p) => <svg {...p} width="12" height="12" 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>,
};

/* ---------- Chip / Badge ---------- */
function StatusChip({ status }) {
  const map = {
    success: { cls: 'ok',   label: 'success' },
    partial: { cls: 'warn', label: 'partial' },
    error:   { cls: 'err',  label: 'error' },
  };
  const s = map[status] || { cls: '', label: status };
  return <span className={`chip ${s.cls}`}><span className="dot" />{s.label}</span>;
}

function Chip({ children, kind, style }) {
  return <span className={`chip ${kind||''}`} style={style}>{children}</span>;
}

function StatusDot({ status }) {
  return <span className={`statusdot ${status}`} />;
}

/* ---------- Sparkline (mini line) ---------- */
function Sparkline({ data, color, height=28 }) {
  if (!data || data.length === 0) return null;
  const w = 100, h = height;
  const min = Math.min(...data), max = Math.max(...data);
  const range = max - min || 1;
  const pts = data.map((v, i) => {
    const x = (i / (data.length - 1)) * w;
    const y = h - ((v - min) / range) * (h - 4) - 2;
    return `${x.toFixed(1)},${y.toFixed(1)}`;
  }).join(' ');
  return (
    <svg className="spark" viewBox={`0 0 ${w} ${h}`} preserveAspectRatio="none">
      <polyline points={pts} fill="none" stroke={color || 'var(--info)'} strokeWidth="1.5" strokeLinejoin="round" strokeLinecap="round" />
      <circle cx={(data.length-1)/(data.length-1)*w} cy={h - ((data[data.length-1] - min) / range) * (h - 4) - 2} r="1.8" fill={color || 'var(--info)'} />
    </svg>
  );
}

/* ---------- Donut (svg) ---------- */
function Donut({ data, size=170, thickness=24 }) {
  // data: [{label, value, color}]
  const total = data.reduce((a, d) => a + d.value, 0);
  const r = (size - thickness) / 2;
  const cx = size / 2, cy = size / 2;
  const circ = 2 * Math.PI * r;
  let offset = 0;

  return (
    <div className="donut-wrap">
      <svg width={size} height={size}>
        <circle cx={cx} cy={cy} r={r} fill="none" stroke="var(--border)" strokeWidth={thickness} />
        {data.map((d, i) => {
          const len = (d.value / total) * circ;
          const el = (
            <circle key={i} cx={cx} cy={cy} r={r} fill="none"
              stroke={d.color} strokeWidth={thickness}
              strokeDasharray={`${len} ${circ-len}`}
              strokeDashoffset={-offset}
              transform={`rotate(-90 ${cx} ${cy})`}
            />
          );
          offset += len;
          return el;
        })}
        <text x={cx} y={cy-4} textAnchor="middle" fontFamily="var(--serif)" fontWeight="700" fontSize="22" fill="var(--text1)">
          {total.toFixed(3)}
        </text>
        <text x={cx} y={cy+14} textAnchor="middle" fontFamily="var(--mono)" fontSize="9" fill="var(--text3)" letterSpacing="0.12em">
          EDITORIAL SCORE
        </text>
      </svg>
      <div className="legends">
        {data.map((d, i) => (
          <div className="ll" key={i}>
            <span className="sw" style={{background: d.color}} />
            <span className="nm">{d.label}</span>
            <span className="vl">{d.value.toFixed(3)}</span>
          </div>
        ))}
      </div>
    </div>
  );
}

/* ---------- Funnel ---------- */
function Funnel({ stages }) {
  const max = Math.max(...stages.map(s => s.value));
  return (
    <div className="funnel">
      {stages.map((s, i) => {
        const w = (s.value / max) * 100;
        const prev = i === 0 ? s.value : stages[i-1].value;
        const ret = i === 0 ? 100 : (s.value / prev * 100);
        const drop = ret < 50;
        return (
          <div className="stage" key={s.name} data-tip={s.tip}>
            <div className="name">{s.name}</div>
            <div className="bar-wrap">
              <div className={`bar s${i+1}`} style={{width: `${w}%`}} />
              <div className="bar-label">{s.value.toLocaleString()}</div>
            </div>
            <div className="num">{s.value}</div>
            <div className={`pct ${drop ? 'drop' : ''}`}>{i === 0 ? '—' : `${ret.toFixed(1)}%`}</div>
          </div>
        );
      })}
    </div>
  );
}

/* ---------- Gantt ---------- */
function Gantt({ lanes, totalDuration }) {
  return (
    <div className="gantt">
      {lanes.map((lane, i) => (
        <Fragment key={i}>
          <div className="lane-name">{lane.name}</div>
          <div className="lane-track">
            {lane.bars.map((b, j) => {
              const left = (b.start / totalDuration) * 100;
              const width = (b.duration / totalDuration) * 100;
              return (
                <div key={j}
                  className={`lane-bar ${b.cls}`}
                  style={{left: `${left}%`, width: `${width}%`, minWidth: '12px'}}
                  data-tip={b.tip}>
                  {b.label}
                </div>
              );
            })}
          </div>
        </Fragment>
      ))}
      <div /><div className="axis">
        <span>0s</span>
        <span>{(totalDuration/4).toFixed(0)}s</span>
        <span>{(totalDuration/2).toFixed(0)}s</span>
        <span>{(totalDuration*3/4).toFixed(0)}s</span>
        <span>{totalDuration.toFixed(0)}s</span>
      </div>
    </div>
  );
}

/* ---------- Score breakdown stacked bar ---------- */
function ScoreBar({ breakdown, total }) {
  const entries = [
    { key: 'source',    label: 'Source',    color: '#5b8def' },
    { key: 'freshness', label: 'Freshness', color: 'var(--gold)' },
    { key: 'relevance', label: 'Relevance', color: '#4ec9b0' },
    { key: 'trends',    label: 'Trends',    color: '#d685c3' },
    { key: 'gemini',    label: 'Gemini',    color: '#c98c4e' },
  ];
  return (
    <div className="scorebar" data-tip={entries.map(e => `${e.label}: ${(breakdown[e.key]||0).toFixed(3)}`).join('  ·  ')}>
      {entries.map(e => {
        const v = breakdown[e.key] || 0;
        const w = (v / total) * 100;
        return <div key={e.key} className={`seg ${e.key}`} style={{width: `${w}%`, background: e.color}} />;
      })}
    </div>
  );
}

/* ---------- helpers ---------- */
function fmtDuration(secs) {
  if (secs == null) return '—';
  const m = Math.floor(secs / 60);
  const s = Math.floor(secs % 60);
  return `${m}:${String(s).padStart(2, '0')}`;
}
function fmtAgo(iso) {
  const now = Date.now();
  const t = new Date(iso).getTime();
  const diff = Math.floor((now - t) / 1000);
  if (diff < 60) return `${diff}s atrás`;
  if (diff < 3600) return `${Math.floor(diff/60)}m atrás`;
  if (diff < 86400) return `${Math.floor(diff/3600)}h ${Math.floor((diff%3600)/60)}m atrás`;
  return `${Math.floor(diff/86400)}d atrás`;
}
function fmtClock(iso) {
  const d = new Date(iso);
  return `${String(d.getHours()).padStart(2,'0')}:${String(d.getMinutes()).padStart(2,'0')}:${String(d.getSeconds()).padStart(2,'0')}`;
}

Object.assign(window, {
  I, StatusChip, StatusDot, Chip, Sparkline, Donut, Funnel, Gantt, ScoreBar,
  fmtDuration, fmtAgo, fmtClock,
});
