const { useState, useEffect, useRef, useMemo, createContext, useContext } = React;
const DS = window.CallKataDesignSystem_89ce12;
const { Button, Card, Badge, Label, Stat, Panel, PillTabs, Segmented, FolderTabs, IconTile, Disc, Icon, StatusDot, KpiTile, ListRow, BarRow, QuestNote, Track, Input, Switch, Slider } = DS;

const AppCtx = createContext(null);
const useApp = () => useContext(AppCtx);

const bandTone = s => (s < 50 ? 'motion' : s > 75 ? 'live' : 'neutral');
const bandColor = { motion: 'var(--motion)', live: 'var(--live)', neutral: 'var(--ink-900)' };

function scoreTileStyle(score) {
  const p = Math.max(0, Math.min(100, score)), d = p - 50, up = d >= 0, mix = Math.round(8 + Math.min(1, Math.abs(d) / 50) * 82);
  return { background: `color-mix(in oklch, var(${up ? '--live' : '--motion'}) ${mix}%, #fff)`, color: Math.abs(d) < 6 ? 'var(--ink-900)' : `var(${up ? '--live-ink' : '--motion-ink'})` };
}

function ScoreRing({ score, size = 64, delta, label }) {
  const fs = size >= 90 ? size * .36 : size >= 56 ? size * .38 : size * .4;
  return <div className="ck-ring" style={{ display: 'inline-flex', alignItems: 'center', gap: 10 }}>
    <span className="ck-stile" role="img" aria-label={`Score ${score} of 100`} style={{ width: size, height: size, fontSize: fs, borderRadius: Math.max(8, Math.round(size * .26)), ...scoreTileStyle(score) }}>{score}</span>
    {(delta !== undefined || label) && <div style={{ display: 'grid', gap: 3 }}>
      {label && <span className="ck-label">{label}</span>}
      {delta !== undefined && <Delta v={delta} />}
    </div>}
  </div>;
}

function Delta({ v, suffix = ' pts', vs = 'vs prior window', style }) {
  if (v === null || v === undefined) return <span className="ck-meta">—</span>;
  const up = v > 0, flat = v === 0;
  const color = flat ? 'var(--text-faint)' : up ? 'var(--live-text)' : 'var(--motion-text)';
  return <span style={{ font: 'var(--type-value)', color, whiteSpace: 'nowrap', ...style }}>{flat ? '· 0' : up ? `↗ +${v}` : `▼ ${v}`}{suffix}{vs && <span style={{ color: 'var(--text-faint)', fontWeight: 400 }}> {vs}</span>}</span>;
}

const CHECK_TONE = { done: 'live', missed: 'motion', na: 'locked', disputed: 'quest' };
const CHECK_WORD = { done: 'done', missed: 'missed', na: 'doesn’t apply', disputed: 'disputed' };
function CheckChip({ status, weight, style }) {
  const disputed = status === 'disputed';
  return <span style={{ display: 'inline-flex', alignItems: 'center', gap: 6, height: 22, padding: '0 9px', borderRadius: 99, font: 'var(--type-badge)', letterSpacing: 'var(--track-badge)', textTransform: 'uppercase', whiteSpace: 'nowrap',
    background: disputed ? 'transparent' : status === 'done' ? 'var(--live-fill)' : status === 'missed' ? 'var(--motion-fill)' : 'var(--locked-tile)',
    color: disputed ? 'var(--quest-text)' : status === 'done' ? 'var(--live-ink)' : status === 'missed' ? 'var(--motion-ink)' : 'var(--text-muted)',
    border: disputed ? '1.5px solid var(--quest)' : '1.5px solid transparent', ...style }}>
    {CHECK_WORD[status]}{weight !== undefined && <span style={{ opacity: .7 }}>·{weight}</span>}
  </span>;
}

function RubricBadge({ v = 'v4', since = 'Oct 2', spans }) {
  const app = useApp();
  return <button className="ck-reset" onClick={() => app.openVersions && app.openVersions()} title="Open version diff" style={{ display: 'inline-flex', alignItems: 'center', gap: 6, height: 24, padding: '0 10px', borderRadius: 99, border: '1px solid var(--border-hairline)', background: 'var(--glass-strong)', font: 'var(--type-value)', color: 'var(--text-body)', cursor: 'pointer' }}>
    <span style={{ width: 6, height: 6, borderRadius: 99, background: spans ? 'var(--motion)' : 'var(--ink-900)' }}></span>
    {spans ? `spans ${spans} rubric versions` : `Rubric ${v} since ${since}`}
  </button>;
}

