/* AAU CRM — Call Log + QC, Inbox Daily Report, Data Sync Explorer */

/* ── Date range + period comparison ── */
const REPORT_TODAY = new Date('2026-06-02T00:00:00');
const CMP_PROFILE = {
  none: null,
  prev: { label: 'kỳ trước liền kề', shift: 'adjacent', f: 0.9, respond: 89, frt: 4.7, qc: 7.6, callQc: 6.6, pass: 44 },
  lastmonth: { label: 'cùng kỳ tháng trước', shift: 30, f: 0.8, respond: 86, frt: 5.3, qc: 7.3, callQc: 6.4, pass: 41 },
};
function fmtDM(d) { return ('0' + d.getDate()).slice(-2) + '/' + ('0' + (d.getMonth() + 1)).slice(-2); }
function rangeDays(range, custom) {
  if (range === 'custom') {
    const p = s => { const [d, m, y] = s.split('/').map(Number); return new Date(y, m - 1, d); };
    try { return Math.max(1, Math.round((p(custom.to) - p(custom.from)) / 864e5) + 1); } catch (e) { return 14; }
  }
  return { '1d': 1, '7d': 7, '30d': 30 }[range] || 1;
}
function spanForDays(days, endOffset = 0) {
  const end = new Date(REPORT_TODAY); end.setDate(end.getDate() - endOffset);
  const start = new Date(end); start.setDate(start.getDate() - (days - 1));
  return { label: fmtDM(start) + ' – ' + fmtDM(end) };
}
function compareSpan(days, cmpKey) {
  const p = CMP_PROFILE[cmpKey]; if (!p) return null;
  return p.shift === 'adjacent' ? spanForDays(days, days) : spanForDays(days, p.shift);
}
function deltaPct(cur, cmp) { return cmp ? Math.round(((cur - cmp) / cmp) * 100) : 0; }

function DateRangeBar({ range, setRange, custom, setCustom, cmp, setCmp }) {
  const days = rangeDays(range, custom);
  const cur = range === 'custom' ? { label: custom.from + ' – ' + custom.to } : spanForDays(days);
  const cs = compareSpan(days, cmp);
  return (
    <div className="row aic g10 wrap" style={{ padding: '12px 16px', background: 'var(--p-bg-surface-tertiary)', borderRadius: 12, marginBottom: 16 }}>
      <Seg value={range} onChange={setRange} options={[{ value: '1d', label: '1 ngày' }, { value: '7d', label: '7 ngày' }, { value: '30d', label: '30 ngày' }, { value: 'custom', label: 'Tùy chọn' }]} />
      {range === 'custom' && (
        <span className="row aic g6">
          <Input icon="calendar" value={custom.from} onChange={v => setCustom({ ...custom, from: v })} style={{ width: 132 }} />
          <span className="t12 subtle">→</span>
          <Input icon="calendar" value={custom.to} onChange={v => setCustom({ ...custom, to: v })} style={{ width: 132 }} />
        </span>
      )}
      <span className="badge info"><Icon name="calendar" size={12} />{cur.label} · {days} ngày</span>
      <span className="mla row aic g8">
        <span className="t12 subtle">So sánh với:</span>
        <Select value={cmp} onChange={setCmp} options={[{ value: 'none', label: 'Tắt' }, { value: 'prev', label: 'Kỳ trước liền kề' }, { value: 'lastmonth', label: 'Cùng kỳ tháng trước' }]} style={{ width: 180 }} />
        {cs && <span className="t12 subtle">({cs.label})</span>}
      </span>
    </div>
  );
}

function InboxHeatmap({ grid: realGrid }) {
  const days = ['T2', 'T3', 'T4', 'T5', 'T6', 'T7', 'CN'];
  const bands = ['8–10h', '10–12h', '12–14h', '14–16h', '16–18h', '18–20h'];
  // [day][band]
  const grid = realGrid || [
    [14, 28, 16, 30, 38, 22],
    [18, 32, 18, 34, 40, 26],
    [16, 30, 14, 36, 44, 30],
    [20, 34, 20, 38, 46, 28],
    [22, 36, 18, 32, 42, 34],
    [28, 40, 24, 30, 36, 44],
    [24, 30, 20, 22, 28, 38],
  ];
  const max = Math.max(1, ...grid.flat());
  return (
    <div>
      <div style={{ display: 'grid', gridTemplateColumns: '46px repeat(6, 1fr)', gap: 4 }}>
        <div />
        {bands.map(b => <div key={b} className="t11 subtle center" style={{ fontWeight: 600 }}>{b}</div>)}
        {days.map((d, di) => (
          <React.Fragment key={d}>
            <div className="t11 subtle" style={{ display: 'flex', alignItems: 'center', fontWeight: 600 }}>{d}</div>
            {grid[di].map((v, bi) => { const a = 0.12 + 0.88 * (v / max); return (
              <div key={bi} className="center" title={d + ' ' + bands[bi] + ': ' + v + ' data'} style={{ height: 30, borderRadius: 6, background: `rgba(124,58,237,${a})`, color: a > 0.55 ? '#fff' : '#573b8a', fontSize: 11, fontWeight: 600, cursor: 'default' }}>{v}</div>
            ); })}
          </React.Fragment>
        ))}
      </div>
      <div className="row aic g8 mt12 t11 subtle">
        <span>Ít</span>
        <div className="row" style={{ gap: 3 }}>{[0.18, 0.4, 0.6, 0.8, 1].map(a => <span key={a} style={{ width: 18, height: 10, borderRadius: 3, background: `rgba(124,58,237,${a})` }} />)}</div>
        <span>Nhiều</span>
        <span className="mla">Khung 16–18h T4–T6 là giờ vàng — nên xếp đủ trực.</span>
      </div>
    </div>
  );
}

