// ============================================================================
// CALLS — точний відтворення дизайну + реальний Ringostat API
// ============================================================================
if (!window._crmCalls) window._crmCalls = { data: null, ts: 0 };
const CALLS_FE_TTL = 15 * 60 * 1000;

// ── Disposition helpers ────────────────────────────────────────────
const CALL_RESULTS = {
  ANSWERED:  { label: "Відповіли",    color: "#10B981", icon: "check"        },
  'NO ANSWER':{ label: "Пропущено",   color: "#EF4444", icon: "phone-missed" },
  MISSED:    { label: "Пропущено",    color: "#EF4444", icon: "phone-missed" },
  BUSY:      { label: "Зайнято",      color: "#F59E0B", icon: "phone-off"    },
  FAILED:    { label: "Помилка",      color: "#EF4444", icon: "phone-off"    },
};

const isMissed   = (c) => c.disposition === 'NO ANSWER' || c.disposition === 'MISSED';
const isIncoming = (c) => c.call_type === 'in' || c.call_type === 'transitin';

function getDispLabel(c) {
  const isOut = !isIncoming(c);
  if (isMissed(c) && isOut) return 'Немає відповіді';
  return CALL_RESULTS[c.disposition]?.label || c.disposition || '—';
}
function getDispColor(c) { return CALL_RESULTS[c.disposition]?.color || 'var(--fg-muted)'; }

function fmtSec(s) {
  const t = Math.floor(s || 0);
  return `${String(Math.floor(t / 60)).padStart(2, '0')}:${String(t % 60).padStart(2, '0')}`;
}
function customerPhone(c) { return c.call_type === 'out' ? c.dst : c.caller; }

// ── Date grouping ──────────────────────────────────────────────────
function callDateGroup(calldate) {
  if (!calldate) return '—';
  const d   = new Date(calldate.replace(' ', 'T'));
  const now = new Date();
  const today     = new Date(now.getFullYear(), now.getMonth(), now.getDate());
  const yesterday = new Date(today - 86400000);
  const cd  = new Date(d.getFullYear(), d.getMonth(), d.getDate());
  if (cd.getTime() === today.getTime()) return 'Сьогодні';
  if (cd.getTime() === yesterday.getTime()) return 'Вчора';
  return d.toLocaleDateString('uk-UA', { day: '2-digit', month: 'long' });
}

// ── Pre-baked waveforms ────────────────────────────────────────────
const WAVES = [
  [.2,.3,.5,.8,.9,.7,.4,.5,.6,.8,.7,.4,.3,.5,.7,.6,.4,.3,.5,.7,.9,.8,.6,.4,.3,.5,.7,.6,.5,.4,.3,.2],
  [.3,.4,.6,.7,.5,.3,.4,.6,.8,.9,.7,.5,.4,.6,.8,.7,.5,.3,.4,.6,.7,.5,.4,.3,.5,.7,.8,.6,.4,.3,.4,.3],
  [.4,.5,.7,.8,.6,.4,.5,.7,.9,.8,.6,.4,.5,.7,.6,.4,.3,.5,.7,.8,.6,.5,.7,.8,.7,.5,.4,.6,.7,.5,.3,.4],
  [.2,.4,.6,.5,.3,.4,.6,.8,.7,.5,.4,.6,.7,.5,.4,.6,.8,.6,.4,.3,.5,.7,.6,.4,.3,.4,.6,.5,.3,.4,.5,.3],
];
function waveIdx(uid) { return uid ? String(uid).split('').reduce((a, c) => a + c.charCodeAt(0), 0) : 0; }

// ── Waveform component ─────────────────────────────────────────────
function Waveform({ uid, progress, playing, onSeek, noRec }) {
  if (noRec) return <span style={{ fontSize: 11, color: 'var(--fg-muted)', fontStyle: 'italic' }}>немає запису</span>;
  const ref  = useRef(null);
  const bars = WAVES[waveIdx(uid) % WAVES.length];
  const handleClick = (e) => {
    if (!ref.current || !onSeek) return;
    const rect = ref.current.getBoundingClientRect();
    onSeek(Math.max(0, Math.min(100, (e.clientX - rect.left) / rect.width * 100)));
  };
  return (
    <div ref={ref} onClick={handleClick} style={{ display: 'flex', alignItems: 'center', gap: 1.5, width: '100%', maxWidth: 240, height: 28, cursor: onSeek ? 'pointer' : 'default' }}>
      {bars.map((amp, i) => {
        const reached = (i + 1) / bars.length * 100 <= progress;
        return <div key={i} style={{ flex: 1, height: `${Math.max(8, amp * 100)}%`, background: reached ? 'var(--accent)' : 'var(--border-default)', borderRadius: 1, transition: 'background 80ms' }}/>;
      })}
    </div>
  );
}