function LowSample({ children, n, min = 10, inline }) {
  return <span title={`too few calls (${n} of ${min} minimum)`} style={{ color: 'var(--text-faint)', display: inline ? 'inline' : 'inline-flex', alignItems: 'center', gap: 6 }}>{children}<span className="ck-meta" style={{ fontStyle: 'italic' }}>too few calls</span></span>;
}

function EmptyState({ children, action, onAction }) {
  return <div style={{ padding: '26px 18px', textAlign: 'center', border: '1.5px dashed var(--border-dashed)', borderRadius: 'var(--r-card)', background: 'var(--glass-ghost)', color: 'var(--text-muted)', font: 'var(--type-body)', display: 'grid', gap: 12, justifyItems: 'center' }}>
    <span>{children}</span>{action && <Button size="sm" variant="secondary" onClick={onAction}>{action}</Button>}
  </div>;
}

function DraftBar({ count, onTest, onPublish, onDiscard }) {
  if (!count) return null;
  return <div style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '10px 14px 10px 18px', borderRadius: 'var(--r-note)', background: 'var(--quest-fill)', color: 'var(--quest-ink)' }}>
    <span style={{ font: 'var(--type-ui)' }}>Draft changes: {count}</span>
    <span className="ck-meta" style={{ color: 'var(--quest-text)' }}>unpublished · grades unchanged until you publish</span>
    <span style={{ flex: 1 }}></span>
    <Button size="sm" variant="secondary" onClick={onDiscard}>Discard</Button>
    <Button size="sm" variant="secondary" onClick={onTest}>Test</Button>
    <Button size="sm" variant="accent" onClick={onPublish}>Publish</Button>
  </div>;
}

function SectionHead({ label, right, children }) {
  return <div style={{ display: 'flex', alignItems: 'baseline', gap: 12, marginBottom: 12 }}>
    <span className="ck-label">{label}</span>{children}<span style={{ flex: 1 }}></span>{right}
  </div>;
}

function Avatar({ name, size = 30 }) {
  const ini = name.split(' ').map(s => s[0]).slice(0, 2).join('');
  return <Disc variant="white" size={size}><span style={{ font: `600 ${Math.round(size * .36)}px/1 var(--font-sans)`, color: 'var(--ink-900)' }}>{ini}</span></Disc>;
}