const DISPO = { consulted: { l: 'Đã tư vấn', tone: 'success', c: '#0a9e6e' }, callback: { l: 'Hẹn gọi lại', tone: 'info', c: '#3b82f6' }, noanswer: { l: 'Không nghe máy', tone: 'warning', c: '#d97706' }, refused: { l: 'Từ chối', tone: 'critical', c: '#ef4444' }, wrong: { l: 'Sai số', tone: 'neutral', c: '#9ca3af' } };
const CALLTYPE = { new: 'Tư vấn mới', followup: 'Follow-up', care: 'CSKH' };
const CALL_DATA = [
  { id: 'c1', leadId: 'L1', dir: 'out', dur: '8:42', agent: 'u5', mins: 35, qcA: 8.2, qcH: 8.5, status: 'reviewed', disp: 'consulted', type: 'followup', talk: { a: 58, c: 42, int: 1, sil: 6 }, kw: ['nhượng quyền', 'học phí'], viol: [] },
  { id: 'c2', leadId: 'L2', dir: 'out', dur: '12:10', agent: 'u4', mins: 80, qcA: 9.0, qcH: 9.1, status: 'reviewed', disp: 'consulted', type: 'followup', talk: { a: 62, c: 38, int: 0, sil: 4 }, kw: ['proposal', 'vận hành'], viol: [] },
  { id: 'c3', leadId: 'L3', dir: 'in', dur: '3:24', agent: 'u4', mins: 120, qcA: 5.8, qcH: 5.5, status: 'disputed', disp: 'noanswer', type: 'new', talk: { a: 70, c: 30, int: 3, sil: 18 }, kw: ['marketing'], viol: ['Báo giá khi chưa qualify', 'Không chốt lịch hẹn'] },
  { id: 'c4', leadId: 'L6', dir: 'out', dur: '1:05', agent: 'u4', mins: 200, qcA: 4.2, qcH: null, status: 'auto', disp: 'noanswer', type: 'followup', talk: { a: 88, c: 12, int: 0, sil: 40 }, kw: [], viol: ['Không lắng nghe nhu cầu'] },
  { id: 'c5', leadId: 'L4', dir: 'out', dur: '6:30', agent: 'u9', mins: 240, qcA: 6.6, qcH: null, status: 'auto', disp: 'callback', type: 'new', talk: { a: 55, c: 45, int: 2, sil: 8 }, kw: ['AI', 'online'], viol: ['Không chốt lịch hẹn'] },
  { id: 'c6', leadId: 'L5', dir: 'out', dur: '9:12', agent: 'u5', mins: 300, qcA: 7.4, qcH: 7.6, status: 'reviewed', disp: 'consulted', type: 'new', talk: { a: 60, c: 40, int: 1, sil: 5 }, kw: ['nhượng quyền', 'trà sữa'], viol: [] },
  { id: 'c7', leadId: 'L8', dir: 'out', dur: '4:48', agent: 'u4', mins: 360, qcA: 8.1, qcH: null, status: 'auto', disp: 'consulted', type: 'new', talk: { a: 57, c: 43, int: 0, sil: 7 }, kw: ['chi phí', 'hải sản'], viol: [] },
  { id: 'c8', leadId: 'L7', dir: 'in', dur: '2:10', agent: 'u9', mins: 420, qcA: 5.0, qcH: 4.8, status: 'reviewed', disp: 'refused', type: 'new', talk: { a: 64, c: 36, int: 4, sil: 12 }, kw: ['giảm giá'], viol: ['Báo giá khi chưa qualify', 'Thái độ chưa chuẩn'] },
  { id: 'c9', leadId: 'L9', dir: 'out', dur: '0:48', agent: 'u9', mins: 480, qcA: 3.6, qcH: null, status: 'auto', disp: 'wrong', type: 'new', talk: { a: 90, c: 10, int: 0, sil: 30 }, kw: [], viol: ['Sai số'] },
  { id: 'c10', leadId: 'L10', dir: 'out', dur: '7:20', agent: 'u4', mins: 540, qcA: 8.8, qcH: 9.0, status: 'reviewed', disp: 'consulted', type: 'care', talk: { a: 61, c: 39, int: 0, sil: 3 }, kw: ['nâng cao', 'gia hạn'], viol: [] },
  { id: 'c11', leadId: 'L2', dir: 'out', dur: '5:55', agent: 'u5', mins: 600, qcA: 7.0, qcH: null, status: 'auto', disp: 'callback', type: 'followup', talk: { a: 59, c: 41, int: 1, sil: 9 }, kw: ['proposal'], viol: ['Không chốt lịch hẹn'] },
  { id: 'c12', leadId: 'L3', dir: 'out', dur: '3:02', agent: 'u5', mins: 660, qcA: 6.2, qcH: null, status: 'auto', disp: 'consulted', type: 'followup', talk: { a: 66, c: 34, int: 2, sil: 11 }, kw: ['đối thủ'], viol: ['Xử lý phản đối yếu'] },
  { id: 'c13', leadId: 'L1', dir: 'in', dur: '10:05', agent: 'u5', mins: 720, qcA: 8.4, qcH: 8.6, status: 'reviewed', disp: 'consulted', type: 'followup', talk: { a: 54, c: 46, int: 0, sil: 5 }, kw: ['chốt', 'early-bird'], viol: [] },
  { id: 'c14', leadId: 'L5', dir: 'out', dur: '2:40', agent: 'u9', mins: 800, qcA: 5.4, qcH: null, status: 'auto', disp: 'noanswer', type: 'new', talk: { a: 80, c: 20, int: 1, sil: 22 }, kw: [], viol: [] },
  { id: 'c15', leadId: 'L4', dir: 'out', dur: '6:14', agent: 'u4', mins: 880, qcA: 7.8, qcH: null, status: 'auto', disp: 'callback', type: 'followup', talk: { a: 58, c: 42, int: 0, sil: 6 }, kw: ['lịch khai giảng'], viol: [] },
  { id: 'c16', leadId: 'L8', dir: 'out', dur: '4:30', agent: 'u5', mins: 960, qcA: 6.9, qcH: null, status: 'auto', disp: 'consulted', type: 'new', talk: { a: 63, c: 37, int: 2, sil: 8 }, kw: ['chi phí'], viol: ['Không chốt lịch hẹn'] },
];
function callScore(c) { return c.qcH != null ? c.qcH : c.qcA; }
function callVerdict(c) { return callScore(c) >= 7 ? 'pass' : 'fail'; }

const SAMPLE_TRANSCRIPT = [
  { t: '00:03', who: 'agent', s: 'pos', text: 'Dạ em chào anh, em gọi từ AAU Academy về khóa anh đang quan tâm ạ.' },
  { t: '00:11', who: 'cust', s: 'neu', text: 'Ừ, mà anh đang hơi bận, học phí nhiêu vậy em?' },
  { t: '00:18', who: 'agent', s: 'neg', text: 'Dạ khóa học phí 18.9 triệu anh ạ.', viol: 'Báo giá khi chưa qualify' },
  { t: '00:27', who: 'cust', s: 'neg', text: 'Đắt vậy, bên đối thủ rẻ hơn mà.' },
  { t: '00:35', who: 'agent', s: 'neu', text: 'Dạ để em gửi anh so sánh giá trị và case study chuỗi tương tự nhé.' },
  { t: '00:48', who: 'cust', s: 'pos', text: 'Ừ em gửi đi, mà chốt lịch khai giảng giúp anh luôn.' },
];

function hl(text, kws) {
  if (!kws || !kws.length) return text;
  let nodes = [text];
  kws.forEach((k, ki) => {
    const next = [];
    nodes.forEach(node => {
      if (typeof node !== 'string') { next.push(node); return; }
      const low = node.toLowerCase(), kl = k.toLowerCase();
      let idx = 0, pos;
      while ((pos = low.indexOf(kl, idx)) !== -1) {
        if (pos > idx) next.push(node.slice(idx, pos));
        next.push(<mark key={ki + '-' + pos} style={{ background: '#fff3cf', padding: '0 2px', borderRadius: 3 }}>{node.slice(pos, pos + k.length)}</mark>);
        idx = pos + k.length;
      }
      if (idx < node.length) next.push(node.slice(idx));
    });
    nodes = next;
  });
  return nodes;
}