// ── KPI strip ──────────────────────────────────────────────────────
function CallsKPI({ calls }) {
  const today    = calls.filter(c => callDateGroup(c.calldate) === 'Сьогодні');
  const total    = today.length;
  const missed   = today.filter(c => isMissed(c)).length;
  const answered = today.filter(c => c.disposition === 'ANSWERED');
  const avg      = answered.length ? Math.round(answered.reduce((a, c) => a + (c.billsec || 0), 0) / answered.length) : 0;
  const inCount  = today.filter(c => isIncoming(c)).length;
  const outCount = today.length - inCount;

  const cards = [
    { label: 'Дзвінків сьогодні', value: total,           icon: 'phone',          tone: 'var(--fg-primary)',  sub: '' },
    { label: 'Пропущених',        value: missed,           icon: 'phone-missed',   tone: '#EF4444',            warn: missed > 0, sub: total > 0 ? `${Math.round(missed / total * 100)}% від усіх` : 'усе під контролем' },
    { label: 'Середня тривал.',   value: fmtSec(avg),     icon: 'timer',          tone: 'var(--fg-primary)',  sub: 'відповіли' },
    { label: 'Вхідні / Вихідні',  value: `${inCount} / ${outCount}`, icon: 'arrow-left-right', tone: 'var(--fg-secondary)', sub: '' },
  ];

  return (
    <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 1, background: 'var(--border-subtle)', borderBottom: '1px solid var(--border-subtle)', flexShrink: 0 }}>
      {cards.map((k, i) => (
        <div key={i} style={{ padding: '16px 22px', background: 'var(--bg-base)', display: 'flex', alignItems: 'center', gap: 14 }}>
          <div style={{ width: 36, height: 36, borderRadius: 8, background: k.warn ? 'rgba(239,68,68,.12)' : 'var(--bg-panel)', display: 'flex', alignItems: 'center', justifyContent: 'center', color: k.tone }}>
            <Icon name={k.icon} size={16}/>
          </div>
          <div style={{ minWidth: 0 }}>
            <div style={{ fontSize: 10, fontWeight: 500, letterSpacing: '0.06em', textTransform: 'uppercase', color: 'var(--fg-muted)', marginBottom: 2 }}>{k.label}</div>
            <div style={{ display: 'flex', alignItems: 'baseline', gap: 8 }}>
              <span style={{ fontSize: 22, fontWeight: 600, color: k.tone, fontVariantNumeric: 'tabular-nums', lineHeight: 1 }}>{k.value}</span>
              {k.sub && <span style={{ fontSize: 11, color: 'var(--fg-muted)' }}>{k.sub}</span>}
            </div>
          </div>
        </div>
      ))}
    </div>
  );
}

// ── Filter chips ───────────────────────────────────────────────────
function CallFilterChips({ active, onChange, calls }) {
  const counts = {
    all:      calls.length,
    incoming: calls.filter(c => isIncoming(c)).length,
    outgoing: calls.filter(c => !isIncoming(c)).length,
    missed:   calls.filter(c => isMissed(c)).length,
  };
  const items = [
    { key: 'all',      label: 'Усі',       tone: 'var(--accent)' },
    { key: 'incoming', label: 'Вхідні',    tone: '#10B981' },
    { key: 'outgoing', label: 'Вихідні',   tone: '#3B82F6' },
    { key: 'missed',   label: 'Пропущені', tone: '#EF4444' },
  ];
  return (
    <div style={{ display: 'flex', gap: 6, flexShrink: 0 }}>
      {items.map(it => {
        const on = active === it.key;
        return (
          <button key={it.key} onClick={() => onChange(it.key)} style={{
            display: 'inline-flex', alignItems: 'center', gap: 6, height: 30, padding: '0 12px',
            background: on ? `color-mix(in srgb, ${it.tone} 14%, transparent)` : 'var(--bg-panel)',
            border: '1px solid ' + (on ? `color-mix(in srgb, ${it.tone} 40%, transparent)` : 'var(--border-subtle)'),
            color: on ? 'var(--fg-primary)' : 'var(--fg-secondary)',
            borderRadius: 999, fontSize: 12, fontWeight: 500, cursor: 'pointer', fontFamily: 'inherit',
          }}>
            {it.key !== 'all' && <span style={{ width: 6, height: 6, borderRadius: '50%', background: it.tone }}/>}
            {it.label}
            <span style={{ fontSize: 11, color: 'var(--fg-muted)', fontVariantNumeric: 'tabular-nums' }}>{counts[it.key]}</span>
          </button>
        );
      })}
    </div>
  );
}