/* ---------- Moment player ---------- */
function MomentPlayer({ call, seek, onSeek, compact }) {
  const [playing, setPlaying] = useState(false);
  const [t, setT] = useState(seek || 0);
  const [speed, setSpeed] = useState(1);
  const [tab, setTab] = useState('Timeline');
  useEffect(() => { if (seek !== undefined && seek !== null) { setT(seek); setPlaying(true); } }, [seek]);
  useEffect(() => { if (!playing) return; const id = setInterval(() => setT(x => Math.min(call.duration, x + speed)), 1000); return () => clearInterval(id); }, [playing, speed, call.duration]);
  useEffect(() => { if (t >= call.duration) setPlaying(false); }, [t]);
  const checks = call.checks.filter(c => c.t !== null);
  const jump = s => { setT(Math.max(0, Math.min(call.duration, s))); };
  useEffect(() => {
    const h = e => { if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') return;
      if (e.code === 'Space') { e.preventDefault(); setPlaying(p => !p); }
      else if (e.key === 'ArrowLeft') jump(t - 5); else if (e.key === 'ArrowRight') jump(t + 5);
      else if (/^[1-9]$/.test(e.key)) { const c = checks[+e.key - 1]; if (c) { jump(c.t); setPlaying(true); } } };
    window.addEventListener('keydown', h); return () => window.removeEventListener('keydown', h);
  });
  const col = { done: 'var(--live)', missed: 'var(--motion)', na: 'var(--gray-400)', disputed: 'var(--quest)' };
  return <div style={{ display: 'grid', gap: 10 }}>
    <div style={{ display: 'flex', alignItems: 'center', gap: 10, flexWrap: 'wrap' }}>
      <button className="ck-reset" aria-label={playing ? 'Pause' : 'Play'} onClick={() => setPlaying(p => !p)} style={{ width: 38, height: 38, borderRadius: 99, background: 'var(--ink-900)', color: '#fff', display: 'grid', placeItems: 'center', cursor: 'pointer', flex: 'none' }}><Icon name={playing ? 'Pause' : 'Play'} size={15} /></button>
      <span style={{ font: 'var(--type-value)', minWidth: 42 }}>{fmt(t)}</span>
      <div style={{ flex: '1 1 160px', position: 'relative', height: 28 }} onClick={e => { const r = e.currentTarget.getBoundingClientRect(); jump(Math.round(((e.clientX - r.left) / r.width) * call.duration)); }}>
        <div style={{ position: 'absolute', left: 0, right: 0, top: 11, height: 6, borderRadius: 99, background: 'rgba(13,13,15,.08)' }}></div>
        <div style={{ position: 'absolute', left: 0, top: 11, height: 6, borderRadius: 99, background: 'var(--purple-500)', width: `${(t / call.duration) * 100}%`, transition: 'width 200ms linear' }}></div>
        {checks.map((c, i) => <button key={c.rule} className="ck-reset" title={`${RULE[c.rule].label} · ${CHECK_WORD[c.status]} · ${fmt(c.t)} (key ${i + 1})`} aria-label={`${RULE[c.rule].label}, ${CHECK_WORD[c.status]}, ${fmt(c.t)}`} onClick={e => { e.stopPropagation(); jump(c.t); setPlaying(true); onSeek && onSeek(c.rule); }} style={{ position: 'absolute', left: `calc(${(c.t / call.duration) * 100}% - 7px)`, top: 7, width: 14, height: 14, borderRadius: 99, background: col[c.status], border: '2px solid #fff', cursor: 'pointer', boxShadow: 'var(--shadow-xs)' }}></button>)}
      </div>
      <span className="ck-meta" style={{ minWidth: 42, textAlign: 'right' }}>{fmt(call.duration)}</span>
      <Segmented items={['1×', '1.5×', '2×']} value={`${speed}×`} onChange={v => setSpeed(parseFloat(v))} />
    </div>
    {!compact && <>
      <PillTabs items={['Timeline', 'Transcript']} value={tab} onChange={setTab} />
      {tab === 'Transcript' ? <Transcript call={call} t={t} onSeek={jump} /> : <div className="ck-meta" style={{ display: 'flex', gap: 14, flexWrap: 'wrap' }}><span><span style={{ color: 'var(--live)' }}>●</span> done</span><span><span style={{ color: 'var(--motion)' }}>●</span> missed</span><span><span style={{ color: 'var(--gray-400)' }}>●</span> doesn’t apply</span></div>}
    </>}
  </div>;
}

function Transcript({ call, t, onSeek }) {
  const lines = useMemo(() => {
    const out = []; const n = Math.max(8, Math.round(call.duration / 60));
    for (let i = 0; i < n; i++) { const s = Math.round((call.duration / n) * i); const c = call.checks.find(k => k.t !== null && Math.abs(k.t - s) < call.duration / n / 2);
      out.push({ t: s, who: i % 2 ? REP[call.rep].name.split(' ')[0] : call.contact, text: c ? c.note : (i % 2 ? 'Okay, so the next thing I need from you is the income side, let’s walk through that.' : 'Sure. It’s mostly W-2, and my spouse has some 1099 on the side.') , rule: c && c.rule }); }
    return out;
  }, [call]);
  const ref = useRef();
  const active = lines.findIndex((l, i) => t >= l.t && (!lines[i + 1] || t < lines[i + 1].t));
  useEffect(() => { const el = ref.current?.children[active]; if (el && ref.current) ref.current.scrollTop = el.offsetTop - ref.current.offsetTop - 40; }, [active]);
  return <div ref={ref} style={{ maxHeight: 220, overflow: 'auto', display: 'grid', gap: 6, padding: 2 }}>
    {lines.map((l, i) => <div key={i} onClick={() => onSeek(l.t)} style={{ display: 'grid', gridTemplateColumns: '40px 70px 1fr', gap: 10, padding: '6px 8px', borderRadius: 8, cursor: 'pointer', background: i === active ? 'var(--paper-2)' : 'transparent', font: 'var(--type-body-sm)' }}>
      <span className="ck-meta">{fmt(l.t)}</span><span style={{ fontWeight: 600 }}>{l.who}</span><span>{l.text}{l.rule && <Badge tone={CHECK_TONE[call.checks.find(c => c.rule === l.rule).status]} style={{ marginLeft: 8 }}>{RULE[l.rule].label}</Badge>}</span>
    </div>)}
  </div>;
}