function TalkBar({ talk }) {
  const over = talk.a > 65;
  return (
    <div>
      <div className="row" style={{ height: 12, borderRadius: 6, overflow: 'hidden' }}>
        <div style={{ width: talk.a + '%', background: '#1a4fa3' }} />
        <div style={{ width: talk.c + '%', background: '#0a9e6e' }} />
      </div>
      <div className="row jcsb t11 mt4"><span style={{ color: '#1a4fa3', fontWeight: 600 }}>Agent {talk.a}%</span><span style={{ color: '#0a9e6e', fontWeight: 600 }}>Khách {talk.c}%</span></div>
      <div className="row g16 mt8 t12 aic"><span className="subtle">Ngắt lời: <b style={{ color: 'var(--p-text)' }}>{talk.int}</b></span><span className="subtle">Khoảng lặng dài: <b style={{ color: 'var(--p-text)' }}>{talk.sil}s</b></span>{over && <span className="badge warning" style={{ marginLeft: 'auto' }}>Agent nói quá nhiều</span>}</div>
    </div>
  );
}

function CoachItem({ who, at, text, ack }) {
  return (
    <div style={{ padding: '10px 12px', borderRadius: 10, border: '1px solid var(--p-border)' }}>
      <div className="row aic g8 mb4"><span className="t12 fw6">{who}</span><span className="t11 subtle">{at}</span>{ack ? <span className="badge success" style={{ marginLeft: 'auto', fontSize: 10 }}>Agent đã đọc</span> : <span className="badge warning" style={{ marginLeft: 'auto', fontSize: 10 }}>Chờ xác nhận</span>}</div>
      <div className="t13">{text}</div>
    </div>
  );
}

