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

// 4-point sparkle star — brand motif
function Sparkle({ size = 14, color = 'currentColor' }) {
  return (
    <svg className="pw-sparkle" width={size} height={size} viewBox="0 0 16 16" fill="none" aria-hidden>
      <path d="M8 0 L9.2 6.8 L16 8 L9.2 9.2 L8 16 L6.8 9.2 L0 8 L6.8 6.8 Z" fill={color} />
    </svg>
  );
}

// Inline lucide-style icons so we don't depend on CDN init timing
const Icon = {
  home:      (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M3 10.5 12 3l9 7.5"/><path d="M5 10v10h14V10"/></svg>,
  flow:      (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M4 6h6v4H4z"/><path d="M14 14h6v4h-6z"/><path d="M10 8h4"/><path d="M14 16H10a4 4 0 0 1-4-4v-2"/></svg>,
  channels:  (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M4 20V8"/><path d="M10 20V4"/><path d="M16 20v-8"/><path d="M22 20V10"/></svg>,
  campaigns: (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M3 11l14-6v14L3 13z"/><path d="M7 12v5"/></svg>,
  creative:  (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" {...p}><rect x="3" y="4" width="18" height="14"/><path d="M3 14l5-5 4 4 3-3 6 6"/></svg>,
  audience:  (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" {...p}><circle cx="9" cy="8" r="3.2"/><path d="M3 20a6 6 0 0 1 12 0"/><circle cx="17" cy="7" r="2.4"/><path d="M15 20a5 5 0 0 1 7-4.6"/></svg>,
  reports:   (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" {...p}><rect x="5" y="3" width="14" height="18"/><path d="M8 8h8M8 12h8M8 16h5"/></svg>,
  settings:  (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" {...p}><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.6 1.6 0 0 0 .3 1.8l.1.1a2 2 0 1 1-2.8 2.8l-.1-.1a1.6 1.6 0 0 0-1.8-.3 1.6 1.6 0 0 0-1 1.5V21a2 2 0 1 1-4 0v-.1a1.6 1.6 0 0 0-1-1.5 1.6 1.6 0 0 0-1.8.3l-.1.1a2 2 0 1 1-2.8-2.8l.1-.1a1.6 1.6 0 0 0 .3-1.8 1.6 1.6 0 0 0-1.5-1H3a2 2 0 1 1 0-4h.1A1.6 1.6 0 0 0 4.6 9a1.6 1.6 0 0 0-.3-1.8l-.1-.1a2 2 0 1 1 2.8-2.8l.1.1a1.6 1.6 0 0 0 1.8.3H9a1.6 1.6 0 0 0 1-1.5V3a2 2 0 1 1 4 0v.1a1.6 1.6 0 0 0 1 1.5 1.6 1.6 0 0 0 1.8-.3l.1-.1a2 2 0 1 1 2.8 2.8l-.1.1a1.6 1.6 0 0 0-.3 1.8V9a1.6 1.6 0 0 0 1.5 1H21a2 2 0 1 1 0 4h-.1a1.6 1.6 0 0 0-1.5 1z"/></svg>,
  calendar:  (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" {...p}><rect x="3" y="5" width="18" height="16"/><path d="M3 9h18M8 3v4M16 3v4"/></svg>,
  download:  (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M12 4v12"/><path d="m7 11 5 5 5-5"/><path d="M4 20h16"/></svg>,
  filter:    (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M3 5h18l-7 9v6l-4-2v-4z"/></svg>,
  arrowUp:   (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M12 19V5M5 12l7-7 7 7"/></svg>,
  arrowDown: (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M12 5v14M19 12l-7 7-7-7"/></svg>,
  arrowRight:(p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M5 12h14M13 5l7 7-7 7"/></svg>,
  plus:      (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M12 5v14M5 12h14"/></svg>,
  chevron:   (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="m6 9 6 6 6-6"/></svg>,
  search:    (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" {...p}><circle cx="11" cy="11" r="7"/><path d="m20 20-3.5-3.5"/></svg>,
  ram:       (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" {...p}><circle cx="5" cy="6" r="2"/><circle cx="5" cy="18" r="2"/><circle cx="19" cy="12" r="2"/><path d="M7 6h6a4 4 0 0 1 4 4v0M7 18h6a4 4 0 0 0 4-4v0"/></svg>,
  venues:    (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M3 21V8l9-5 9 5v13"/><path d="M9 21v-6h6v6"/></svg>,
};

// Delta pill
function Delta({ value, suffix = '%', invert = false }) {
  const pos = invert ? value < 0 : value > 0;
  const neg = invert ? value > 0 : value < 0;
  const cls = pos ? 'pos' : (neg ? 'neg' : '');
  const ArrowIcon = value > 0 ? Icon.arrowUp : (value < 0 ? Icon.arrowDown : null);
  return (
    <span className={'pw-delta ' + cls}>
      {ArrowIcon && <ArrowIcon width="10" height="10" />}
      {value >= 0 ? '+' : ''}{value.toFixed(1)}{suffix}
    </span>
  );
}

// Live-data ready flag — true once the API has returned and adoptInit ran.
// Avoids the "demo numbers flash before live load" first-paint bug.
function isLive() {
  return !!(window.CoverStory && window.CoverStory._dataSource === 'live');
}

// Tiny shimmer block used by skeleton states. CSS is in index.html.
function Shimmer({ w, h, style }) {
  return <div className="pw-shimmer" style={{ width: w, height: h, ...(style || {}) }} />;
}

// KPI tile. If live data hasn't arrived yet, render a skeleton so the
// demo numbers don't flash in before the API responds.
function Kpi({ label, value, delta, sub, invertDelta, sparkline, loading }) {
  const showSkeleton = loading || !isLive();
  return (
    <div className="pw-kpi">
      <div className="pw-kpi-label">{label}</div>
      {showSkeleton ? (
        <Shimmer w="60%" h="32px" style={{ margin: '6px 0 4px' }} />
      ) : (
        <div className="pw-kpi-value">{value}</div>
      )}
      {sparkline && !showSkeleton && <div style={{ height: 30, margin: '-2px -2px 0' }}>{sparkline}</div>}
      {sparkline && showSkeleton && <Shimmer w="100%" h="30px" style={{ margin: '0 -2px 0' }} />}
      <div className="pw-kpi-foot">
        {showSkeleton ? <Shimmer w="40px" h="14px" /> : (delta != null ? <Delta value={delta} invert={invertDelta} /> : <span />)}
        <span style={{ color: 'var(--pw-fg-subtle)' }}>{sub}</span>
      </div>
    </div>
  );
}

// Empty state inside a Card or table. Pair with onClear to render a reset
// affordance when filters are involved.
function EmptyState({ title, hint, onClear, clearLabel }) {
  return (
    <div style={{ padding: '36px 20px', textAlign: 'center', color: 'var(--pw-fg-muted)' }}>
      <div style={{ fontSize: 14, fontWeight: 500, color: 'var(--pw-fg)', marginBottom: 4 }}>{title || 'Nothing here yet'}</div>
      {hint && <div style={{ fontSize: 12, marginBottom: onClear ? 12 : 0 }}>{hint}</div>}
      {onClear && (
        <button className="pw-btn" onClick={onClear} style={{ marginTop: 4 }}>
          {clearLabel || 'Clear filters'}
        </button>
      )}
    </div>
  );
}

// Error state — for when a fetch failed. Pass onRetry to render a retry CTA.
function ErrorState({ title, detail, onRetry }) {
  return (
    <div style={{ padding: '36px 20px', textAlign: 'center', color: 'var(--pw-fg-muted)', border: '1px dashed var(--pw-hair)' }}>
      <div style={{ fontSize: 14, fontWeight: 500, color: 'var(--pw-neg)', marginBottom: 4 }}>{title || "Couldn't load"}</div>
      {detail && <div style={{ fontSize: 12, marginBottom: onRetry ? 12 : 0 }}>{detail}</div>}
      {onRetry && (
        <button className="pw-btn" onClick={onRetry} style={{ marginTop: 4 }}>
          Retry
        </button>
      )}
    </div>
  );
}

// Canonical date/time formatter for the dashboard. Mode:
//   'date'      → '08 Aug'
//   'datetime'  → '08 Aug · 10:30'   ← default
//   'iso'       → '2026-08-08T10:30:00.000Z'
//   'long'      → '8 August 2026, 10:30'
// Use this everywhere a date renders so format is consistent across pages.
function fmtDt(d, mode) {
  if (!d) return '—';
  var date = d instanceof Date ? d : new Date(d);
  if (isNaN(date.getTime())) return '—';
  mode = mode || 'datetime';
  if (mode === 'iso') return date.toISOString();
  if (mode === 'date') return date.toLocaleDateString('en-GB', { day: '2-digit', month: 'short' });
  if (mode === 'long') return date.toLocaleDateString('en-GB', { day: 'numeric', month: 'long', year: 'numeric' })
    + ', ' + date.toLocaleTimeString('en-GB', { hour: '2-digit', minute: '2-digit' });
  // default datetime
  return date.toLocaleDateString('en-GB', { day: '2-digit', month: 'short' })
    + ' · ' + date.toLocaleTimeString('en-GB', { hour: '2-digit', minute: '2-digit' });
}

// Card
function Card({ title, sub, right, children, style }) {
  return (
    <div className="pw-card" style={style}>
      {(title || right) && (
        <div className="pw-card-head">
          <div>
            {sub && <div className="pw-card-sub" style={{ marginBottom: 4 }}>{sub}</div>}
            {title && <div className="pw-card-title">{title}</div>}
          </div>
          {right}
        </div>
      )}
      {children}
    </div>
  );
}

// Date range picker
function DateRange({ value, onChange }) {
  const [open, setOpen] = useState(false);
  const [customOpen, setCustomOpen] = useState(false);
  const today = new Date().toISOString().slice(0, 10);
  const weekAgo = new Date(Date.now() - 7 * 86400000).toISOString().slice(0, 10);
  const [from, setFrom] = useState(weekAgo);
  const [to, setTo] = useState(today);
  const ref = useRef(null);
  useEffect(() => {
    function click(e) { if (ref.current && !ref.current.contains(e.target)) { setOpen(false); setCustomOpen(false); } }
    document.addEventListener('click', click);
    return () => document.removeEventListener('click', click);
  }, []);
  const options = [
    ['today', 'Today'],
    ['yesterday', 'Yesterday'],
    ['7d', 'Last 7 days'],
    ['30d', 'Last 30 days'],
    ['90d', 'Last 90 days'],
    ['qtd', 'Quarter to date'],
    ['ytd', 'Year to date'],
  ];
  const label = value === 'custom'
    ? `${from} → ${to}`
    : (options.find(o => o[0] === value)?.[1] || 'Last 30 days');
  function applyCustom() {
    if (!/^\d{4}-\d{2}-\d{2}$/.test(from) || !/^\d{4}-\d{2}-\d{2}$/.test(to)) return;
    if (window.CoverStory && window.CoverStory.setCustomRange) {
      window.CoverStory.setCustomRange(from, to);
    }
    onChange('custom');
    setOpen(false); setCustomOpen(false);
  }
  return (
    <div ref={ref} style={{ position: 'relative' }}>
      <button className="pw-btn" onClick={() => setOpen(o => !o)}>
        <Icon.calendar /> {label} <Icon.chevron width="12" height="12" />
      </button>
      {open && !customOpen && (
        <div className="pw-popover">
          {options.map(([k, l]) => (
            <button key={k} className={value === k ? 'active' : ''} onClick={() => { onChange(k); setOpen(false); }}>{l}</button>
          ))}
          <div style={{ borderTop: '1px solid var(--pw-hair)', marginTop: 4, paddingTop: 4 }}>
            <button className={value === 'custom' ? 'active' : ''} onClick={() => setCustomOpen(true)}>Custom range…</button>
          </div>
        </div>
      )}
      {open && customOpen && (
        <div className="pw-popover" style={{ padding: 14, minWidth: 240 }}>
          <div style={{ fontSize: 11, color: 'var(--pw-fg-subtle)', letterSpacing: '0.08em', textTransform: 'uppercase', marginBottom: 6 }}>From</div>
          <input type="date" value={from} onChange={e => setFrom(e.target.value)} max={to}
                 style={{ width: '100%', padding: '6px 8px', border: '1px solid var(--pw-hair)', background: 'var(--pw-bg-elevated)', color: 'var(--pw-fg)', fontSize: 13, marginBottom: 10 }} />
          <div style={{ fontSize: 11, color: 'var(--pw-fg-subtle)', letterSpacing: '0.08em', textTransform: 'uppercase', marginBottom: 6 }}>To</div>
          <input type="date" value={to} onChange={e => setTo(e.target.value)} min={from} max={today}
                 style={{ width: '100%', padding: '6px 8px', border: '1px solid var(--pw-hair)', background: 'var(--pw-bg-elevated)', color: 'var(--pw-fg)', fontSize: 13, marginBottom: 12 }} />
          <div style={{ display: 'flex', gap: 6 }}>
            <button className="pw-btn" style={{ flex: 1, justifyContent: 'center' }} onClick={() => setCustomOpen(false)}>Back</button>
            <button className="pw-btn pw-btn-primary" style={{ flex: 1, justifyContent: 'center' }} onClick={applyCustom}>Apply</button>
          </div>
        </div>
      )}
    </div>
  );
}

// Channel filter chips
function ChannelFilters({ channelsOn, onToggle }) {
  return (
    <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap' }}>
      {CoverStory.CHANNELS.map(c => (
        <div
          key={c.id}
          className={'pw-chip' + (channelsOn[c.id] ? '' : ' off')}
          onClick={() => onToggle(c.id)}
        >
          <span className="pw-chip-dot" style={{ background: channelsOn[c.id] ? c.color : 'var(--pw-hair-strong)' }} />
          {c.name}
        </div>
      ))}
    </div>
  );
}

// Scenario toggle
function ScenarioToggle({ value, onChange }) {
  return (
    <div className="pw-toggle">
      {['Actual', 'Forecast', '+10% spend'].map(opt => (
        <button key={opt} className={value === opt ? 'on' : ''} onClick={() => onChange(opt)}>{opt}</button>
      ))}
    </div>
  );
}

Object.assign(window, { Sparkle, Icon, Delta, Kpi, Card, DateRange, ChannelFilters, ScenarioToggle });