/* ---------- Drawer / modal ---------- */
function Drawer({ open, onClose, width = 560, children, label }) {
  useEffect(() => { const h = e => e.key === 'Escape' && onClose(); window.addEventListener('keydown', h); return () => window.removeEventListener('keydown', h); }, [onClose]);
  return <>
    <div onClick={onClose} style={{ position: 'fixed', inset: 0, background: 'rgba(13,13,15,.18)', opacity: open ? 1 : 0, pointerEvents: open ? 'auto' : 'none', transition: 'opacity var(--dur) var(--ease-out)', zIndex: 40 }}></div>
    <aside aria-label={label} className="ck-drawer" style={{ position: 'fixed', top: 12, right: 12, bottom: 12, width: `min(${width}px, calc(100vw - 24px))`, background: 'rgba(255,255,255,.92)', backdropFilter: 'var(--blur-md)', WebkitBackdropFilter: 'var(--blur-md)', borderRadius: 'var(--r-panel)', boxShadow: 'var(--shadow-float)', transform: open ? 'translateX(0)' : 'translateX(calc(100% + 24px))', transition: 'transform var(--dur-slow) var(--ease-out)', zIndex: 41, overflow: 'auto', padding: 22 }}>
      {open && children}
    </aside>
  </>;
}

function Modal({ open, onClose, title, children, footer, width = 520 }) {
  if (!open) return null;
  return <div onClick={onClose} style={{ position: 'fixed', inset: 0, background: 'rgba(13,13,15,.22)', display: 'grid', placeItems: 'center', zIndex: 60, padding: 20 }}>
    <div onClick={e => e.stopPropagation()} role="dialog" aria-label={title} style={{ width: '100%', maxWidth: width, background: 'rgba(255,255,255,.96)', borderRadius: 'var(--r-panel)', boxShadow: 'var(--shadow-float)', padding: 22, display: 'grid', gap: 16 }}>
      <div style={{ display: 'flex', alignItems: 'center' }}><span style={{ font: 'var(--type-title)' }}>{title}</span><span style={{ flex: 1 }}></span><button className="ck-reset" onClick={onClose} aria-label="Close" style={{ cursor: 'pointer', color: 'var(--text-faint)', fontSize: 18 }}>×</button></div>
      {children}
      {footer && <div style={{ display: 'flex', gap: 10, justifyContent: 'flex-end' }}>{footer}</div>}
    </div>
  </div>;
}

/* Toast */
function Toast({ msg }) { if (!msg) return null; return <div style={{ position: 'fixed', left: '50%', bottom: 24, transform: 'translateX(-50%)', background: 'var(--ink-900)', color: '#fff', padding: '10px 16px', borderRadius: 99, font: 'var(--type-ui-sm)', zIndex: 80, boxShadow: 'var(--shadow-float)' }}>{msg}</div>; }

/* Sparkline */
function Spark({ data, w = 120, h = 36, color = 'var(--purple-500)' }) {
  const min = Math.min(...data), max = Math.max(...data), rng = max - min || 1;
  const pts = data.map((v, i) => [(i / (data.length - 1)) * (w - 4) + 2, h - 3 - ((v - min) / rng) * (h - 6)]);
  const d = pts.map((p, i) => `${i ? 'L' : 'M'}${p[0]},${p[1]}`).join(' ');
  return <svg width={w} height={h} viewBox={`0 0 ${w} ${h}`}><path d={`${d} L${w - 2},${h} L2,${h} Z`} fill="#ece0f8" opacity=".65" /><path d={d} fill="none" stroke={color} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" /></svg>;
}

Object.assign(window, { AppCtx, useApp, bandTone, scoreTileStyle, ScoreRing, Delta, CheckChip, CHECK_TONE, CHECK_WORD, RubricBadge, LowSample, EmptyState, DraftBar, SectionHead, Avatar, MomentPlayer, Drawer, Modal, Toast, Spark, Button, Card, Badge, Label, Stat, Panel, PillTabs, Segmented, FolderTabs, IconTile, Disc, Icon, StatusDot, KpiTile, ListRow, BarRow, QuestNote, Track, Input, Switch, Slider });