// Chuẩn hoá 1 cuộc gọi từ backend (AAU.calls: {id,leadId,dir,duration,agent,at,qc,verdict})
// về shape mà UI QC cần — các field QC sâu (talk/viol/kw) để mặc định rỗng cho tới khi
// engine QC chấm (CQA). KHÔNG còn dùng CALL_DATA hardcode.
function normCall(c) {
  const dispMap = { pass: 'consulted', fail: 'refused', callback: 'callback', 'no-answer': 'noanswer', noanswer: 'noanswer' };
  return {
    id: c.id, leadId: c.leadId, dir: c.dir || 'out',
    dur: c.duration || c.dur || '—', agent: c.agent, mins: c.mins || 0,
    qcA: c.qc != null ? c.qc : (c.qcA != null ? c.qcA : null),
    qcH: c.qcH != null ? c.qcH : null, status: c.status || 'auto',
    disp: c.disp || dispMap[c.verdict] || 'consulted', type: c.type || 'new',
    talk: c.talk || { a: 0, c: 0, int: 0, sil: 0 }, kw: c.kw || [], viol: c.viol || [], at: c.at,
  };
}
function CallLogEmpty() {
  return (
    <div className="page wide">
      <PageHead title="Cuộc gọi & QC" subtitle="Nhật ký cuộc gọi + chấm điểm chất lượng, coaching & hàng đợi gọi lại" />
      <EmptyState icon="phone" title="Chưa có cuộc gọi nào"
        desc="Đã xoá data mẫu. Cuộc gọi thật sẽ hiện khi có log click-to-call hoặc engine QC chấm. Màn này nay đọc từ AAU.calls (backend thật), không còn data cứng." />
    </div>
  );
}
// Wrapper: rỗng → EmptyState (tránh chia 0 / crash); có data → body đọc AAU.calls thật.
function CallLogQC() {
  if (!AAU.calls || AAU.calls.length === 0) return <CallLogEmpty />;
  return <CallLogQCBody />;
}
function CallLogQCBody() {
  const [open, setOpen] = useState(null);
  const [playing, setPlaying] = useState(false);
  const [cbSet, setCbSet] = useState(false);
  const [range, setRange] = useState('1d');
  const [custom, setCustom] = useState({ from: '19/05/2026', to: '02/06/2026' });
  const [cmp, setCmp] = useState('prev');
  const [fAgent, setFAgent] = useState('all');
  const [fVerdict, setFVerdict] = useState('all');
  const [fDisp, setFDisp] = useState('all');
  const [fType, setFType] = useState('all');
  const [tab, setTab] = useState('qc');
  const [coach, setCoach] = useState('');
  const [coachSent, setCoachSent] = useState(false);
  const [cbDone, setCbDone] = useState({});
  useEffect(() => { setCbSet(false); setPlaying(false); setTab('qc'); setCoach(''); setCoachSent(false); }, [open]);

  const ruleset = AAU.qcRulesets[1];
  const sales = AAU.users.filter(u => u.role === 'sales');
  const enrich = c => { const u = AAU.users.find(x => x.id === c.agent); return { ...c, lead: AAU.leadById(c.leadId) || { name: c.leadId || 'Khách', company: '' }, agentName: u?.name, agentColor: u?.color, score: callScore(c), verdict: callVerdict(c), at: c.at || new Date(Date.now() - (c.mins || 0) * 60000).toISOString() }; };
  const all = AAU.calls.map(normCall).map(enrich);
  const rows = all.filter(c => (fAgent === 'all' || c.agent === fAgent) && (fVerdict === 'all' || c.verdict === fVerdict) && (fDisp === 'all' || c.disp === fDisp) && (fType === 'all' || c.type === fType));

  const days = rangeDays(range, custom);
  const prof = CMP_PROFILE[cmp];
  const cmpOn = !!prof;
  const perDay = 16;
  const calls = perDay * days;
  const totalMin = 96 * days;
  const durLabel = totalMin >= 60 ? Math.floor(totalMin / 60) + ' giờ ' + (totalMin % 60) + ' phút' : totalMin + ' phút';
  const passRate = Math.round(all.filter(c => c.verdict === 'pass').length / all.length * 100);
  const qcAvg = (all.reduce((s, c) => s + c.score, 0) / all.length).toFixed(1).replace('.', ',');
  const dCalls = cmpOn ? deltaPct(calls, perDay * days * prof.f) : null;
  const dQc = cmpOn ? deltaPct(6.9, prof.callQc) : null;
  const dPass = cmpOn ? passRate - prof.pass : null;
  const periodLabel = range === 'custom' ? custom.from + ' – ' + custom.to : spanForDays(days).label;
  const cmpLabel = cmpOn ? compareSpan(days, cmp).label : '';

  const byAgent = sales.map(u => { const cs = rows.filter(c => c.agent === u.id); const n = cs.length; const avg = n ? cs.reduce((s, c) => s + c.score, 0) / n : 0; return { u, n, avg, pass: n ? Math.round(cs.filter(c => c.verdict === 'pass').length / n * 100) : 0 }; }).sort((a, b) => b.avg - a.avg);
  const violCounts = {};
  rows.forEach(c => c.viol.forEach(v => { violCounts[v] = (violCounts[v] || 0) + 1; }));
  const topViol = Object.entries(violCounts).map(([l, v]) => ({ l, v })).sort((a, b) => b.v - a.v).slice(0, 5);
  const violMax = Math.max(1, ...topViol.map(t => t.v));
  const dispAgg = Object.keys(DISPO).map(k => ({ l: DISPO[k].l, v: rows.filter(c => c.disp === k).length, color: DISPO[k].c })).filter(d => d.v > 0);
  const queue = all.filter(c => ['callback', 'noanswer'].includes(c.disp));

  const trendDays = Math.min(Math.max(days, 7), 30);
  const trend = Array.from({ length: trendDays }, (_, i) => { const d = new Date(REPORT_TODAY); d.setDate(d.getDate() - (trendDays - 1 - i)); return { l: fmtDM(d), v: 12 + ((i * 7 + 5) % 9) }; });
  const qcTrend = Array.from({ length: trendDays }, (_, i) => { const d = new Date(REPORT_TODAY); d.setDate(d.getDate() - (trendDays - 1 - i)); return { l: fmtDM(d), v: +(6.2 + ((i * 3 + 2) % 16) / 10).toFixed(1) }; });

  const cols = [
    { key: 'lead', label: 'Khách hàng', render: c => <div className="linkish" onClick={e => { e.stopPropagation(); navigate('/leads/' + c.leadId); }}>{c.lead.name}<div className="t11 subtle">{c.lead.company}</div></div>, csv: c => c.lead.name },
    { key: 'type', label: 'Loại', render: c => <span className="t12">{CALLTYPE[c.type]}</span> },
    { key: 'dir', label: 'Hướng', render: c => <Badge tone={c.dir === 'out' ? 'info' : 'neutral'}>{c.dir === 'out' ? 'Gọi đi' : 'Gọi đến'}</Badge> },
    { key: 'disp', label: 'Kết quả', render: c => <Badge tone={DISPO[c.disp].tone}>{DISPO[c.disp].l}</Badge> },
    { key: 'dur', label: 'Thời lượng', num: true },
    { key: 'agentName', label: 'Agent' },
    { key: 'at', label: 'Thời gian', render: c => relTime(c.at) + ' trước', csv: c => c.mins + 'm' },
    { key: 'score', label: 'QC', num: true, render: c => <span className="row aic g6" style={{ justifyContent: 'flex-end' }}><span className="fw7" style={{ color: c.score >= 7 ? '#0e7c4a' : '#c4320a' }}>{c.score}</span>{c.qcH != null ? <span className="badge neutral" style={{ fontSize: 9, padding: '0 4px' }}>QC</span> : <span className="badge magic" style={{ fontSize: 9, padding: '0 4px' }}>AI</span>}</span> },
    { key: 'verdict', label: 'Verdict', render: c => <Badge tone={c.verdict === 'pass' ? 'success' : 'critical'}>{c.verdict.toUpperCase()}</Badge> },
    { key: 'review', label: 'Review', render: c => c.status === 'reviewed' ? <Badge tone="success" dot>Đã duyệt</Badge> : c.status === 'disputed' ? <Badge tone="critical" dot>Khiếu nại</Badge> : <Badge tone="neutral" dot>AI tự động</Badge> },
    { key: 'act', label: '', sortable: false, render: c => <Button size="sm" icon="play" onClick={e => { e.stopPropagation(); setOpen(c); }}>Nghe</Button> },
  ];
  const toolbar = (
    <div className="row aic g8 wrap">
      <Select value={fAgent} onChange={setFAgent} options={[{ value: 'all', label: 'Mọi agent' }, ...sales.map(u => ({ value: u.id, label: u.name }))]} style={{ width: 132 }} />
      <Select value={fType} onChange={setFType} options={[{ value: 'all', label: 'Mọi loại' }, ...Object.entries(CALLTYPE).map(([v, l]) => ({ value: v, label: l }))]} style={{ width: 128 }} />
      <Select value={fDisp} onChange={setFDisp} options={[{ value: 'all', label: 'Mọi kết quả' }, ...Object.entries(DISPO).map(([v, o]) => ({ value: v, label: o.l }))]} style={{ width: 140 }} />
      <Select value={fVerdict} onChange={setFVerdict} options={[{ value: 'all', label: 'PASS + FAIL' }, { value: 'pass', label: 'Chỉ PASS' }, { value: 'fail', label: 'Chỉ FAIL' }]} style={{ width: 126 }} />
    </div>
  );

  return (
    <div className="page wide">
      <PageHead title="Cuộc gọi & QC" subtitle="Nhật ký cuộc gọi + chấm điểm chất lượng, coaching & hàng đợi gọi lại"
        actions={<><Button icon="download">Xuất</Button><Button icon="settings" onClick={() => navigate('/qc/rulesets')}>Bộ tiêu chí</Button></>} />
      <DateRangeBar range={range} setRange={setRange} custom={custom} setCustom={setCustom} cmp={cmp} setCmp={setCmp} />
      {cmpOn && (
        <div className="row aic g8" style={{ padding: '9px 14px', borderRadius: 10, background: 'var(--p-info-bg)', color: 'var(--p-info-text)', marginBottom: 16, fontSize: 12.5 }}>
          <Icon name="chart" size={15} />Đang so sánh <b>{periodLabel}</b> với <b>{cmpLabel}</b> ({prof.label}).
        </div>
      )}
      <div className="grid gc4 mb16">
        <KPI label="Cuộc gọi trong kỳ" value={calls} delta={cmpOn ? dCalls : null} sub={cmpOn ? 'so ' + prof.label : days + ' ngày'} icon="phone" />
        <KPI label="Điểm QC TB" value={qcAvg} delta={cmpOn ? dQc : null} sub={cmpOn ? 'so ' + prof.label : 'thang 10'} icon="checkCircle" />
        <KPI label="Tỷ lệ PASS" value={passRate + '%'} delta={cmpOn ? dPass : null} sub={cmpOn ? 'so ' + prof.label : 'qua QC'} icon="target" />
        <KPI label="Tổng thời lượng" value={durLabel} delta={cmpOn ? dCalls : null} sub={cmpOn ? 'so ' + prof.label : 'TB ~6 ph/cuộc'} icon="clock" />
      </div>

      {queue.length > 0 && (
        <Card title={'Hàng đợi cần gọi lại (' + queue.length + ')'} subtitle="Cuộc gọi nhỡ / hẹn gọi lại — ưu tiên xử lý trong ngày" className="mb16">
          <div className="col g8">
            {queue.map(c => cbDone[c.id] ? (
              <div key={c.id} className="row aic g10" style={{ padding: '9px 12px', borderRadius: 10, background: 'var(--p-success-bg)' }}><Icon name="check" size={15} color="#0e7c4a" /><span className="t13" style={{ color: '#0e7c4a' }}>Đã xử lý — {c.lead.name}</span></div>
            ) : (
              <div key={c.id} className="row aic g12" style={{ padding: '10px 12px', borderRadius: 10, border: '1px solid var(--p-border)' }}>
                <Avatar name={c.lead.name} size={32} color={c.agentColor} />
                <div className="f1"><div className="t13 fw6 linkish" onClick={() => navigate('/leads/' + c.leadId)}>{c.lead.name} <span className="subtle" style={{ fontWeight: 400 }}>· {c.lead.company}</span></div><div className="t11 subtle">{DISPO[c.disp].l} · {relTime(c.at)} trước · phụ trách {c.agentName}</div></div>
                <Badge tone="warning"><Icon name="clock" size={11} />Hạn: hôm nay</Badge>
                <Button size="sm" variant="primary" icon="phone" onClick={() => setCbDone(s => ({ ...s, [c.id]: true }))}>Gọi lại</Button>
              </div>
            ))}
          </div>
        </Card>
      )}

      <div className="grid mb16" style={{ gridTemplateColumns: '1fr 1fr' }}>
        <Card title="Số cuộc gọi / ngày"><LineChart data={trend} color="#1a4fa3" height={210} /></Card>
        <Card title="Điểm QC TB / ngày"><LineChart data={qcTrend} color="#0a9e6e" height={210} fmt={v => v.toFixed(1)} /></Card>
      </div>

      <div className="grid mb16" style={{ gridTemplateColumns: '1.1fr 1.1fr 1fr' }}>
        <Card title="QC theo Agent">
          <table className="src-tbl">
            <thead><tr><th style={{ textAlign: 'left' }}>Agent</th><th style={{ textAlign: 'right' }}>Cuộc</th><th style={{ textAlign: 'right' }}>QC TB</th><th style={{ textAlign: 'right' }}>PASS</th></tr></thead>
            <tbody>
              {byAgent.map((a, i) => (
                <tr key={a.u.id}>
                  <td><span className="row aic g8"><span className="t12 fw7 subtle" style={{ width: 14 }}>{i + 1}</span><Avatar name={a.u.name} color={a.u.color} size={24} /><span className="fw6">{a.u.name}</span></span></td>
                  <td style={{ textAlign: 'right' }} className="tnum">{a.n}</td>
                  <td style={{ textAlign: 'right', color: a.avg >= 7 ? '#0e7c4a' : '#c4320a' }} className="fw7 tnum">{a.n ? a.avg.toFixed(1) : '—'}</td>
                  <td style={{ textAlign: 'right' }} className="tnum">{a.n ? a.pass + '%' : '—'}</td>
                </tr>
              ))}
            </tbody>
          </table>
        </Card>
        <Card title="Top tiêu chí hay rớt">
          {topViol.length === 0 ? <div className="t12 muted" style={{ padding: 12 }}>Không có vi phạm trong bộ lọc hiện tại.</div> : (
            <div className="col g12" style={{ paddingTop: 4 }}>
              {topViol.map(t => (
                <div key={t.l}>
                  <div className="row jcsb t12 mb4"><span className="fw5">{t.l}</span><span className="subtle tnum">{t.v} lần</span></div>
                  <Progress value={Math.round(t.v / violMax * 100)} color="#c4320a" />
                </div>
              ))}
            </div>
          )}
        </Card>
        <Card title="Phân bổ kết quả">
          {dispAgg.length === 0 ? <div className="t12 muted" style={{ padding: 12 }}>Không có dữ liệu.</div> : (
            <div className="col g10 center"><Donut data={dispAgg} center={{ v: rows.length, l: 'cuộc gọi' }} /><div className="col g6" style={{ width: '100%' }}>{dispAgg.map(d => <div key={d.l} className="row jcsb aic"><span className="row aic g6 t12"><span style={{ width: 9, height: 9, borderRadius: 2, background: d.color }} />{d.l}</span><span className="fw6 tnum">{d.v}</span></div>)}</div></div>
          )}
        </Card>
      </div>

      <div className="t13 fw7 mb8">Nhật ký cuộc gọi</div>
      <DataTable columns={cols} rows={rows} getId={c => c.id} searchKeys={['agentName']} toolbar={toolbar} onRowClick={c => setOpen(c)} exportName="calls" pageSize={8} />

      {open && (
        <Drawer title="Chi tiết cuộc gọi & QC" width={560} onClose={() => setOpen(null)}>
          <div className="row aic g10 mb12">
            <Avatar name={open.lead.name} size={42} color={open.agentColor} />
            <div className="f1"><div className="t15 fw7 linkish" onClick={() => navigate('/leads/' + open.leadId)}>{open.lead.name}</div><div className="t12 muted">{open.lead.company} · {open.agentName} · {CALLTYPE[open.type]}</div></div>
            <Badge tone={open.verdict === 'pass' ? 'success' : 'critical'}>{open.verdict.toUpperCase()}</Badge>
          </div>
          <div className="row g10 mb14">
            <div className="f1 center col" style={{ padding: 10, borderRadius: 10, background: 'var(--p-magic-bg)' }}><span className="t11 fw6" style={{ color: '#573b8a' }}>AI chấm</span><span className="fw7" style={{ fontSize: 22, color: '#573b8a' }}>{open.qcA}</span></div>
            <div className="f1 center col" style={{ padding: 10, borderRadius: 10, background: open.qcH != null ? 'var(--p-success-bg)' : 'var(--p-bg-surface-tertiary)' }}><span className="t11 fw6 subtle">QC người</span><span className="fw7" style={{ fontSize: 22 }}>{open.qcH != null ? open.qcH : '—'}</span></div>
            <div className="f1 center col" style={{ padding: 10, borderRadius: 10, border: '1px solid var(--p-border)' }}><span className="t11 fw6 subtle">Review</span><span className="t12 fw6 mt4 center" style={{ textAlign: 'center' }}>{open.status === 'reviewed' ? 'Đã duyệt' : open.status === 'disputed' ? 'Khiếu nại' : 'AI tự động'}</span></div>
          </div>
          <div style={{ padding: 14, borderRadius: 12, background: 'var(--p-bg-surface-tertiary)' }} className="mb14">
            <div className="row aic g12">
              <Button variant="primary" icon={playing ? 'pause' : 'play'} onClick={() => setPlaying(!playing)} />
              <div className="f1"><div className="prog"><span style={{ width: playing ? '45%' : '12%' }} /></div></div>
              <span className="t12 tnum subtle">{open.dur}</span>
              <IconButton name="download" title="Tải ghi âm" />
            </div>
          </div>
          <Tabs value={tab} onChange={setTab} tabs={[{ value: 'qc', label: 'Chấm điểm' }, { value: 'transcript', label: 'Transcript' }, { value: 'coaching', label: 'Coaching' }]} />
          <div className="mt14">
            {tab === 'qc' && (
              <div>
                <div className="t12 fw7 subtle mb8">PHÂN TÍCH HỘI THOẠI</div>
                <TalkBar talk={open.talk} />
                <div className="t12 fw7 subtle mb8 mt16">CHẤM ĐIỂM THEO TIÊU CHÍ</div>
                <div className="col g8">{ruleset.criteria.map((cr, i) => { const sc = [8, 6, 7, 4][i] ?? 6; return (<div key={i}><div className="row jcsb t12 mb4"><span>{cr.name} <span className="subtle">({cr.weight}%)</span></span><span className="fw7">{sc}/10</span></div><Progress value={sc} max={10} color={sc >= 7 ? '#0e7c4a' : '#c4320a'} /></div>); })}</div>
                {open.viol.length > 0 && (<div><div className="t12 fw7 subtle mb8 mt16">VI PHẠM PHÁT HIỆN</div><div className="col g6">{open.viol.map((v, i) => <div key={i} className="row aic g8" style={{ padding: '8px 10px', borderRadius: 8, background: 'var(--p-critical-bg)' }}><Icon name="alert" size={14} color="#8e1f0b" /><span className="t12" style={{ color: '#8e1f0b' }}>{v}</span></div>)}</div></div>)}
                <div className="t12 fw7 subtle mb8 mt16">KẾT QUẢ & FOLLOW-UP</div>
                <div className="col g10" style={{ padding: 14, borderRadius: 12, border: '1px solid var(--p-border)' }}>
                  <div className="row jcsb aic"><span className="t13">Kết quả cuộc gọi</span><Badge tone={DISPO[open.disp].tone}>{DISPO[open.disp].l}</Badge></div>
                  <div className="row jcsb aic"><span className="t13">Lịch gọi lại</span><div className="row g8 aic"><Input icon="calendar" value="03/06/2026 09:00" onChange={() => {}} style={{ width: 168 }} /><Button size="sm" variant={cbSet ? 'success' : 'secondary'} icon={cbSet ? 'check' : 'clock'} onClick={() => setCbSet(true)}>{cbSet ? 'Đã đặt' : 'Đặt lịch'}</Button></div></div>
                  <div className="row g8"><Button variant="secondary" icon="kanban" onClick={() => navigate('/leads/' + open.leadId)}>Chuyển stage</Button><Button variant="plain" icon="checkCircle" onClick={() => navigate('/leads/' + open.leadId)}>Tạo task follow-up</Button></div>
                </div>
              </div>
            )}
            {tab === 'transcript' && (
              <div className="col g10">
                <div className="t11 subtle">Click một dòng để tua tới đoạn ghi âm tương ứng. Từ khóa quan trọng được tô sáng.</div>
                {SAMPLE_TRANSCRIPT.map((l, i) => { const sc = { pos: '#0a9e6e', neu: '#8a8a8a', neg: '#c4320a' }[l.s]; return (
                  <div key={i} onClick={() => setPlaying(true)} className="row g10" style={{ cursor: 'pointer' }}>
                    <span className="t11 tnum subtle" style={{ width: 42, flexShrink: 0, paddingTop: 2 }}>{l.t}</span>
                    <span style={{ width: 4, borderRadius: 3, background: sc, flexShrink: 0 }} />
                    <div className="f1"><div className="t11 fw6" style={{ color: l.who === 'agent' ? '#1a4fa3' : '#0a9e6e' }}>{l.who === 'agent' ? 'Agent' : 'Khách'}</div><div className="t13">{hl(l.text, open.kw)}</div>{l.viol && <span className="badge critical" style={{ fontSize: 10, marginTop: 4 }}>Vi phạm: {l.viol}</span>}</div>
                  </div>
                ); })}
                {open.kw.length > 0 && <div className="row g6 wrap mt6">{open.kw.map(k => <span key={k} className="tag" style={{ background: '#fff3cf', color: '#7a4d00' }}><Icon name="search" size={11} />{k}</span>)}</div>}
              </div>
            )}
            {tab === 'coaching' && (
              <div className="col g14">
                <div>
                  <div className="t12 fw7 subtle mb6">GỬI NHẬN XÉT CHO {(open.agentName || '').toUpperCase()}</div>
                  <textarea className="input" rows={3} value={coach} onChange={e => setCoach(e.target.value)} placeholder="Nhận xét điểm cần cải thiện, ví dụ: chưa chốt lịch hẹn rõ ràng…" style={{ resize: 'none' }} />
                  <div className="row jcsb aic mt8"><span className="t11 subtle">Agent sẽ nhận thông báo & xác nhận đã đọc.</span><Button size="sm" variant="primary" icon="send" onClick={() => setCoachSent(true)} disabled={!coach.trim() && !coachSent}>{coachSent ? 'Đã gửi' : 'Gửi nhận xét'}</Button></div>
                </div>
                <div>
                  <div className="t12 fw7 subtle mb8">LỊCH SỬ COACHING</div>
                  <div className="col g10">
                    {coachSent && <CoachItem who="Bạn" at="vừa xong" text={coach || '(nhận xét mới)'} ack={false} />}
                    <CoachItem who="Trần Quản Lý" at="2 ngày trước" text="Cần xác nhận ngân sách trước khi báo giá — lần này báo giá hơi sớm." ack={true} />
                    <CoachItem who="Trần Quản Lý" at="1 tuần trước" text="Mở đầu chuyên nghiệp, giữ nhịp này nhé." ack={true} />
                  </div>
                </div>
              </div>
            )}
          </div>
        </Drawer>
      )}
    </div>
  );
}