// ── Direction icon ─────────────────────────────────────────────────
function DirIcon({ c }) {
  const incoming = isIncoming(c);
  const missed   = isMissed(c);
  const color = incoming ? (missed ? '#EF4444' : '#10B981') : (missed ? '#F59E0B' : 'var(--fg-secondary)');
  const icon  = incoming ? (missed ? 'phone-missed' : 'phone-incoming') : 'phone-outgoing';
  return (
    <div style={{ width: 28, height: 28, borderRadius: 6, background: `color-mix(in srgb, ${color} 14%, transparent)`, display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
      <Icon name={icon} size={14} style={{ color }}/>
    </div>
  );
}

// ── Result chip ────────────────────────────────────────────────────
function ResultChip({ c }) {
  const color = getDispColor(c);
  return (
    <span style={{ display: 'inline-flex', alignItems: 'center', gap: 4, padding: '3px 7px', borderRadius: 4, fontSize: 11, fontWeight: 500, background: `color-mix(in srgb, ${color} 14%, transparent)`, color }}>
      {getDispLabel(c)}
    </span>
  );
}

// ── Bottom audio player (desktop) ─────────────────────────────────
function BottomPlayer({ call, playing, progress, currentTime, duration, playbackRate, onToggle, onStop, onRateChange, onSeek }) {
  if (!call) return null;
  const RATES = [0.75, 1, 1.5, 2];
  const miniBtn = { width: 30, height: 30, borderRadius: 6, background: 'var(--bg-base)', border: '1px solid var(--border-subtle)', color: 'var(--fg-secondary)', cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center' };
  return (
    <div style={{ position: 'absolute', left: 0, right: 0, bottom: 0, background: 'color-mix(in srgb, var(--bg-panel) 92%, transparent)', backdropFilter: 'blur(12px)', borderTop: '1px solid var(--border-default)', padding: '12px 24px', display: 'flex', alignItems: 'center', gap: 14, boxShadow: '0 -8px 24px rgba(0,0,0,.3)', zIndex: 10 }}>
      <Avatar name={call.employee_fio} size={36}/>
      <div style={{ minWidth: 180 }}>
        <div style={{ fontSize: 13, fontWeight: 500, color: 'var(--fg-primary)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{call.employee_fio || '—'}</div>
        <div style={{ fontSize: 11, color: 'var(--fg-muted)', fontFamily: 'var(--font-mono)', fontVariantNumeric: 'tabular-nums' }}>{fmtPhone(customerPhone(call))}</div>
      </div>
      <button onClick={() => onSeek({ currentTarget: { getBoundingClientRect: () => ({ left: 0, width: 1 }), }, clientX: 0 })} style={miniBtn}><Icon name="rotate-ccw" size={13}/></button>
      <button onClick={onToggle} style={{ ...miniBtn, background: 'var(--accent)', color: '#fff', borderColor: 'var(--accent)', width: 36, height: 36 }}>
        <Icon name={playing ? 'pause' : 'play'} size={14}/>
      </button>
      <button style={miniBtn}><Icon name="rotate-cw" size={13}/></button>
      <span style={{ fontFamily: 'var(--font-mono)', fontVariantNumeric: 'tabular-nums', fontSize: 12, color: 'var(--fg-secondary)', minWidth: 44 }}>{fmtSec(currentTime)}</span>
      <div style={{ flex: 1 }}>
        <Waveform uid={call.uniqueid} progress={progress} playing={true} onSeek={(p) => { const a = window._crmAudio; if (a?.duration) { a.currentTime = p / 100 * a.duration; } }}/>
      </div>
      <span style={{ fontFamily: 'var(--font-mono)', fontVariantNumeric: 'tabular-nums', fontSize: 12, color: 'var(--fg-muted)', minWidth: 44 }}>{fmtSec(duration)}</span>
      <div style={{ display: 'flex', gap: 2, padding: 2, background: 'var(--bg-base)', borderRadius: 6, border: '1px solid var(--border-subtle)' }}>
        {RATES.map(s => (
          <button key={s} onClick={() => onRateChange(s)} style={{ height: 24, padding: '0 8px', border: 0, borderRadius: 4, background: playbackRate === s ? 'var(--accent)' : 'transparent', color: playbackRate === s ? '#fff' : 'var(--fg-secondary)', fontSize: 11, fontWeight: 500, cursor: 'pointer', fontFamily: 'var(--font-mono)', fontVariantNumeric: 'tabular-nums' }}>{s}x</button>
        ))}
      </div>
      <button title="Завантажити" style={miniBtn}><Icon name="download" size={13}/></button>
      <button onClick={onStop} title="Закрити" style={miniBtn}><Icon name="x" size={14}/></button>
    </div>
  );
}

// ── Bottom player mobile ───────────────────────────────────────────
function BottomPlayerMobile({ call, playing, progress, currentTime, duration, playbackRate, onToggle, onStop, onRateChange }) {
  if (!call) return null;
  const RATES = [0.75, 1, 1.5, 2];
  return (
    <div style={{ flexShrink: 0, borderTop: '1px solid var(--border-subtle)', background: 'var(--bg-raised)', padding: '10px 16px', display: 'flex', flexDirection: 'column', gap: 8 }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
        <button onClick={onToggle} style={{ width: 36, height: 36, borderRadius: '50%', background: 'var(--accent)', border: 0, display: 'flex', alignItems: 'center', justifyContent: 'center', cursor: 'pointer', flexShrink: 0 }}>
          <Icon name={playing ? 'pause' : 'play'} size={16} color="#fff"/>
        </button>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ fontSize: 12, fontWeight: 500, color: 'var(--fg-primary)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{call.employee_fio || '—'}</div>
          <div style={{ fontSize: 11, color: 'var(--fg-muted)', fontFamily: 'var(--font-mono)' }}>{fmtSec(currentTime)} / {fmtSec(duration)}</div>
        </div>
        <div style={{ display: 'flex', gap: 3 }}>
          {RATES.map(r => <button key={r} onClick={() => onRateChange(r)} style={{ padding: '2px 5px', borderRadius: 3, fontSize: 10, cursor: 'pointer', fontFamily: 'var(--font-mono)', background: playbackRate === r ? 'var(--accent)' : 'transparent', border: `1px solid ${playbackRate === r ? 'var(--accent)' : 'var(--border-default)'}`, color: playbackRate === r ? '#fff' : 'var(--fg-secondary)' }}>{r}x</button>)}
        </div>
        <button onClick={onStop} style={{ width: 28, height: 28, border: '1px solid var(--border-default)', borderRadius: 5, background: 'transparent', color: 'var(--fg-muted)', display: 'flex', alignItems: 'center', justifyContent: 'center', cursor: 'pointer' }}><Icon name="x" size={12}/></button>
      </div>
      <div style={{ height: 5, background: 'var(--border-strong)', borderRadius: 3, position: 'relative' }}>
        <div style={{ position: 'absolute', left: 0, top: 0, height: '100%', width: `${progress}%`, background: 'var(--accent)', borderRadius: 3 }}/>
      </div>
    </div>
  );
}

// ── Main Calls component ───────────────────────────────────────────
function Calls({ isMobile }) {
  const [calls,        setCalls]        = useState(() => window._crmCalls?.data || []);
  const [loading,      setLoading]      = useState(() => !window._crmCalls?.data);
  const [refreshing,   setRefreshing]   = useState(false);
  const [error,        setError]        = useState(null);
  const [playingId,    setPlayingId]    = useState(null);
  const [playingCall,  setPlayingCall]  = useState(null);
  const [progress,     setProgress]     = useState(0);
  const [currentTime,  setCurrentTime]  = useState(0);
  const [duration,     setDuration]     = useState(0);
  const [playbackRate, setPlaybackRate] = useState(1);
  const [query,        setQuery]        = useState('');
  const [typeFilter,   setTypeFilter]   = useState('all');
  const [managerFilter,setManagerFilter]= useState(null);
  const [dropMgr,      setDropMgr]      = useState(false);
  const audioRef = useRef(null);

  const applyAndCache = (data) => { window._crmCalls = { data, ts: Date.now() }; setCalls(data); };

  const loadCalls = () => {
    setLoading(true); setError(null);
    API.getCalls().then(d => { applyAndCache(d.calls || []); setLoading(false); }).catch(e => { setError(e.message); setLoading(false); });
  };

  const refreshCalls = () => {
    setRefreshing(true);
    API.getCalls(true).then(d => { applyAndCache(d.calls || []); setRefreshing(false); }).catch(() => setRefreshing(false));
  };

  useEffect(() => {
    const c = window._crmCalls;
    if (c?.data) {
      setCalls(c.data); setLoading(false);
      if (Date.now() - c.ts >= CALLS_FE_TTL) API.getCalls().then(d => applyAndCache(d.calls || [])).catch(() => {});
    } else { loadCalls(); }
    const t = setInterval(() => API.getCalls().then(d => applyAndCache(d.calls || [])).catch(() => {}), 30 * 60 * 1000);
    return () => clearInterval(t);
  }, []);

  useEffect(() => () => { audioRef.current?.pause(); }, []);

  const stopAudio = () => {
    if (audioRef.current) { audioRef.current.pause(); audioRef.current.ontimeupdate = null; audioRef.current.onended = null; }
    window._crmAudio = null;
    setPlayingId(null); setPlayingCall(null); setProgress(0); setCurrentTime(0); setDuration(0);
  };

  const handleToggle = (call) => {
    if (!call.recording) return;
    if (playingId === call.uniqueid) { audioRef.current?.pause(); setPlayingId(null); setPlayingCall(null); setProgress(0); setCurrentTime(0); return; }
    stopAudio();
    const audio = new Audio(call.recording);
    audio.playbackRate = playbackRate;
    audio.onloadedmetadata = () => setDuration(audio.duration || 0);
    audio.ontimeupdate = () => { if (audio.duration) { setProgress(Math.round(audio.currentTime / audio.duration * 100)); setCurrentTime(audio.currentTime); } };
    audio.onended = () => { setPlayingId(null); setPlayingCall(null); setProgress(0); setCurrentTime(0); };
    audioRef.current = audio;
    window._crmAudio = audio;
    audio.play().catch(() => { setPlayingId(null); setPlayingCall(null); });
    setPlayingId(call.uniqueid); setPlayingCall(call); setProgress(0); setCurrentTime(0); setDuration(0);
  };

  const handleRateChange = (rate) => { setPlaybackRate(rate); if (audioRef.current) audioRef.current.playbackRate = rate; };

  const managers = [...new Set(calls.map(c => c.employee_fio).filter(Boolean))].sort();

  const filtered = calls.filter(c => {
    if (query && !`${c.caller} ${c.dst} ${c.employee_fio} ${c.connected_with}`.toLowerCase().includes(query.toLowerCase())) return false;
    if (managerFilter && c.employee_fio !== managerFilter) return false;
    if (typeFilter === 'incoming' && !isIncoming(c)) return false;
    if (typeFilter === 'outgoing' &&  isIncoming(c)) return false;
    if (typeFilter === 'missed'   && !isMissed(c))   return false;
    return true;
  });

  // Group by date
  const groups = filtered.reduce((acc, c) => {
    const g = callDateGroup(c.calldate);
    (acc[g] = acc[g] || []).push(c);
    return acc;
  }, {});

  const playerProps = { call: playingCall, playing: !!playingId, progress, currentTime, duration, playbackRate, onToggle: () => handleToggle(playingCall), onStop: stopAudio, onRateChange: handleRateChange, onSeek: () => {} };

  const refreshBtnEl = (
    <button onClick={refreshCalls} disabled={refreshing} style={{ width: 30, height: 30, border: '1px solid var(--border-subtle)', borderRadius: 6, background: 'var(--bg-base)', color: 'var(--fg-secondary)', display: 'flex', alignItems: 'center', justifyContent: 'center', cursor: refreshing ? 'default' : 'pointer' }}>
      <Icon name="refresh-cw" size={13}/>
    </button>
  );

  if (loading) return (
    <div style={{ flex: 1, display: 'flex', alignItems: 'center', justifyContent: 'center', flexDirection: 'column', gap: 8 }}>
      <Icon name="phone" size={24} style={{ color: 'var(--fg-muted)', opacity: 0.4 }}/>
      <span style={{ color: 'var(--fg-muted)', fontSize: 13 }}>Завантаження дзвінків…</span>
    </div>
  );

  if (error) return (
    <div style={{ flex: 1, display: 'flex', alignItems: 'center', justifyContent: 'center', flexDirection: 'column', gap: 10 }}>
      <Icon name="alert-circle" size={24} style={{ color: '#ef4444' }}/>
      <span style={{ color: '#ef4444', fontSize: 13 }}>Помилка: {error}</span>
      <Button variant="secondary" size="sm" leftIcon="refresh-cw" onClick={loadCalls}>Спробувати знову</Button>
    </div>
  );

  // ── Mobile ─────────────────────────────────────────────────────
  if (isMobile) {
    return (
      <>
        <div style={{ padding: '10px 16px 4px', flexShrink: 0, display: 'flex', gap: 8, alignItems: 'center' }}>
          <div style={{ position: 'relative', flex: 1 }}>
            <Icon name="search" size={14} style={{ position: 'absolute', left: 12, top: '50%', transform: 'translateY(-50%)', color: 'var(--fg-muted)' }}/>
            <input value={query} onChange={e => setQuery(e.target.value)} placeholder="Пошук за номером, менеджером…" style={{ width: '100%', height: 32, boxSizing: 'border-box', padding: '0 12px 0 34px', background: 'var(--bg-panel)', color: 'var(--fg-primary)', border: '1px solid var(--border-default)', borderRadius: 6, fontSize: 12, outline: 'none', fontFamily: 'inherit' }}/>
          </div>
          {refreshBtnEl}
        </div>
        <div style={{ flex: 1, overflowY: 'auto', padding: '8px 16px', display: 'flex', flexDirection: 'column', gap: 10 }}>
          {filtered.length === 0 && <div style={{ textAlign: 'center', color: 'var(--fg-muted)', fontSize: 13, padding: '40px 0' }}>Дзвінків не знайдено</div>}
          {Object.entries(groups).map(([date, items]) => (
            <div key={date}>
              <div style={{ fontSize: 10, fontWeight: 500, letterSpacing: '0.06em', textTransform: 'uppercase', color: 'var(--fg-muted)', padding: '8px 2px 4px', display: 'flex', alignItems: 'center', gap: 6 }}>
                <Icon name="calendar" size={10}/>{date} <span style={{ opacity: 0.5 }}>· {items.length}</span>
              </div>
              {items.map(c => {
                const isPlaying = playingId === c.uniqueid;
                const color = getDispColor(c);
                return (
                  <div key={c.uniqueid} style={{ background: 'var(--bg-panel)', border: '1px solid var(--border-subtle)', borderRadius: 12, padding: 14, display: 'flex', flexDirection: 'column', gap: 10, marginBottom: 8 }}>
                    <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
                      <DirIcon c={c}/>
                      <div style={{ flex: 1, minWidth: 0 }}>
                        <div style={{ fontFamily: 'var(--font-mono)', fontSize: 13, fontWeight: 500, color: 'var(--fg-primary)', fontVariantNumeric: 'tabular-nums' }}>{fmtPhone(customerPhone(c))}</div>
                        <div style={{ fontSize: 11, color: 'var(--fg-muted)' }}>{c.employee_fio || '—'}</div>
                      </div>
                      <ResultChip c={c}/>
                      <span style={{ fontFamily: 'var(--font-mono)', fontSize: 11, color, flexShrink: 0 }}>{c.billsec ? fmtSec(c.billsec) : '—'}</span>
                    </div>
                    {c.recording && (
                      <div style={{ display: 'flex', alignItems: 'center', gap: 10, paddingTop: 8, borderTop: '1px solid var(--border-subtle)' }}>
                        <button onClick={() => handleToggle(c)} style={{ width: 32, height: 32, borderRadius: '50%', background: isPlaying ? 'var(--accent)' : 'var(--bg-raised)', border: '1px solid ' + (isPlaying ? 'var(--accent)' : 'var(--border-default)'), color: isPlaying ? '#fff' : 'var(--fg-secondary)', cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
                          <Icon name={isPlaying ? 'pause' : 'play'} size={13}/>
                        </button>
                        <Waveform uid={c.uniqueid} progress={isPlaying ? progress : 0} playing={isPlaying} onSeek={null}/>
                      </div>
                    )}
                  </div>
                );
              })}
            </div>
          ))}
        </div>
        <BottomPlayerMobile {...playerProps}/>
      </>
    );
  }

  // ── Desktop ────────────────────────────────────────────────────
  const dropStyle = { position: 'absolute', top: 'calc(100% + 4px)', left: 0, minWidth: 180, background: 'var(--bg-raised)', border: '1px solid var(--border-default)', borderRadius: 8, padding: 4, boxShadow: 'var(--shadow-1)', zIndex: 10 };
  const dropItem  = (label, active, onClick) => (
    <button key={label} onClick={onClick} style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', width: '100%', padding: '8px 10px', border: 0, borderRadius: 6, cursor: 'pointer', textAlign: 'left', background: active ? 'var(--bg-active)' : 'transparent', color: 'var(--fg-primary)', fontSize: 13, fontFamily: 'inherit' }}>
      {label}{active && <Icon name="check" size={13} color="var(--accent)"/>}
    </button>
  );

  return (
    <div style={{ flex: 1, display: 'flex', flexDirection: 'column', minWidth: 0, minHeight: 0, position: 'relative' }}>
      <style>{`.call-row:hover { background: var(--bg-hover) !important; }`}</style>

      <CallsKPI calls={calls}/>

      {/* Toolbar */}
      <div style={{ padding: '12px 24px', borderBottom: '1px solid var(--border-subtle)', display: 'flex', alignItems: 'center', gap: 12, flexWrap: 'wrap', flexShrink: 0 }}>
        <CallFilterChips active={typeFilter} onChange={setTypeFilter} calls={calls}/>
        <div style={{ flex: 1 }}/>
        <div style={{ position: 'relative', width: 240 }}>
          <Icon name="search" size={13} style={{ position: 'absolute', left: 10, top: '50%', transform: 'translateY(-50%)', color: 'var(--fg-muted)' }}/>
          <input value={query} onChange={e => setQuery(e.target.value)} placeholder="Клієнт, номер, менеджер…" style={{ width: '100%', height: 30, boxSizing: 'border-box', padding: '0 12px 0 30px', background: 'var(--bg-raised)', color: 'var(--fg-primary)', border: '1px solid var(--border-default)', borderRadius: 6, fontSize: 12, outline: 'none', fontFamily: 'inherit' }}/>
        </div>
        {/* Manager filter */}
        <div style={{ position: 'relative' }}>
          <Button variant={managerFilter ? 'primary' : 'secondary'} size="sm" leftIcon="users" onClick={() => setDropMgr(d => !d)}>
            {managerFilter || 'Усі менеджери'}
          </Button>
          {dropMgr && (<>
            <div onClick={() => setDropMgr(false)} style={{ position: 'fixed', inset: 0, zIndex: 9 }}/>
            <div style={dropStyle}>
              {dropItem('Усі менеджери', !managerFilter, () => { setManagerFilter(null); setDropMgr(false); })}
              {managers.map(m => dropItem(m, managerFilter === m, () => { setManagerFilter(m); setDropMgr(false); }))}
            </div>
          </>)}
        </div>
        <Button variant="secondary" size="sm" leftIcon="download">Експорт</Button>
        {refreshBtnEl}
      </div>

      {/* Column headers (sticky) */}
      <div style={{
        display: 'grid',
        gridTemplateColumns: '36px 240px minmax(0,1.6fr) 110px minmax(220px,1.2fr) 72px minmax(0,1fr) 90px',
        alignItems: 'center', gap: 12, padding: '10px 24px',
        borderBottom: '1px solid var(--border-subtle)', background: 'var(--bg-panel)',
        fontSize: 10, fontWeight: 500, letterSpacing: '0.06em', textTransform: 'uppercase', color: 'var(--fg-muted)',
        position: 'sticky', top: 0, zIndex: 1, flexShrink: 0,
      }}>
        <span/><span>Телефон</span><span>Клієнт</span><span>Результат</span><span>Запис</span><span>Трив.</span><span>Менеджер</span><span>Час</span>
      </div>

      {/* Rows grouped by date */}
      <div style={{ flex: 1, overflowY: 'auto', paddingBottom: playingCall ? 88 : 0 }}>
        {filtered.length === 0 && (
          <div style={{ padding: 60, textAlign: 'center', color: 'var(--fg-muted)', fontSize: 13 }}>Дзвінків не знайдено</div>
        )}
        {Object.entries(groups).map(([date, items]) => (
          <div key={date}>
            <div style={{ padding: '8px 24px', fontSize: 10, fontWeight: 500, letterSpacing: '0.06em', textTransform: 'uppercase', color: 'var(--fg-muted)', background: 'var(--bg-base)', borderBottom: '1px solid var(--border-subtle)', display: 'flex', alignItems: 'center', gap: 8 }}>
              <Icon name="calendar" size={11}/>
              {date}
              <span style={{ opacity: 0.5 }}>· {items.length}</span>
            </div>

            {items.map(c => {
              const isPlaying = playingId === c.uniqueid;
              const hasRec    = !!c.recording;
              return (
                <div key={c.uniqueid} className="call-row" style={{
                  display: 'grid',
                  gridTemplateColumns: '36px 240px minmax(0,1.6fr) 110px minmax(220px,1.2fr) 72px minmax(0,1fr) 90px',
                  alignItems: 'center', gap: 12, padding: '12px 24px',
                  borderBottom: '1px solid var(--border-subtle)',
                  background: isPlaying ? 'var(--bg-active)' : 'transparent',
                  cursor: 'pointer',
                }}>
                  <DirIcon c={c}/>

                  {/* Телефон */}
                  <div style={{ minWidth: 0 }}>
                    <div style={{ fontFamily: 'var(--font-mono)', fontSize: 13, fontWeight: 500, color: 'var(--fg-primary)', fontVariantNumeric: 'tabular-nums', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{fmtPhone(customerPhone(c))}</div>
                  </div>

                  {/* Клієнт */}
                  <div style={{ minWidth: 0 }}>
                    <div style={{ fontSize: 13, color: 'var(--fg-primary)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{c.employee_fio || '—'}</div>
                  </div>

                  {/* Результат */}
                  <ResultChip c={c}/>

                  {/* Запис з waveform */}
                  <div onClick={e => { if (!hasRec) return; e.stopPropagation(); handleToggle(c); }} style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                    {hasRec && (
                      <button style={{ width: 28, height: 28, borderRadius: '50%', flexShrink: 0, background: isPlaying ? 'var(--accent)' : 'var(--bg-panel)', border: '1px solid ' + (isPlaying ? 'var(--accent)' : 'var(--border-default)'), color: isPlaying ? '#fff' : 'var(--fg-secondary)', cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
                        <Icon name={isPlaying ? 'pause' : 'play'} size={11}/>
                      </button>
                    )}
                    <Waveform uid={c.uniqueid} progress={isPlaying ? progress : 0} playing={isPlaying} noRec={!hasRec}
                      onSeek={hasRec ? (p) => { if (!isPlaying) handleToggle(c); if (audioRef.current?.duration) audioRef.current.currentTime = p / 100 * audioRef.current.duration; } : null}/>
                  </div>

                  {/* Тривалість */}
                  <span style={{ fontFamily: 'var(--font-mono)', fontVariantNumeric: 'tabular-nums', fontSize: 13, color: (c.billsec || 0) === 0 ? 'var(--fg-muted)' : 'var(--fg-primary)' }}>
                    {(c.billsec || 0) === 0 ? '—' : fmtSec(c.billsec)}
                  </span>

                  {/* Менеджер */}
                  <div style={{ display: 'flex', alignItems: 'center', gap: 8, minWidth: 0 }}>
                    {c.employee_fio ? (
                      <><Avatar name={c.employee_fio} size={22}/><span style={{ fontSize: 12, color: 'var(--fg-secondary)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{c.employee_fio}</span></>
                    ) : (
                      <span style={{ fontSize: 12, color: 'var(--fg-muted)' }}>—</span>
                    )}
                  </div>

                  {/* Час */}
                  <span style={{ fontSize: 12, color: 'var(--fg-muted)', fontFamily: 'var(--font-mono)', fontVariantNumeric: 'tabular-nums' }}>
                    {fmtCallDate(c.calldate)}
                  </span>
                </div>
              );
            })}
          </div>
        ))}
      </div>

      {/* Sticky bottom player */}
      <BottomPlayer {...playerProps}/>
    </div>
  );
}

window.Calls = Calls;