function InboxReportEmpty() {
  return (
    <div className="page wide">
      <PageHead title="Báo cáo Inbox" subtitle="Tổng hợp hội thoại, tốc độ phản hồi, QC chat theo ngày" />
      <EmptyState icon="chart" title="Chưa có dữ liệu hội thoại để báo cáo"
        desc="Đã xoá data mẫu. Báo cáo sẽ có số khi hội thoại thật được đồng bộ về (nối CQA + Đồng bộ kênh ở Nguồn kết nối)." />
    </div>
  );
}
// Wrapper: chưa có hội thoại thật → EmptyState (không hiện báo cáo giả).
function InboxDailyReport() {
  if (!AAU.conversations || Object.keys(AAU.conversations).length === 0) return <InboxReportEmpty />;
  return <InboxDailyReportBody />;
}
function InboxDailyReportBody() {
  const live = !!(window.API && window.API.enabled);
  const [range, setRange] = useState('7d');
  const [custom, setCustom] = useState({ from: '19/05/2026', to: '02/06/2026' });
  const [cmp, setCmp] = useState('none');
  const [rep, setRep] = useState(null);
  const [loading, setLoading] = useState(false);

  const isoD = d => d.getFullYear() + '-' + String(d.getMonth() + 1).padStart(2, '0') + '-' + String(d.getDate()).padStart(2, '0');
  const range2dates = () => {
    if (range === 'custom') { const p = s => { const [d, m, y] = s.split('/').map(Number); return new Date(y, m - 1, d); }; try { return { from: isoD(p(custom.from)), to: isoD(p(custom.to)) }; } catch (e) { return {}; } }
    const dd = rangeDays(range, custom); const end = new Date(); const start = new Date(); start.setDate(end.getDate() - (dd - 1));
    return { from: isoD(start), to: isoD(end) };
  };
  useEffect(() => {
    if (!live || !window.API.inboxReport) { setRep(null); return; }
    const { from, to } = range2dates(); let alive = true; setLoading(true);
    window.API.inboxReport({ from, to }).then(r => { if (alive) setRep(r); }).catch(() => { if (alive) setRep(null); }).finally(() => { if (alive) setLoading(false); });
    return () => { alive = false; };
  }, [live, range, custom]);

  const days = rangeDays(range, custom);
  const fmtN = n => Math.round(n || 0).toLocaleString('vi-VN');
  const fmtFrt = m => !m ? '—' : (m < 60 ? (Math.round(m * 10) / 10).toString().replace('.', ',') + ' ph' : (Math.round(m / 6) / 10).toString().replace('.', ',') + ' h');
  const chMeta = ch => (AAU.channels && AAU.channels[ch]) || { label: ch, color: '#8a8f98' };
  const userName = id => (AAU.users || []).find(u => u.id === id)?.name || id;
  const userColor = id => (AAU.users || []).find(u => u.id === id)?.color || '#5b6cff';
  const _rd = range2dates();
  const _dm = iso => { try { const [y, m, d] = iso.split('-'); return d + '/' + m; } catch (e) { return iso; } };
  const periodLabel = range === 'custom' ? custom.from + ' – ' + custom.to : (_rd.from && _rd.to ? _dm(_rd.from) + ' – ' + _dm(_rd.to) : spanForDays(days).label);

  // ===== số liệu THẬT khi LIVE (rep), else MOCK demo =====
  const liveData = live && rep;
  const k = liveData ? rep.kpi : { data: 320 * days, replied: Math.round(320 * days * 0.92), replyRate: 92, avgFrtMin: 4.2, unanswered: 0 };
  const srcRows = liveData
    ? (rep.bySource || []).map(s => ({ page: s.account || chMeta(s.channel).label, ch: s.channel, sync: true, data: s.data, replied: s.replied, frtMin: s.frtMin, rate: Math.round(s.replyRate) }))
    : [{ page: 'Fanpage F&B Academy', ch: 'fb', sync: true, data: 96 * days, replied: 92 * days, frtMin: 3.1 }, { page: 'Zalo OA Học viện', ch: 'zalo', sync: true, data: 86 * days, replied: 82 * days, frtMin: 2.8 }].map(s => ({ ...s, rate: Math.round(s.replied / s.data * 100) }));
  const chanRows = liveData
    ? (rep.byChannel || []).map(c => ({ l: chMeta(c.channel).label, v: c.count, color: chMeta(c.channel).color }))
    : [{ l: 'FB', v: 142 * days, color: '#0084ff' }, { l: 'Zalo', v: 86 * days, color: '#0068ff' }];
  const totalChan = chanRows.reduce((a, b) => a + b.v, 0);
  const hourly = liveData
    ? (rep.byHour || []).filter(h => h.hour >= 6 && h.hour <= 22).map(h => ({ l: h.hour + 'h', v: h.count }))
    : ['8h', '9h', '10h', '11h', '12h', '13h', '14h', '15h', '16h', '17h', '18h', '19h'].map((l, i) => ({ l, v: [12, 28, 34, 30, 18, 14, 26, 38, 42, 36, 22, 16][i] * days }));
  // heatmap: fold [7][24] → [7][6] band 8-20
  const heatGrid = liveData && rep.heat ? rep.heat.map(row => [0, 1, 2, 3, 4, 5].map(b => (row[8 + b * 2] || 0) + (row[9 + b * 2] || 0))) : null;
  const lb = liveData
    ? (rep.leaderboard || []).map(r => ({ id: r.sales, name: userName(r.sales), color: userColor(r.sales), convos: r.convos, respond: Math.round(r.replyRate), frtMin: r.frtMin, closes: r.won }))
    : [{ name: 'Phạm Tuấn', color: '#0a9e6e', convos: 64 * days, respond: 95, frtMin: 2.6, closes: 3 * days }];
  const fn = liveData ? rep.funnel : { data: 320 * days, leads: 198 * days, twoWay: 142 * days, won: 6 * days };
  const funnelSteps = [
    { l: 'Data về', v: fn.data, color: '#8a8a8a' },
    { l: 'Thành Lead', v: fn.leads, color: '#3b82f6' },
    { l: 'Chat 2 chiều', v: fn.twoWay, color: '#0a9e6e' },
    { l: 'Won', v: fn.won, color: '#7c3aed' },
  ];
  const unanswered = liveData ? (rep.unansweredList || []) : [];

  return (
    <div className="page wide">
      <PageHead title="Báo cáo Inbox" subtitle={'Số liệu THẬT từ hội thoại · ' + periodLabel + (liveData ? '' : ' · (demo — bật LIVE để xem số thật)')}
        actions={<Button icon="refresh" onClick={() => { const { from, to } = range2dates(); if (live) window.API.inboxReport({ from, to }).then(setRep); }} disabled={loading}>{loading ? 'Đang tải…' : 'Tải lại'}</Button>} />
      <DateRangeBar range={range} setRange={setRange} custom={custom} setCustom={setCustom} cmp={cmp} setCmp={setCmp} />
      {!live && <div className="row aic g8 mb16" style={{ padding: '9px 14px', borderRadius: 10, background: 'var(--p-warning-bg)' }}><Icon name="alert" size={15} color="#b06f00" /><span className="t12">Đang ở MOCK — mở app với <code>?api=…</code> để xem số liệu thật từ hội thoại.</span></div>}
      <div className="grid gc4 mb16">
        <KPI label="Data đổ về" value={fmtN(k.data)} sub={days + ' ngày · ' + chanRows.length + ' kênh'} icon="inbox" />
        <KPI label="Tỷ lệ phản hồi" value={Math.round(k.replyRate) + '%'} sub={fmtN(k.replied) + '/' + fmtN(k.data) + ' đã chat'} icon="message" />
        <KPI label="First response TB" value={fmtFrt(k.avgFrtMin)} sub="TB/hội thoại" icon="clock" />
        <KPI label="Chưa trả lời" value={fmtN(k.unanswered)} sub="khách đang chờ rep" icon="alert" />
      </div>

      {unanswered.length > 0 && (
        <Card title={'🔴 Hội thoại CHƯA trả lời (' + unanswered.length + ')'} subtitle="Khách nhắn mà chưa ai phản hồi — xếp theo thời gian chờ, xử trước cái lâu nhất" className="mb16">
          <table className="src-tbl">
            <thead><tr><th style={{ textAlign: 'left' }}>Khách</th><th>Nguồn</th><th style={{ textAlign: 'left' }}>Tin cuối</th><th style={{ textAlign: 'right' }}>Chờ</th><th></th></tr></thead>
            <tbody>
              {unanswered.slice(0, 15).map((w, i) => (
                <tr key={i} className="clickable" onClick={() => navigate('/inbox')}>
                  <td className="fw6">{w.name || '(khách)'}</td>
                  <td style={{ textAlign: 'center' }}><span className="t11" style={{ color: chMeta(w.channel).color, fontWeight: 600 }}>{chMeta(w.channel).label}{w.account ? ' · ' + w.account : ''}</span></td>
                  <td className="t12 muted" style={{ maxWidth: 280, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{w.lastText || '—'}</td>
                  <td style={{ textAlign: 'right' }} className="fw7 tnum"><span style={{ color: w.waitMin > 60 ? '#c4320a' : w.waitMin > 15 ? '#b06f00' : '#0e7c4a' }}>{fmtFrt(w.waitMin)}</span></td>
                  <td style={{ textAlign: 'right' }}><Button size="sm" variant="plain" icon="chevronRight" /></td>
                </tr>
              ))}
            </tbody>
          </table>
        </Card>
      )}

      <Card title="Báo cáo theo nguồn (kênh / tài khoản thật)" className="mb16"
        actions={<Button size="sm" icon="refresh" onClick={() => navigate('/system/channels')}>Quản lý kết nối</Button>}>
        {srcRows.length === 0 ? <div className="t13 muted center" style={{ padding: 20 }}>Chưa có hội thoại trong kỳ này.</div> : (
        <table className="src-tbl">
          <thead>
            <tr>
              <th style={{ textAlign: 'left' }}>Nguồn / Tài khoản</th>
              <th>Kênh</th>
              <th style={{ textAlign: 'right' }}>Data về</th>
              <th style={{ textAlign: 'right' }}>Đã phản hồi</th>
              <th style={{ textAlign: 'right' }}>Tỉ lệ respond</th>
              <th style={{ textAlign: 'right' }}>First response</th>
            </tr>
          </thead>
          <tbody>
            {srcRows.map((s, i) => { const rate = s.rate; return (
              <tr key={i}>
                <td className="fw6">{s.page}</td>
                <td style={{ textAlign: 'center' }}><ChannelDot ch={s.ch} size={18} /></td>
                <td style={{ textAlign: 'right' }} className="tnum">{fmtN(s.data)}</td>
                <td style={{ textAlign: 'right' }} className="tnum">{fmtN(s.replied)}</td>
                <td style={{ textAlign: 'right' }}>
                  <span className="row aic g8" style={{ justifyContent: 'flex-end' }}>
                    <span style={{ width: 54 }}><Progress value={rate} color={rate >= 90 ? '#0e7c4a' : rate >= 80 ? '#b06f00' : '#c4320a'} /></span>
                    <span className="fw7 tnum" style={{ minWidth: 34, color: rate >= 90 ? '#0e7c4a' : rate >= 80 ? '#b06f00' : '#c4320a' }}>{rate}%</span>
                  </span>
                </td>
                <td style={{ textAlign: 'right' }} className="tnum">{fmtFrt(s.frtMin)}</td>
              </tr>
            ); })}
          </tbody>
        </table>
        )}
      </Card>
      <div className="grid mb16" style={{ gridTemplateColumns: '1fr 1fr' }}>
        <Card title="Data về theo giờ"><BarChart data={hourly} color="#7c3aed" height={240} /></Card>
        <div className="col g12">
          <Card title="Data theo kênh"><div className="row aic g16"><Donut data={chanRows} center={{ v: fmtN(totalChan), l: 'hội thoại' }} /><div className="col g8">{chanRows.map(d => <div key={d.l} className="row jcsb aic" style={{ minWidth: 140 }}><span className="row aic g6 t12"><span style={{ width: 9, height: 9, borderRadius: 2, background: d.color }} />{d.l}</span><span className="fw6 tnum">{fmtN(d.v)}</span></div>)}</div></div></Card>
          <Card title="Phễu: Chat → Lead → Won">
            <Funnel steps={funnelSteps} />
          </Card>
        </div>
      </div>
      <Card title="Heatmap data về (giờ × ngày trong tuần)" subtitle="Xác định khung giờ cao điểm để xếp ca trực inbox" className="mb16"><InboxHeatmap grid={heatGrid} /></Card>
      <div className="grid" style={{ gridTemplateColumns: '1fr' }}>
        <Card title="Bảng xếp hạng theo Sales" subtitle="Hiệu suất xử lý inbox trong kỳ (theo lead phụ trách)">
          {lb.length === 0 ? <div className="t13 muted center" style={{ padding: 20 }}>Chưa có dữ liệu sales trong kỳ.</div> : (
          <table className="src-tbl">
            <thead>
              <tr>
                <th style={{ textAlign: 'left' }}>Sales</th>
                <th style={{ textAlign: 'right' }}>Hội thoại</th>
                <th style={{ textAlign: 'right' }}>Tỉ lệ respond</th>
                <th style={{ textAlign: 'right' }}>First response</th>
                <th style={{ textAlign: 'right' }}>Won</th>
              </tr>
            </thead>
            <tbody>
              {lb.map((r, i) => (
                <tr key={i}>
                  <td><span className="row aic g8"><span className="t12 fw7 subtle" style={{ width: 16 }}>{i + 1}</span><Avatar name={r.name} color={r.color} size={26} /><span className="fw6">{r.name}</span></span></td>
                  <td style={{ textAlign: 'right' }} className="tnum">{fmtN(r.convos)}</td>
                  <td style={{ textAlign: 'right', color: r.respond >= 90 ? '#0e7c4a' : '#b06f00' }} className="fw7 tnum">{r.respond}%</td>
                  <td style={{ textAlign: 'right' }} className="tnum">{fmtFrt(r.frtMin)}</td>
                  <td style={{ textAlign: 'right' }} className="fw7 tnum">{r.closes}</td>
                </tr>
              ))}
            </tbody>
          </table>
          )}
        </Card>
      </div>
    </div>
  );
}

function DataExplorer() {
  const [view, setView] = useState('all');
  const rows = AAU.leads;
  const cols = [
    { key: 'name', label: 'Tên', render: l => <span className="fw6">{l.name}</span> },
    { key: 'company', label: 'Công ty' },
    { key: 'phone', label: 'SĐT' },
    { key: 'email', label: 'Email' },
    { key: 'source', label: 'Nguồn', render: l => AAU.sourceMeta[l.source]?.label, csv: l => AAU.sourceMeta[l.source]?.label },
    { key: 'channel', label: 'Kênh', render: l => AAU.channels[l.channel]?.label },
    { key: 'stage', label: 'Stage', render: l => AAU.stageById(l.stage)?.name, csv: l => AAU.stageById(l.stage)?.name },
    { key: 'industry', label: 'Ngành' },
    { key: 'region', label: 'Khu vực' },
    { key: 'revenue', label: 'Doanh thu/th', num: true, render: l => AAU.fmtVNDm(l.revenue) },
    { key: 'grade', label: 'Grade' },
    { key: 'createdAt', label: 'Ngày tạo', render: l => AAU.fmtDate(l.createdAt) },
  ];
  const health = [
    { icon: 'phone', t: 'Thiếu SĐT', v: 0, tone: 'success' },
    { icon: 'users', t: 'Trùng lặp nghi ngờ', v: 2, tone: 'warning' },
    { icon: 'tag', t: 'Chưa gán nguồn', v: 0, tone: 'success' },
    { icon: 'user', t: 'Chưa gán phụ trách', v: 3, tone: 'critical' },
  ];
  return (
    <div className="page wide">
      <PageHead title="Data Sync Explorer" subtitle="Toàn bộ lead/customer đã đồng bộ — mọi trường, lọc đa điều kiện, saved views, xuất CSV"
        actions={<Button variant="primary" icon="save">Lưu view hiện tại</Button>} />
      <div className="grid gc4 mb16">
        {health.map((h, i) => (
          <div key={i} className="card pad row aic g12" style={{ cursor: 'pointer' }}>
            <span className="center" style={{ width: 38, height: 38, borderRadius: 10, background: 'var(--p-' + h.tone + '-bg)', color: 'var(--p-' + h.tone + '-text)' }}><Icon name={h.icon} size={18} /></span>
            <div><div className="t22 fw7" style={{ fontSize: 22 }}>{h.v}</div><div className="t12 muted">{h.t}</div></div>
          </div>
        ))}
      </div>
      <div className="row aic g8 mb12">
        <span className="t12 subtle">Saved views:</span>
        <PillTabs value={view} onChange={setView} options={[{ value: 'all', label: 'Tất cả' }, { value: 'hot', label: 'Hot leads' }, { value: 'unassigned', label: 'Chưa gán' }, { value: 'hcm', label: 'Khu vực HCM' }]} />
      </div>
      <DataTable columns={cols} rows={rows} getId={l => l.id} searchKeys={['name', 'company', 'phone', 'email']} selectable bulkActions={[{ icon: 'tag', label: 'Gán nguồn', onClick: () => {} }, { icon: 'user', label: 'Gán sales', onClick: () => {} }]} onRowClick={l => navigate('/leads/' + l.id)} exportName="data-explorer" pageSize={9} />
    </div>
  );
}

Object.assign(window, { CallLogQC, InboxDailyReport, DataExplorer });
