/* AAU CRM — Platform: QC, Analytics, RBAC, Settings, Automation */

// 10 mẫu ruleset đa dạng (chat + call) cho F&B education.
const QC_TEMPLATES = [
  { name: 'Chuẩn chat tư vấn', type: 'chat', channelScope: 'all', threshold: 7, criteria: [{ name: 'Chào hỏi đúng chuẩn', weight: 15 }, { name: 'Hỏi nhu cầu/qualify', weight: 25 }, { name: 'Báo giá & xử lý phản đối', weight: 30 }, { name: 'Chốt bước tiếp theo (CTA)', weight: 20 }, { name: 'Chính tả & thái độ', weight: 10 }] },
  { name: 'Chuẩn chat ngoài giờ (Bot AI)', type: 'chat', channelScope: 'all', threshold: 7, criteria: [{ name: 'Chào hỏi thân thiện', weight: 20 }, { name: 'Trả lời đúng theo KB', weight: 35 }, { name: 'Không bịa thông tin', weight: 25 }, { name: 'Hẹn chuyên viên sáng mai', weight: 20 }] },
  { name: 'Tư vấn khóa học (Education)', type: 'chat', channelScope: 'all', threshold: 7, criteria: [{ name: 'Hiểu mô hình KD của khách', weight: 25 }, { name: 'Map đúng khóa phù hợp', weight: 30 }, { name: 'Trình bày lộ trình học', weight: 25 }, { name: 'Học phí & ưu đãi rõ ràng', weight: 20 }] },
  { name: 'Chốt deal / Đàm phán', type: 'chat', channelScope: 'all', threshold: 7.5, criteria: [{ name: 'Tạo tính cấp thiết (urgency)', weight: 20 }, { name: 'Xử lý phản đối', weight: 30 }, { name: 'Ưu đãi đúng thời điểm', weight: 20 }, { name: 'Chốt rõ ràng (CTA)', weight: 30 }] },
  { name: 'Chăm sóc sau ghi danh (Onboarding)', type: 'chat', channelScope: 'all', threshold: 7, criteria: [{ name: 'Xác nhận lịch học', weight: 25 }, { name: 'Hướng dẫn thủ tục', weight: 25 }, { name: 'Giải đáp thắc mắc', weight: 25 }, { name: 'Thái độ tận tâm', weight: 25 }] },
  { name: 'Xử lý khiếu nại', type: 'chat', channelScope: 'all', threshold: 7.5, criteria: [{ name: 'Lắng nghe & xin lỗi', weight: 25 }, { name: 'Xác nhận đúng vấn đề', weight: 20 }, { name: 'Đưa giải pháp', weight: 30 }, { name: 'Cam kết theo dõi', weight: 15 }, { name: 'Giữ thái độ bình tĩnh', weight: 10 }] },
  { name: 'Re-engage lead nguội', type: 'chat', channelScope: 'all', threshold: 6.5, criteria: [{ name: 'Mở đầu cá nhân hóa', weight: 25 }, { name: 'Lý do nên quay lại', weight: 25 }, { name: 'Ưu đãi hấp dẫn', weight: 25 }, { name: 'CTA đặt lịch', weight: 25 }] },
  { name: 'Chuẩn Zalo OA', type: 'chat', channelScope: 'zalo', threshold: 7, criteria: [{ name: 'Phản hồi nhanh', weight: 25 }, { name: 'Dùng đúng ZNS template', weight: 20 }, { name: 'Tư vấn đúng nhu cầu', weight: 35 }, { name: 'Chốt CTA', weight: 20 }] },
  { name: 'Facebook comment → inbox', type: 'chat', channelScope: 'fb', threshold: 6.5, criteria: [{ name: 'Rep comment lịch sự', weight: 20 }, { name: 'Kéo về inbox', weight: 40 }, { name: 'Tư vấn trong inbox', weight: 25 }, { name: 'Chốt CTA', weight: 15 }] },
  { name: 'Telesale (Call QC)', type: 'call', channelScope: 'all', threshold: 7, criteria: [{ name: 'Mở đầu chuyên nghiệp', weight: 15 }, { name: 'Khai thác nhu cầu', weight: 30 }, { name: 'Trình bày giá trị', weight: 25 }, { name: 'Chốt lịch hẹn', weight: 30 }] },
];

function RulesetEditor({ initial, onClose, onSaved }) {
  const isNew = !initial.id;
  const [name, setName] = useState(initial.name || '');
  const [channelScope, setCh] = useState(initial.channelScope || 'all');
  const [type, setType] = useState(initial.type || 'chat');
  const [threshold, setTh] = useState(String(initial.threshold != null ? initial.threshold : 7));
  const [crit, setCrit] = useState((initial.criteria && initial.criteria.length ? initial.criteria : [{ name: '', weight: 0 }]).map(c => ({ ...c })));
  const [busy, setBusy] = useState(false);
  const sumW = crit.reduce((s, c) => s + (parseInt(c.weight, 10) || 0), 0);
  const setC = (i, k, v) => setCrit(cs => cs.map((c, j) => j === i ? { ...c, [k]: v } : c));
  const save = async () => {
    if (!name.trim() || busy) return;
    setBusy(true);
    const payload = {
      id: initial.id || ('qc_' + Date.now()), name: name.trim(), channelScope, type,
      threshold: parseFloat(threshold) || 7,
      criteria: crit.filter(c => c.name.trim()).map(c => ({ name: c.name.trim(), weight: parseInt(c.weight, 10) || 0 })),
      model: initial.model || 'Claude',
    };
    try {
      if (window.API && window.API.enabled) {
        if (isNew) await window.API.qcCreateRuleset(payload); else await window.API.qcUpdateRuleset(payload.id, payload);
      }
      onSaved(payload, isNew);
      onClose();
    } catch (e) { window.alert('Lưu lỗi: ' + (e && e.message || e)); }
    finally { setBusy(false); }
  };
  return (
    <Modal title={isNew ? 'Tạo Ruleset' : 'Sửa Ruleset'} width={560} onClose={onClose}
      footer={<><Button onClick={onClose}>Hủy</Button><Button variant="primary" icon="check" onClick={save} disabled={busy || !name.trim()}>{busy ? 'Đang lưu…' : 'Lưu'}</Button></>}>
      <Field label="Tên ruleset"><Input value={name} onChange={setName} placeholder="VD: Chuẩn chat ngoài giờ" autoFocus /></Field>
      <div className="grid gc2 g16">
        <Field label="Kênh áp dụng"><Select value={channelScope} onChange={setCh} options={[{ value: 'all', label: 'Tất cả kênh' }, { value: 'fb', label: 'Messenger' }, { value: 'zalo', label: 'Zalo OA' }, { value: 'instagram', label: 'Instagram' }, { value: 'tiktok', label: 'TikTok' }]} /></Field>
        <Field label="Ngưỡng PASS"><Input value={threshold} onChange={setTh} /></Field>
      </div>
      <Field label="Loại"><Select value={type} onChange={setType} options={[{ value: 'chat', label: 'Chat' }, { value: 'call', label: 'Cuộc gọi' }]} /></Field>
      <Field label={'Tiêu chí (tên · trọng số) — tổng ' + sumW + '%' + (sumW !== 100 ? ' ⚠ nên = 100' : ' ✓')}>
        <div className="col g8">
          {crit.map((c, i) => (
            <div key={i} className="row g8 aic">
              <Input value={c.name} onChange={v => setC(i, 'name', v)} placeholder="Tên tiêu chí" />
              <Input value={String(c.weight)} onChange={v => setC(i, 'weight', v)} placeholder="%" style={{ width: 70 }} />
              <button className="iconbtn" title="Xóa" onClick={() => setCrit(cs => cs.filter((_, j) => j !== i))} style={{ width: 30, height: 30, flexShrink: 0 }}><Icon name="trash" size={14} /></button>
            </div>
          ))}
          <Button size="sm" icon="plus" variant="plain" onClick={() => setCrit(cs => [...cs, { name: '', weight: 0 }])}>Thêm tiêu chí</Button>
        </div>
      </Field>
    </Modal>
  );
}

function QCRulesets() {
  const live = !!(window.API && window.API.enabled);
  const [list, setList] = useState(() => (AAU.qcRulesets || []).map(r => ({ ...r })));
  const [editing, setEditing] = useState(null);
  useEffect(() => { if (live && window.API.qcRulesets) window.API.qcRulesets().then(d => { if (Array.isArray(d)) setList(d); }).catch(() => { }); }, [live]);
  const reload = () => { if (live && window.API.qcRulesets) window.API.qcRulesets().then(d => { if (Array.isArray(d)) { setList(d); if (window.AAU) { AAU.qcRulesets.length = 0; d.forEach(x => AAU.qcRulesets.push(x)); } } }).catch(() => { }); };
  const onSaved = () => reload();
  const del = r => { if (!window.confirm('Xóa ruleset "' + r.name + '"?')) return; if (live && window.API.qcDeleteRuleset) window.API.qcDeleteRuleset(r.id).then(reload).catch(() => { }); else setList(l => l.filter(x => x.id !== r.id)); };
  return (
    <div className="page wide">
      <PageHead title="QC Rulesets" subtitle="Bộ tiêu chí chấm chất lượng chat/call — tạo, sửa, hoặc dùng mẫu có sẵn"
        actions={<Button variant="primary" icon="plus" onClick={() => setEditing({})}>Tạo ruleset</Button>} />

      <Card className="mb16" title="Mẫu có sẵn (10)" subtitle="Bấm để tạo nhanh từ mẫu — chỉnh lại trước khi lưu">
        <div className="row g8 wrap">
          {QC_TEMPLATES.map((t, i) => (
            <button key={i} className="tag" style={{ cursor: 'pointer', padding: '6px 11px' }} onClick={() => setEditing({ ...t })}>
              <Icon name="plus" size={12} /> {t.name} <span className="subtle">· {t.criteria.length} tiêu chí{t.type === 'call' ? ' · call' : ''}</span>
            </button>
          ))}
        </div>
      </Card>

      <div className="grid gc2">
        {list.map(r => (
          <Card key={r.id} title={r.name} subtitle={(r.type === 'call' ? 'Cuộc gọi' : 'Chat') + (r.channelScope && r.channelScope !== 'all' ? ' · ' + r.channelScope : ' · đa kênh') + ' · ' + (r.model || 'Claude')}
            actions={<Badge tone={r.type === 'call' ? 'warning' : 'info'}>{r.type || 'chat'}</Badge>}>
            <div className="grid gc4 mb16">
              <div><div className="t11 subtle">Đã chấm</div><div className="t17 fw7">{r.analyzed || 0}</div></div>
              <div><div className="t11 subtle">Điểm TB</div><div className="t17 fw7">{r.avg || '—'}</div></div>
              <div><div className="t11 subtle">Ngưỡng</div><div className="t17 fw7">{r.threshold != null ? r.threshold : 7}</div></div>
              <div><div className="t11 subtle">Pass rate</div><div className="t17 fw7">{r.analyzed ? Math.round((r.pass || 0) / r.analyzed * 100) + '%' : '—'}</div></div>
            </div>
            <div className="t11 fw7 subtle mb8">TIÊU CHÍ CHẤM</div>
            <div className="col g6">{(r.criteria || []).map((c, i) => <div key={i} className="row jcsb aic t12"><span>{c.name}</span><span className="tag">{c.weight}%</span></div>)}</div>
            <div className="row g6 mt12"><Button size="sm" icon="edit" onClick={() => setEditing({ ...r })}>Sửa</Button>{Perm.canDelete() && <Button size="sm" variant="plain" icon="trash" onClick={() => del(r)}>Xóa</Button>}<Button size="sm" variant="plain" onClick={() => navigate('/qc/dashboard')}>Dashboard</Button></div>
          </Card>
        ))}
      </div>
      {editing && <RulesetEditor initial={editing} onClose={() => setEditing(null)} onSaved={onSaved} />}
    </div>
  );
}

function QCDashboard() {
  const live = !!(window.API && window.API.enabled);
  const [from, setFrom] = useState('');
  const [to, setTo] = useState('');
  const [ch, setCh] = useState('all');
  const [rep, setRep] = useState(null);
  const [loading, setLoading] = useState(false);
  useEffect(() => {
    if (!live || !window.API.qcScan) return;
    const qs = [];
    if (from) qs.push('from=' + from);
    if (to) qs.push('to=' + to);
    if (ch !== 'all') qs.push('channel=' + ch);
    setLoading(true);
    window.API.qcScan(qs.join('&')).then(d => { setRep(d); setLoading(false); }).catch(() => setLoading(false));
  }, [live, from, to, ch]);

  const sum = rep && rep.summary, bd = rep && rep.breakdown;
  const sc = v => v >= 8 ? '#0a9e6e' : v >= 7 ? '#b06a00' : '#c4320a';
  const distColor = { good: '#0a9e6e', ok: '#3b82f6', weak: '#f59e0b', bad: '#c4320a' };
  const distLabel = { good: 'Tốt (≥8)', ok: 'Đạt (7–8)', weak: 'Yếu (5–7)', bad: 'Kém (<5)' };
  const tot = (sum && sum.scanned) || 1;
  return (
    <div className="page wide">
      <PageHead title="QC Report" subtitle="Báo cáo chấm chất lượng hội thoại — lọc theo ngày/kênh, tổng hợp lỗi & gợi ý cải thiện"
        actions={<div className="row aic g8">
          <input type="date" className="input" value={from} onChange={e => setFrom(e.target.value)} style={{ height: 32, fontSize: 12.5 }} />
          <span className="subtle t12">→</span>
          <input type="date" className="input" value={to} onChange={e => setTo(e.target.value)} style={{ height: 32, fontSize: 12.5 }} />
          <Select value={ch} onChange={setCh} options={[{ value: 'all', label: 'Mọi kênh' }, { value: 'fb', label: 'Facebook' }, { value: 'zalo', label: 'Zalo' }, { value: 'instagram', label: 'Instagram' }, { value: 'tiktok', label: 'TikTok' }]} style={{ width: 140 }} />
          {rep && rep.engine && <span className="t12 subtle">Model: <b>{rep.engine.model}</b> · {rep.engine.mode === 'ai' ? 'AI' : 'rule'} · <span className="linkish" onClick={() => navigate('/system/ai-settings')}>Đổi</span></span>}
        </div>} />
      {!live && <EmptyState icon="chart" title="Cần chế độ LIVE" desc="Mở app qua backend để xem báo cáo QC thật." />}
      {live && (
        <>
          <div className="grid gc4 mb16">
            <KPI label="Đã chấm" value={sum ? AAU.fmtNum(sum.scanned) : '…'} sub={(from || to) ? 'theo kỳ chọn' : 'tất cả'} icon="checkCircle" />
            <KPI label="Điểm TB" value={sum ? sum.avgScore.toFixed(1) : '…'} sub="thang 10" icon="chart" />
            <KPI label="Tỷ lệ PASS" value={sum ? Math.round(sum.passRate) + '%' : '…'} sub={sum ? sum.pass + '/' + sum.scanned : ''} icon="target" />
            <KPI label="Nghiêm trọng" value={sum ? AAU.fmtNum(sum.severe) : '…'} sub="khách hỏi giá chưa đáp" icon="alert" />
          </div>
          {bd && (
            <>
              <div className="grid mb16" style={{ gridTemplateColumns: '1fr 1fr' }}>
                <Card title="Điểm theo tiêu chí" subtitle="Điểm thấp / % yếu cao = kỹ năng cần đào tạo">
                  {bd.criteria.map((c, i) => (
                    <div key={i} style={{ marginBottom: 11 }}>
                      <div className="row jcsb t12"><span>{c.name} <span className="subtle">· {c.weight}%</span></span><span className="fw6" style={{ color: sc(c.avg) }}>{c.avg.toFixed(1)}/10 · yếu {Math.round(c.weakPct)}%</span></div>
                      <div style={{ height: 8, borderRadius: 5, background: 'var(--p-bg-surface-tertiary)', marginTop: 3, overflow: 'hidden' }}><div style={{ width: (c.avg * 10) + '%', height: '100%', background: sc(c.avg) }} /></div>
                    </div>
                  ))}
                </Card>
                <Card title="Phân phối điểm">
                  <div className="col g12">
                    {['good', 'ok', 'weak', 'bad'].map(k => { const v = bd.scoreDist[k] || 0; return (
                      <div key={k}><div className="row jcsb t12 mb4"><span>{distLabel[k]}</span><span className="fw6">{v} · {Math.round(v / tot * 100)}%</span></div><Progress value={v} max={tot} color={distColor[k]} /></div>
                    ); })}
                  </div>
                </Card>
              </div>
              <div className="grid mb16" style={{ gridTemplateColumns: '1fr 1fr' }}>
                <Card title="Tổng hợp lỗi" subtitle="Nhiều → ít">
                  <table className="tbl"><thead><tr><th>Lỗi</th><th className="num">Số ca</th><th className="num">%</th></tr></thead>
                    <tbody>
                      {(bd.issues || []).map((it, i) => <tr key={i}><td>{it.label}</td><td className="num fw6">{it.count}</td><td className="num">{Math.round(it.pct)}%</td></tr>)}
                      {!(bd.issues || []).length && <tr><td colSpan={3} className="muted t12" style={{ padding: 14 }}>Không có lỗi nổi bật 🎉</td></tr>}
                    </tbody></table>
                </Card>
                <Card title="Gợi ý cải thiện" subtitle="Ưu tiên theo tần suất lỗi">
                  <div className="col g10">
                    {(bd.recommendations || []).map((rc, i) => (
                      <div key={i} className="row g8" style={{ alignItems: 'flex-start', padding: 11, borderRadius: 10, background: 'var(--p-magic-bg)' }}>
                        <Icon name="sparkles" size={15} color="#573b8a" style={{ flexShrink: 0, marginTop: 2 }} />
                        <div><div className="t13 fw6">{rc.issue} <span className="subtle">· {rc.count} ca</span></div><div className="t12 muted mt2">{rc.advice}</div></div>
                      </div>
                    ))}
                    {!(bd.recommendations || []).length && <div className="muted t12">Chất lượng ổn — chưa cần cải thiện gấp.</div>}
                  </div>
                </Card>
              </div>
              <Card title="Hội thoại cần xem (điểm thấp / nghiêm trọng)">
                <table className="tbl"><thead><tr><th>Khách</th><th>Kênh</th><th className="num">Điểm</th><th>Verdict</th><th>Vấn đề</th></tr></thead>
                  <tbody>{(rep.items || []).slice(0, 12).map(it => (
                    <tr key={it.id}><td className="fw6">{it.name}{it.sev && <span className="badge critical" style={{ fontSize: 9, marginLeft: 6 }}>NGHIÊM TRỌNG</span>}</td><td className="t12">{it.ch}</td><td className="num fw7" style={{ color: sc(it.score) }}>{it.score.toFixed(1)}</td><td><Badge tone={it.verdict === 'pass' ? 'success' : 'critical'}>{it.verdict.toUpperCase()}</Badge></td><td className="muted t12">{it.summary}</td></tr>
                  ))}</tbody></table>
              </Card>
            </>
          )}
          {!bd && <div className="muted t13" style={{ padding: 20 }}>{loading ? 'Đang quét & chấm hội thoại…' : 'Chưa có dữ liệu.'}</div>}
        </>
      )}
    </div>
  );
}

function QCReports() {
  const rows = [
    { date: '2026-06-01', count: 42, pass: 78, avg: 7.8, top: 'Thiếu CTA', leader: 'Phạm Tuấn' },
    { date: '2026-05-31', count: 38, pass: 74, avg: 7.5, top: 'Báo giá sớm', leader: 'Lê Vy' },
    { date: '2026-05-30', count: 45, pass: 80, avg: 8.0, top: 'Chính tả', leader: 'Phạm Tuấn' },
  ];
  return (
    <div className="page wide">
      <PageHead title="QC Daily Report" subtitle="Snapshot chất lượng cuối ngày · có cơ chế kháng nghị điểm"
        actions={<Input icon="calendar" value="Tháng 6/2026" onChange={() => {}} style={{ width: 160 }} />} />
      <Card title="Báo cáo theo ngày">
        <table className="tbl"><thead><tr><th>Ngày</th><th className="num">Số chấm</th><th className="num">Pass rate</th><th className="num">Điểm TB</th><th>Top vi phạm</th><th>Sale tốt nhất</th><th></th></tr></thead>
          <tbody>{rows.map((r, i) => <tr key={i}><td>{AAU.fmtDate(r.date)}</td><td className="num">{r.count}</td><td className="num fw6">{r.pass}%</td><td className="num">{r.avg}</td><td className="muted">{r.top}</td><td>{r.leader}</td><td><Button size="sm" variant="plain">Kháng nghị</Button></td></tr>)}</tbody></table>
      </Card>
    </div>
  );
}

const ATTR_PATH_TAB = { '/analytics/funnel': 'funnel', '/marketing/attribution': 'models', '/analytics/attribution': 'forecast' };
const ATTR_TAB_PATH = { funnel: '/analytics/funnel', models: '/marketing/attribution', forecast: '/analytics/attribution' };

function AttributionHub() {
  const path = (location.hash || '#/analytics/funnel').slice(1);
  const tab = ATTR_PATH_TAB[path] || 'funnel';
  const tabs = [
    { value: 'funnel', label: 'Đối soát phễu' },
    { value: 'models', label: 'Mô hình attribution' },
    { value: 'forecast', label: 'ROAS & Dự báo' },
  ];
  const subtitle = {
    funnel: 'Phễu end-to-end Spend→Won & đối soát: marketing báo bao nhiêu lead vs CRM ghi nhận chất lượng thật',
    models: 'Cùng tập lead — công chuyển đổi đổi theo mô hình: first-touch · last-touch · tuyến tính',
    forecast: 'ROAS & CAC theo campaign (last-touch) · dự báo doanh thu theo xác suất',
  }[tab];
  return (
    <div className="page wide">
      <PageHead title="Attribution & Đối soát MKT↔Sales" subtitle={subtitle}
        actions={<Button icon="download" onClick={() => window.print()}>Xuất báo cáo</Button>} />
      <div className="mb16"><Tabs tabs={tabs} value={tab} onChange={v => navigate(ATTR_TAB_PATH[v])} /></div>
      {tab === 'funnel' && <FunnelReconcileBody />}
      {tab === 'models' && <AttributionModelsBody />}
      {tab === 'forecast' && <RoasForecastBody />}
    </div>
  );
}

function FunnelReconcileBody() {
  const T = AAU.totals;
  const steps = [
    { l: 'Spend', v: T.spend, disp: AAU.fmtVNDm(T.spend), color: '#0084ff' },
    { l: 'Messages', v: T.messages, disp: AAU.fmtNum(T.messages), color: '#3b82f6' },
    { l: 'Lead', v: T.leadsCount, disp: AAU.fmtNum(T.leadsCount), color: '#8b5cf6' },
    { l: 'Qualified', v: T.qualified, disp: AAU.fmtNum(T.qualified), color: '#f59e0b' },
    { l: 'Won', v: T.won, disp: AAU.fmtNum(T.won), color: '#10b981' },
    { l: 'Doanh thu', v: T.won, disp: AAU.fmtVNDm(T.revenue), color: '#0a9e6e' },
  ];
  const max = T.messages;
  return (
    <>
      <Card title="Phễu end-to-end" className="mb16">
        <div className="col g10">{steps.map((s, i) => { const pct = i === 0 ? 100 : Math.round(s.v / (steps[1].v) * 100); const conv = i > 0 ? Math.round(steps[i].v / steps[i - 1].v * 100) : null; return (
          <div key={i}><div className="row jcsb t12 mb4"><span className="fw6">{s.l}</span><span className="muted">{s.disp}{conv != null && i > 1 && <span className="subtle"> · {conv}% từ bước trước</span>}</span></div>
          <div style={{ height: 28, borderRadius: 7, background: '#f1f1f1' }}><div style={{ width: Math.max(8, (i === 0 ? 100 : s.v / max * 100)) + '%', height: '100%', background: s.color, borderRadius: 7 }} /></div></div>
        ); })}</div>
      </Card>
      <div className="grid gc2">
        <Card title="Đối soát Marketing vs CRM">
          <table className="tbl"><thead><tr><th>Chỉ số</th><th className="num">MKT báo</th><th className="num">CRM ghi</th><th className="num">Chênh</th></tr></thead>
            <tbody>
              <tr><td>Lead</td><td className="num">324</td><td className="num">286</td><td className="num sla-bad">−38</td></tr>
              <tr><td>Qualified</td><td className="num">—</td><td className="num">142</td><td className="num">—</td></tr>
              <tr><td>Won</td><td className="num">—</td><td className="num">22</td><td className="num">—</td></tr>
            </tbody></table>
        </Card>
        <Card title="Điểm rò rỉ">
          <div className="col g10">
            <div className="row g8" style={{ padding: 12, borderRadius: 10, background: 'var(--p-critical-bg)' }}><Icon name="alert" size={18} color="#8e1f0b" /><div className="t13"><b>38 lead về không ai chăm.</b> Chưa gán phụ trách trong 24h → mất. Bật automation SLA.</div></div>
            <div className="row g8" style={{ padding: 12, borderRadius: 10, background: 'var(--p-warning-bg)' }}><Icon name="refresh" size={18} color="#5e4200" /><div className="t13"><b>Creative TikTok hút sai tệp.</b> Lead nhiều nhưng qualify thấp → review targeting.</div></div>
            <div className="row g8 mt2"><Button size="sm" variant="plain" icon="chart" onClick={() => navigate('/marketing/sources')}>Phân tích nguồn chi tiết</Button><Button size="sm" variant="plain" icon="kanban" onClick={() => navigate('/leads/kanban')}>Mở pipeline</Button></div>
          </div>
        </Card>
      </div>
    </>
  );
}

function RoasForecastBody() {
  const rows = AAU.campaigns.map(c => { const price = AAU.courseById(c.course)?.price || 12000000; return ({ ...c, course: AAU.courseById(c.course)?.name, rev: c.won * price, roas: c.won * price / c.spend, cac: c.spend / c.won }); });
  const forecast = [
    { close: 'Tuần này', value: 33800000, prob: 0.7 }, { close: 'Tuần tới', value: 48700000, prob: 0.5 }, { close: 'Th6', value: 96000000, prob: 0.35 },
  ];
  const expected = forecast.reduce((s, f) => s + f.value * f.prob, 0);
  return (
    <>
      <Card title="Attribution theo campaign" className="mb16">
        <table className="tbl"><thead><tr><th>Campaign</th><th>Khóa</th><th className="num">Spend</th><th className="num">Lead</th><th className="num">Won</th><th className="num">Doanh thu</th><th className="num">ROAS</th><th className="num">CAC</th></tr></thead>
          <tbody>{rows.map(c => <tr key={c.id}><td className="fw6">{c.name}</td><td className="muted t12">{c.course}</td><td className="num">{AAU.fmtVNDm(c.spend)}</td><td className="num">{c.leads}</td><td className="num">{c.won}</td><td className="num fw6">{AAU.fmtVNDm(c.rev)}</td><td className="num fw6" style={{ color: c.roas >= 2 ? '#0e7c4a' : '#c4320a' }}>{c.roas.toFixed(1)}×</td><td className="num">{AAU.fmtVND(c.cac)}</td></tr>)}</tbody></table>
      </Card>
      <div className="grid gc2">
        <Card title="Dự báo doanh thu" subtitle="Σ(deal value × xác suất)">
          <div className="col g10">{forecast.map((f, i) => <div key={i} className="row jcsb aic"><span className="t13">{f.close} <span className="subtle">· xác suất {f.prob * 100}%</span></span><span className="fw6 tnum">{AAU.fmtVNDm(f.value)}</span></div>)}
            <div className="divider mt8 mb8" /><div className="row jcsb aic"><span className="t13 fw7">Dự báo kỳ vọng</span><span className="t17 fw7 sla-ok">{AAU.fmtVNDm(expected)}</span></div></div>
        </Card>
        <Card title="Cohort theo nguồn" subtitle="Won-rate theo tháng vào">
          <table className="tbl"><thead><tr><th>Cohort</th><th className="num">Lead</th><th className="num">Won M+1</th><th className="num">Won M+2</th></tr></thead>
            <tbody><tr><td>T4 · Paid</td><td className="num">86</td><td className="num">7%</td><td className="num">12%</td></tr><tr><td>T4 · Organic</td><td className="num">42</td><td className="num">10%</td><td className="num">16%</td></tr><tr><td>T5 · Paid</td><td className="num">98</td><td className="num">6%</td><td className="num">—</td></tr></tbody></table>
        </Card>
      </div>
    </>
  );
}

const ROLE_TONE = { admin: 'magic', manager: 'info', sales: 'success', mkt: 'info', finance: 'warning', qc: 'neutral' };
const ACCESS_LABEL = { view: 'Chỉ xem', edit: 'Chỉnh sửa', manage: 'Quản trị' };
const roleLabel = id => (AAU.roles.find(r => r.id === id) || {}).label || id;

const apiLive = () => !!(window.API && window.API.enabled);

function UserManagement() {
  const [list, setList] = useState(() => (AAU.users || []).map(u => ({ ...u })));
  const [q, setQ] = useState('');
  const [roleFilter, setRoleFilter] = useState('all');
  const [modal, setModal] = useState(null);   // null | 'add' | userObj (edit)
  const [invite, setInvite] = useState(null); // { link, emailed, email, emailError } after create/invite
  const [confirmDel, setConfirmDel] = useState(null); // user pending delete confirmation
  const [err, setErr] = useState('');
  const [busy, setBusy] = useState(false);

  // LIVE: load the authoritative list from the backend. MOCK: use AAU.users.
  useEffect(() => {
    if (!apiLive()) return;
    let alive = true;
    window.API.listUsers().then(us => { if (alive && Array.isArray(us)) setList(us); }).catch(() => { });
    return () => { alive = false; };
  }, []);

  const filtered = list.filter(u =>
    (roleFilter === 'all' || u.role === roleFilter) &&
    (!q || (u.name + ' ' + (u.email || '') + ' ' + (u.title || '')).toLowerCase().includes(q.toLowerCase())));

  const active = list.filter(u => u.active).length;
  const roleOpts = [{ value: 'all', label: 'Tất cả vai trò' }, ...AAU.roles.map(r => ({ value: r.id, label: r.label + ' (' + list.filter(u => u.role === r.id).length + ')' }))];
  const scopeText = u => u.buScope === 'all' ? 'Toàn bộ khóa' : (Array.isArray(u.buScope) ? u.buScope.length + ' khóa cụ thể' : '—');
  const localInit = name => (name || '?').split(' ').slice(-2).map(w => w[0]).join('').toUpperCase().slice(0, 2);

  const saveUser = async (data, doInvite, newPassword) => {
    setErr(''); setBusy(true);
    try {
      if (data.id) { // edit
        if (apiLive()) {
          const saved = await window.API.updateUser(data.id, data);
          if (newPassword) await window.API.setUserPassword(data.id, newPassword);
          setList(ls => ls.map(u => u.id === data.id ? { ...u, ...saved, ...(newPassword ? { invited: false } : {}) } : u));
        } else {
          setList(ls => ls.map(u => u.id === data.id ? { ...u, ...data } : u));
        }
        setModal(null);
      } else { // create
        if (apiLive()) {
          const res = await window.API.createUser({ ...data, invite: doInvite });
          setList(ls => [res.user, ...ls]);
          setModal(null);
          if (doInvite && res.activationLink) setInvite({ link: res.activationLink, emailed: res.emailed, email: res.user.email, emailError: res.emailError });
        } else {
          const colors = ['#5b6cff', '#0a9e6e', '#d62976', '#d97706', '#7c3aed', '#0084ff'];
          setList(ls => [{ ...data, id: 'u' + Date.now(), avatar: localInit(data.name), color: colors[ls.length % colors.length], active: true, invited: true }, ...ls]);
          setModal(null);
        }
      }
    } catch (ex) { setErr(ex.message || 'Lưu thất bại.'); }
    setBusy(false);
  };

  const toggleActive = async u => {
    setErr('');
    const next = !u.active;
    if (apiLive()) {
      try { await window.API.setUserActive(u.id, next); } catch (ex) { setErr(ex.message); return; }
    }
    setList(ls => ls.map(x => x.id === u.id ? { ...x, active: next } : x));
  };

  // removeUser deletes u, first transferring everything they own to transferTo
  // (required when they own data — enforced by the modal and the backend).
  const removeUser = async (u, transferTo) => {
    setErr(''); setBusy(true);
    if (apiLive()) {
      try { await window.API.deleteUser(u.id, transferTo); } catch (ex) { setErr(ex.message); setBusy(false); return; }
    }
    setList(ls => ls.filter(x => x.id !== u.id));
    setBusy(false);
    setConfirmDel(null);
  };

  const resendInvite = async u => {
    setErr('');
    if (!apiLive()) { setErr('Cần chế độ LIVE (backend) để tạo link kích hoạt.'); return; }
    try {
      const res = await window.API.inviteUser(u.id);
      setInvite({ link: res.activationLink, emailed: res.emailed, email: res.email, emailError: res.emailError });
    } catch (ex) { setErr(ex.message); }
  };

  return (
    <div className="page wide">
      <PageHead title="Quản lý người dùng" subtitle="Thêm, mời & phân vai trò/phạm vi cho nhân sự. Người được mời tự đặt mật khẩu qua link kích hoạt."
        actions={Perm.can('system', 'create') && <Button variant="primary" icon="plus" onClick={() => setModal('add')}>Thêm người dùng</Button>} />

      {err && <div className="t12" style={{ color: '#b91c1c', background: '#fef2f2', border: '1px solid #fecaca', borderRadius: 8, padding: '8px 12px', marginBottom: 12 }}>{err}</div>}

      <div className="grid gc4 mb16">
        <KPI label="Tổng người dùng" value={list.length} icon="users" />
        <KPI label="Đang hoạt động" value={active} sub={list.length ? Math.round(active / list.length * 100) + '%' : '0%'} icon="checkCircle" />
        <KPI label="Tạm khóa" value={list.length - active} icon="alert" />
        <KPI label="Số vai trò" value={AAU.roles.length} sub="cấu hình ở RBAC" icon="shield" />
      </div>

      <Card pad={false} title="Danh sách người dùng"
        actions={<div className="row g8 aic">
          <Input icon="search" value={q} onChange={setQ} placeholder="Tìm tên, email…" style={{ width: 200 }} />
          <Select value={roleFilter} onChange={setRoleFilter} options={roleOpts} style={{ width: 180 }} />
        </div>}>
        <table className="tbl">
          <thead><tr><th>Người dùng</th><th>Vai trò</th><th>Chức danh</th><th>Phạm vi BU</th><th>Quyền</th><th>Trạng thái</th><th className="num"></th></tr></thead>
          <tbody>
            {filtered.map(u => (
              <tr key={u.id} style={{ opacity: u.active ? 1 : 0.55 }}>
                <td>
                  <div className="row aic g10">
                    <Avatar name={u.name} color={u.color} size={32} />
                    <div><div className="t13 fw6">{u.name}</div><div className="t11 subtle">{u.email}</div></div>
                  </div>
                </td>
                <td><div className="row g4 wrap">{((u.roles && u.roles.length ? u.roles : [u.role]).filter(Boolean)).map(rid => <Badge key={rid} tone={ROLE_TONE[rid] || 'neutral'}>{roleLabel(rid)}</Badge>)}</div></td>
                <td className="t12 muted">{u.title}</td>
                <td className="t12">{scopeText(u)}</td>
                <td><span className="tag">{ACCESS_LABEL[u.access] || u.access}</span></td>
                <td>
                  {u.invited ? <Badge tone="warning" dot>Chờ kích hoạt</Badge> : (u.active ? <Badge tone="success" dot>Hoạt động</Badge> : <Badge tone="neutral">Tạm khóa</Badge>)}
                </td>
                <td className="num">
                  <div className="row g4 jce aic">
                    {Perm.can('system', 'edit') && u.invited && <Button size="sm" variant="plain" icon="mail" onClick={() => resendInvite(u)}>Lấy link</Button>}
                    {Perm.can('system', 'edit') && !u.invited && (u.active
                      ? <Button size="sm" variant="plain" icon="lock" onClick={() => toggleActive(u)}>Tạm khóa</Button>
                      : <Button size="sm" variant="plain" icon="checkCircle" onClick={() => toggleActive(u)}>Mở khóa</Button>)}
                    {Perm.can('system', 'edit') && <Button size="sm" variant="plain" icon="edit" onClick={() => setModal(u)}>Sửa</Button>}
                    {Perm.canDelete() && <Button size="sm" variant="plain" icon="trash" onClick={() => setConfirmDel(u)}>Xóa</Button>}
                    {!Perm.can('system', 'edit') && <span className="t11 subtle">Chỉ xem</span>}
                  </div>
                </td>
              </tr>
            ))}
            {filtered.length === 0 && <tr><td colSpan={7}><div className="t12 muted" style={{ padding: 24, textAlign: 'center' }}>Không tìm thấy người dùng phù hợp.</div></td></tr>}
          </tbody>
        </table>
      </Card>

      {modal && <UserForm user={modal === 'add' ? null : modal} busy={busy} onClose={() => setModal(null)} onSave={saveUser} onResetLink={u => { setModal(null); resendInvite(u); }} />}
      {invite && <InviteResultModal info={invite} onClose={() => setInvite(null)} />}
      {confirmDel && (
        <DeleteUserModal user={confirmDel} users={list} busy={busy}
          onClose={() => !busy && setConfirmDel(null)}
          onConfirm={transferTo => removeUser(confirmDel, transferTo)} />
      )}
    </div>
  );
}

// DeleteUserModal — Larksuite-style offboarding. Before a user is deleted, any
// data they currently own (leads, course groups) MUST be handed to another
// active user so nothing is orphaned or stuck on a departed person's name.
// History (who sent which message) is left untouched.
function DeleteUserModal({ user, users, busy, onClose, onConfirm }) {
  const [owned, setOwned] = useState(null);  // {counts,total} | null=loading
  const [target, setTarget] = useState('');

  // Recipient candidates: active users other than the one being deleted.
  const candidates = (users || []).filter(u => u.id !== user.id && u.active && !u.invited);
  const isSuper = u => u.role === 'superadmin' || u.salesRole === 'superadmin';

  useEffect(() => {
    // Default the recipient to a Super Admin, else an admin, else first candidate.
    const def = candidates.find(isSuper) || candidates.find(u => u.role === 'admin' || u.salesRole === 'admin') || candidates[0];
    setTarget(def ? def.id : '');
    let alive = true;
    if (apiLive()) {
      window.API.userOwned(user.id)
        .then(r => { if (alive) setOwned({ counts: r.counts || {}, total: r.total || 0 }); })
        .catch(() => { if (alive) setOwned({ counts: {}, total: 0 }); });
    } else {
      // MOCK: count from window.AAU so the dialog still demonstrates the flow.
      const leads = (AAU.leads || []).filter(l => l.assignedTo === user.id).length;
      const cg = Object.values(AAU.courseGroupOwner || {}).filter(v => v === user.id).length;
      const counts = {}; if (leads) counts.leads = leads; if (cg) counts.courseGroups = cg;
      setOwned({ counts, total: leads + cg });
    }
    return () => { alive = false; };
  }, [user.id]);

  const loading = owned === null;
  const total = owned ? owned.total : 0;
  const needTransfer = total > 0;
  const targetUser = candidates.find(u => u.id === target);
  const canDelete = !loading && !busy && (!needTransfer || !!targetUser);

  const ownLabel = c => {
    const parts = [];
    if (c.leads) parts.push(c.leads + ' lead');
    if (c.courseGroups) parts.push(c.courseGroups + ' nhóm khóa');
    return parts.join(' · ');
  };

  return (
    <Modal title="Xác nhận xóa người dùng" width={480} onClose={onClose}
      footer={<div className="row g8 jce">
        <Button variant="plain" disabled={busy} onClick={onClose}>Hủy</Button>
        <Button variant="critical" icon="trash" disabled={!canDelete}
          onClick={() => onConfirm(needTransfer ? target : undefined)}>
          {busy ? 'Đang xử lý…' : (needTransfer ? 'Chuyển giao & xóa' : 'Xóa người dùng')}
        </Button>
      </div>}>
      <div className="row g12" style={{ alignItems: 'flex-start' }}>
        <div style={{ width: 36, height: 36, borderRadius: 8, background: '#fef2f2', color: '#b91c1c', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}><Icon name="alert" size={20} /></div>
        <div className="t13" style={{ flex: 1 }}>
          <div>Bạn có chắc muốn xóa người dùng <b>{user.name}</b>{user.email ? <span className="subtle"> ({user.email})</span> : null}?</div>
          <div className="t12 subtle mt8">Hành động này <b>không thể hoàn tác</b>. Nếu chỉ muốn ngừng đăng nhập tạm thời, hãy dùng nút <b>Tạm khóa</b> thay vì xóa.</div>

          {loading && <div className="t12 muted mt12">Đang kiểm tra dữ liệu người này phụ trách…</div>}

          {!loading && needTransfer && (
            <div className="mt16" style={{ borderTop: '1px solid var(--p-border)', paddingTop: 12 }}>
              <div className="t12">Người này đang phụ trách <b>{ownLabel(owned.counts)}</b>. Phải <b>chuyển giao</b> cho người khác trước khi xóa (lịch sử tin nhắn/cuộc gọi vẫn giữ nguyên tên cũ).</div>
              <div className="mt12"><Field label="Chuyển toàn bộ cho">
                <Select value={target} onChange={setTarget}
                  options={candidates.map(u => ({ value: u.id, label: u.name + (isSuper(u) ? ' — Super Admin' : (u.title ? ' — ' + u.title : '')) }))} />
              </Field></div>
              {!candidates.length && <div className="t12" style={{ color: '#b91c1c' }}>Không có người nhận hợp lệ (cần ít nhất 1 người đang hoạt động). Hãy thêm/mở khóa một tài khoản trước.</div>}
            </div>
          )}

          {!loading && !needTransfer && (
            <div className="t12 muted mt12">Người này không phụ trách lead/nhóm khóa nào — xóa an toàn.</div>
          )}
        </div>
      </div>
    </Modal>
  );
}

function InviteResultModal({ info, onClose }) {
  const [copied, setCopied] = useState(false);
  const copy = () => { try { navigator.clipboard.writeText(info.link); setCopied(true); setTimeout(() => setCopied(false), 2000); } catch (e) { } };
  return (
    <Modal title="Mời người dùng" onClose={onClose} width={560}
      footer={<><Button onClick={onClose}>Đóng</Button><Button variant="primary" icon={copied ? 'check' : 'paperclip'} onClick={copy}>{copied ? 'Đã chép' : 'Chép link'}</Button></>}>
      <div className="col g14">
        {info.emailed
          ? <div className="row g8 aic t13" style={{ color: '#0a7d4f' }}><Icon name="checkCircle" size={16} /><span>Đã gửi email mời tới <b>{info.email}</b>. Nhắc họ kiểm tra cả hộp thư spam.</span></div>
          : <div className="row g8 aic t13" style={{ color: '#a15c00' }}><Icon name="alert" size={16} /><span>{info.emailError ? ('Gửi email thất bại: ' + info.emailError + '. ') : 'Email chưa được cấu hình. '}Hãy <b>gửi link bên dưới</b> cho người dùng (Zalo/email tay).</span></div>}
        <Field label={'Link kích hoạt cho ' + info.email}>
          <div className="row g8 aic">
            <Input value={info.link} onChange={() => { }} readOnly style={{ flex: 1, fontFamily: 'monospace', fontSize: 12 }} />
            <Button icon={copied ? 'check' : 'paperclip'} onClick={copy}>{copied ? 'Đã chép' : 'Chép'}</Button>
          </div>
        </Field>
        <div className="t11 subtle">Người nhận mở link → đặt mật khẩu → tự đăng nhập. Link có hạn 7 ngày; hết hạn thì bấm “Lấy link” để tạo lại.</div>
      </div>
    </Modal>
  );
}

function UserForm({ user, onClose, onSave, onResetLink, busy }) {
  const [f, setF] = useState(user || { name: '', email: '', role: 'sales', salesRole: 'member', title: '', buScope: 'all', access: 'edit' });
  const [scopeKind, setScopeKind] = useState(user ? (user.buScope === 'all' ? 'all' : 'bu') : 'all');
  const [courses, setCourses] = useState(() => Array.isArray(user && user.buScope) ? user.buScope.slice() : []);
  const [channelScope, setChannelScope] = useState(() => Array.isArray(user && user.channelScope) ? user.channelScope.slice() : []);
  const toggleCh = id => setChannelScope(cs => cs.includes(id) ? cs.filter(x => x !== id) : [...cs, id]);
  const [invite, setInvite] = useState(true);
  const [newPw, setNewPw] = useState('');
  const [newPw2, setNewPw2] = useState('');
  const [roles, setRoles] = useState(() => {
    if (user && Array.isArray(user.roles) && user.roles.length) return user.roles.slice();
    if (user && user.role) return [user.role];
    return ['sales'];
  });
  const set = (k, v) => setF(s => ({ ...s, [k]: v }));
  const toggleRole = id => setRoles(rs => rs.includes(id) ? rs.filter(x => x !== id) : [...rs, id]);
  const pwErr = newPw && (newPw.length < 6 ? 'Mật khẩu tối thiểu 6 ký tự.' : (newPw !== newPw2 ? 'Mật khẩu nhập lại không khớp.' : ''));
  const valid = (f.name || '').trim() && (f.email || '').trim() && roles.length > 0 && !pwErr;
  const toggleCourse = id => setCourses(cs => cs.includes(id) ? cs.filter(x => x !== id) : [...cs, id]);
  const submit = () => {
    if (!valid) return;
    const buScope = scopeKind === 'all' ? 'all' : courses;
    onSave({ ...f, role: roles[0], roles, buScope, channelScope }, !user && invite, newPw.trim() || null);
  };
  const allCourses = (AAU.courses || []).filter(c => c.status !== 'coming_soon');

  return (
    <Modal title={user ? 'Sửa người dùng' : 'Thêm người dùng'} onClose={onClose} width={560}
      footer={<><Button onClick={onClose}>Hủy</Button><Button variant="primary" onClick={submit} disabled={!valid || busy}>{busy ? 'Đang lưu…' : (user ? 'Lưu thay đổi' : 'Tạo người dùng')}</Button></>}>
      <div className="col g16">
        <div className="grid gc2 g16">
          <Field label="Họ tên"><Input value={f.name} onChange={v => set('name', v)} placeholder="VD: Nguyễn Văn A" autoFocus /></Field>
          <Field label="Email"><Input value={f.email} onChange={v => set('email', v)} placeholder="ten@aau.vn" /></Field>
        </div>
        <Field label={'Vai trò (RBAC) — tick được NHIỀU vai trò, quyền = hợp của tất cả' + (roles.length > 1 ? ' · đang chọn ' + roles.length : '')}>
          <div className="grid gc3 g6" style={{ border: '1px solid var(--p-border-subdued, #e3e6ea)', borderRadius: 10, padding: 10 }}>
            {AAU.roles.map(r => (
              <label key={r.id} className="row g6 aic t12" style={{ cursor: 'pointer' }}>
                <input type="checkbox" checked={roles.includes(r.id)} onChange={() => toggleRole(r.id)} />
                <span>{r.label}</span>
              </label>
            ))}
          </div>
        </Field>
        <Field label="Chức danh"><Input value={f.title} onChange={v => set('title', v)} placeholder="VD: Sales BU 4" /></Field>
        <Field label="Phạm vi dữ liệu">
          <Seg value={scopeKind} onChange={setScopeKind} options={[{ value: 'all', label: 'Toàn bộ khóa' }, { value: 'bu', label: 'Theo nhóm khóa được giao' }]} />
        </Field>
        {scopeKind === 'bu' && (
          <div style={{ border: '1px solid var(--p-border-subdued, #e3e6ea)', borderRadius: 10, padding: 10, maxHeight: 160, overflow: 'auto' }}>
            <div className="grid gc2 g6">
              {allCourses.map(c => (
                <label key={c.id} className="row g6 aic t12" style={{ cursor: 'pointer' }}>
                  <input type="checkbox" checked={courses.includes(c.id)} onChange={() => toggleCourse(c.id)} />
                  <span>{c.code ? c.code + ' · ' : ''}{c.name}</span>
                </label>
              ))}
            </div>
            {allCourses.length === 0 && <div className="t12 muted">Chưa có khóa học.</div>}
          </div>
        )}
        <Field label="Mức quyền truy cập">
          <Seg value={f.access} onChange={v => set('access', v)} options={[{ value: 'view', label: 'Chỉ xem' }, { value: 'edit', label: 'Chỉnh sửa' }, { value: 'manage', label: 'Quản trị' }]} />
        </Field>
        <Field label={'Kênh chat được phép (Inbox)' + (channelScope.length ? ' · đang chọn ' + channelScope.length : ' · để trống = mọi kênh')}>
          <div className="grid gc3 g6" style={{ border: '1px solid var(--p-border-subdued, #e3e6ea)', borderRadius: 10, padding: 10 }}>
            {Object.values(AAU.channels || {}).map(ch => (
              <label key={ch.id} className="row g6 aic t12" style={{ cursor: 'pointer' }}>
                <input type="checkbox" checked={channelScope.includes(ch.id)} onChange={() => toggleCh(ch.id)} />
                <span>{ch.label}</span>
              </label>
            ))}
          </div>
          <div className="t11 subtle mt6" style={{ lineHeight: 1.5 }}>Để trống = thấy & trả lời <b>mọi kênh</b>. Chọn cụ thể = chỉ thấy hội thoại các kênh đó. <b>Admin / Manager</b> luôn xem tất cả. Với <b>Zalo cá nhân</b>, còn phải được gán đúng tài khoản ở “Nguồn kết nối”.</div>
        </Field>
        {!user && (
          <div className="row jcsb aic" style={{ padding: 12, borderRadius: 10, background: 'var(--p-bg-surface-secondary)' }}>
            <div><div className="t13 fw6">Mời kích hoạt</div><div className="t11 subtle">Tạo link đặt mật khẩu (gửi email nếu đã cấu hình SMTP). Tắt = tạo tài khoản trước, mời sau.</div></div>
            <Switch on={invite} onChange={setInvite} />
          </div>
        )}
        {user && (
          <div className="col g10" style={{ padding: 12, borderRadius: 10, background: 'var(--p-bg-surface-secondary)' }}>
            <div className="row jcsb aic">
              <div className="t13 fw6">Đặt lại mật khẩu</div>
              <Button size="sm" icon="mail" onClick={() => onResetLink && onResetLink(user)}>Gửi link để họ tự đặt</Button>
            </div>
            <div className="grid gc2 g10">
              <Input type="password" value={newPw} onChange={setNewPw} placeholder="Mật khẩu mới" />
              <Input type="password" value={newPw2} onChange={setNewPw2} placeholder="Nhập lại mật khẩu" />
            </div>
            {pwErr ? <div className="t11" style={{ color: '#b91c1c' }}>{pwErr}</div>
              : <div className="t11 subtle">Đặt mật khẩu mới trực tiếp (để trống nếu không đổi), HOẶC gửi link để người dùng tự đặt.</div>}
          </div>
        )}
        <div className="row g8 aic t12 muted">
          <Icon name="shield" size={14} />
          <span>Vai trò <b>{roleLabel(f.role)}</b> sẽ áp dụng ma trận quyền tương ứng. Chỉnh chi tiết ở màn RBAC.</span>
        </div>
      </div>
    </Modal>
  );
}

function RBACMatrix() {
  const [role, setRole] = useState('manager');
  const r = AAU.roles.find(x => x.id === role);
  const all = r.perms === 'all';
  // Resolve actions cho 1 resource: override theo resource > scope theo group
  const groupOf = key => AAU.rbacGroups.find(g => g.resources.some(x => x.key === key)).group;
  const permsFor = key => {
    if (all) return AAU.rbacActions.map(a => a.key);
    if (r.over && r.over[key]) return r.over[key];
    return (r.scope && r.scope[groupOf(key)]) || [];
  };
  const isOverridden = key => !all && r.over && r.over.hasOwnProperty(key);
  const can = (key, act) => permsFor(key).includes(act);

  // Tổng hợp số liệu
  const allRes = AAU.rbacGroups.flatMap(g => g.resources);
  const granted = allRes.reduce((s, x) => s + (all ? AAU.rbacActions.length : permsFor(x.key).length), 0);
  const totalCells = allRes.length * AAU.rbacActions.length;
  const modulesTouched = AAU.rbacGroups.filter(g => g.resources.some(x => permsFor(x.key).length > 0)).length;

  return (
    <div className="page wide">
      <PageHead title="RBAC — Phân quyền" subtitle="Ma trận chi tiết module × resource × action. Override theo từng màn, kế thừa theo nhóm."
        actions={<Button variant="primary" icon="plus">Tạo role</Button>} />

      {/* Role picker — thẻ chọn */}
      <div className="grid mb16" style={{ gridTemplateColumns: 'repeat(' + AAU.roles.length + ', 1fr)', gap: 10 }}>
        {AAU.roles.map(x => {
          const active = x.id === role;
          return (
            <div key={x.id} onClick={() => setRole(x.id)} className="card pad"
              style={{ cursor: 'pointer', borderColor: active ? 'var(--p-interactive)' : 'var(--p-border)', boxShadow: active ? '0 0 0 2px var(--p-interactive)' : 'none' }}>
              <div className="row jcsb aic">
                <span className="t13 fw7">{x.label}</span>
                {x.perms === 'all' ? <Badge tone="magic">Full</Badge> : <span className="t12 muted">{x.users} user</span>}
              </div>
              <div className="t12 muted mt4" style={{ lineHeight: 1.35 }}>{x.desc}</div>
            </div>
          );
        })}
      </div>

      {/* Tóm tắt quyền của role đang chọn */}
      <div className="grid gc4 mb16">
        {[
          { t: 'Quyền được cấp', v: all ? totalCells : granted, sub: '/' + totalCells + ' ô', tone: 'info' },
          { t: 'Module truy cập', v: modulesTouched, sub: '/' + AAU.rbacGroups.length + ' nhóm', tone: 'success' },
          { t: 'Override riêng', v: all ? 0 : Object.keys(r.over || {}).length, sub: 'khác mặc định nhóm', tone: 'warning' },
          { t: 'Mức độ', v: all ? '100%' : Math.round(granted / totalCells * 100) + '%', sub: 'độ phủ quyền', tone: 'magic' },
        ].map((c, i) => (
          <div key={i} className="card pad">
            <div className="t12 muted">{c.t}</div>
            <div className="row aic g6 mt4"><span className="fw7" style={{ fontSize: 24 }}>{c.v}</span><span className="t12 subtle">{c.sub}</span></div>
          </div>
        ))}
      </div>

      <Card pad={false} title={'Ma trận quyền · ' + r.label} subtitle={all ? 'Toàn quyền — không thể chỉnh' : 'Tick để cấp/thu quyền · hàng ⚑ là override riêng'}>
        <div style={{ overflowX: 'auto' }}>
          <table className="tbl rbac-tbl">
            <thead>
              <tr>
                <th style={{ minWidth: 220, position: 'sticky', left: 0, background: 'var(--p-bg-surface)' }}>Resource</th>
                {AAU.rbacActions.map(a => <th key={a.key} className="num">{a.label}</th>)}
              </tr>
            </thead>
            <tbody>
              {AAU.rbacGroups.map(g => {
                const grpActs = AAU.rbacActions.map(a => g.resources.every(res => can(res.key, a.key)));
                return (
                  <React.Fragment key={g.group}>
                    <tr className="rbac-grp">
                      <td className="fw7 t12" style={{ position: 'sticky', left: 0, background: 'var(--p-bg-surface-secondary)', textTransform: 'uppercase', letterSpacing: '.04em', color: 'var(--p-text-subdued)' }}>{g.group}</td>
                      {AAU.rbacActions.map((a, ai) => (
                        <td key={a.key} className="num"><div style={{ display: 'inline-flex', opacity: .55 }}><Checkbox on={all || grpActs[ai]} onChange={() => {}} /></div></td>
                      ))}
                    </tr>
                    {g.resources.map(res => (
                      <tr key={res.key}>
                        <td style={{ position: 'sticky', left: 0, background: 'var(--p-bg-surface)' }}>
                          <span className="row aic g6">{res.label}{isOverridden(res.key) && <Badge tone="warning">⚑ riêng</Badge>}</span>
                        </td>
                        {AAU.rbacActions.map(a => (
                          <td key={a.key} className="num"><div style={{ display: 'inline-flex' }}><Checkbox on={can(res.key, a.key)} onChange={() => {}} /></div></td>
                        ))}
                      </tr>
                    ))}
                  </React.Fragment>
                );
              })}
            </tbody>
          </table>
        </div>
      </Card>
    </div>
  );
}

function SystemSettings() {
  const [tab, setTab] = useState('ai');
  const tabs = [{ value: 'ai', label: 'AI Providers' }, { value: 'notif', label: 'Thông báo' }, { value: 'fx', label: 'Tỷ giá' }, { value: 'brand', label: 'Branding' }];
  return (
    <div className="page wide">
      <PageHead title="System Settings" subtitle="Cấu hình tenant — mọi thay đổi có lịch sử (ai · khi nào)"
        actions={<Button variant="primary" icon="save">Lưu thay đổi</Button>} />
      <Card pad={false}>
        <div style={{ padding: '4px 8px' }}><Tabs value={tab} onChange={setTab} tabs={tabs} /></div>
        <div className="card-body">
          {tab === 'ai' && <div className="col g16"><Field label="AI Provider"><Select value="claude" onChange={() => {}} options={[{ value: 'claude', label: 'Anthropic Claude' }, { value: 'openai', label: 'OpenAI' }]} /></Field><Field label="API Key"><Input value="sk-ant-••••••••••••" onChange={() => {}} /></Field><Field label="Model chấm QC"><Select value="sonnet" onChange={() => {}} options={[{ value: 'sonnet', label: 'Claude Sonnet' }, { value: 'haiku', label: 'Claude Haiku' }]} /></Field></div>}
          {tab === 'notif' && <div className="col g10">{['Telegram', 'Email', 'Zalo ZNS', 'In-app'].map((n, i) => <div key={i} className="row jcsb aic" style={{ padding: 12, borderRadius: 10, border: '1px solid var(--p-border)' }}><span className="t13 fw6">{n}</span><Switch on={i < 3} onChange={() => {}} /></div>)}</div>}
          {tab === 'fx' && <div className="row g16"><Field label="USD → VND"><Input value="25.400" onChange={() => {}} /></Field><Field label="Cập nhật"><Input value="Hằng ngày" onChange={() => {}} /></Field></div>}
          {tab === 'brand' && <div className="col g16"><Field label="Tên hiển thị"><Input value="AAU Academy — HCM" onChange={() => {}} /></Field><Field label="Màu chủ đạo"><div className="row g6">{['#008060', '#0084ff', '#7c3aed'].map(c => <span key={c} style={{ width: 28, height: 28, borderRadius: 7, background: c }} />)}</div></Field></div>}
        </div>
      </Card>
    </div>
  );
}

function AutomationCenter() {
  const [rules, setRules] = useState(AAU.automationRules.map(r => ({ ...r })));
  return (
    <div className="page wide">
      <PageHead title="Notification & Automation" subtitle="Quy tắc nếu-X-thì-Y: sự kiện → kênh gửi → người nhận"
        actions={<Button variant="primary" icon="plus">Thêm rule</Button>} />
      <div className="col g12">
        {rules.map((r, idx) => (
          <Card key={r.id} pad>
            <div className="row aic g12">
              <span className="center" style={{ width: 38, height: 38, borderRadius: 10, background: 'var(--p-bg-surface-tertiary)', color: '#7c3aed' }}><Icon name="bolt" size={18} /></span>
              <div className="f1">
                <div className="t14 fw6">{r.name}</div>
                <div className="row aic g6 t12 muted mt4"><Badge tone="warning">Khi: {r.event}</Badge><Icon name="arrowRight" size={12} /><Badge tone="info">Gửi: {r.channel}</Badge><Icon name="arrowRight" size={12} /><span>{r.to}</span></div>
              </div>
              <Switch on={r.on} onChange={v => { setRules(rs => rs.map((x, i) => i === idx ? { ...x, on: v } : x)); if (window.API && window.API.enabled) window.API.put('/automation/rules/' + r.id, { on: v }).catch(() => {}); }} />
            </div>
          </Card>
        ))}
      </div>
    </div>
  );
}

// ============================================================
//  Auto-staging rules — quy tắc tự động chuyển stage cho Pipeline Kanban.
// ============================================================
const COND_TYPES = [
  { value: 'has_phone', label: 'Có số điện thoại' },
  { value: 'two_way_chat', label: 'Đang chat (khách nhắn + mình trả lời)' },
  { value: 'stale_days', label: 'N ngày không tương tác' },
  { value: 'has_email', label: 'Có email' },
  { value: 'hot_signal', label: 'Có tín hiệu nóng (hỏi giá/lịch)' },
];
const condLabel = r => {
  const base = (COND_TYPES.find(c => c.value === r.condType) || {}).label || r.condType;
  return r.condType === 'stale_days' ? (r.days || 14) + ' ngày không tương tác' : base;
};
const stageName = id => { const s = (AAU.stages || []).find(x => x.id === id); return s ? ((s.code ? s.code + ' ' : '') + s.name) : id; };

function StageRules() {
  const live = () => !!(window.API && window.API.enabled);
  const [list, setList] = useState([]);
  const [editing, setEditing] = useState(null); // null | 'add' | rule
  const [busy, setBusy] = useState(false);
  const [msg, setMsg] = useState('');
  const canEdit = window.Perm ? Perm.can('leads', 'approve') : true;
  const load = () => { if (live()) window.API.stageRules().then(d => Array.isArray(d) && setList(d)).catch(() => { }); };
  useEffect(() => { load(); }, []);
  const sorted = [...list].sort((a, b) => (a.priority || 0) - (b.priority || 0));

  const save = async (rule) => {
    setBusy(true); setMsg('');
    try {
      if (rule.id && list.find(r => r.id === rule.id)) await window.API.updateStageRule(rule.id, rule);
      else await window.API.createStageRule(rule);
      setEditing(null); load();
    } catch (e) { setMsg(e.message || 'Lưu lỗi'); }
    setBusy(false);
  };
  const toggle = async (r) => { try { await window.API.updateStageRule(r.id, { enabled: !r.enabled }); load(); } catch (e) { setMsg(e.message); } };
  const remove = async (r) => { if (!window.confirm('Xóa quy tắc "' + r.name + '"?')) return; try { await window.API.deleteStageRule(r.id); load(); } catch (e) { setMsg(e.message); } };
  const runNow = async () => {
    setBusy(true); setMsg('');
    try { const res = await window.API.runStageRules(); setMsg('✓ Đã chạy: chuyển ' + res.moved + ' lead.'); if (typeof LeadStore !== 'undefined' && LeadStore.reload) { try { await window.API.refreshLeads(); } catch (e) { } } }
    catch (e) { setMsg(e.message || 'Chạy lỗi'); }
    setBusy(false);
  };

  return (
    <div className="page wide">
      <PageHead title="Quy tắc tự động chuyển stage" subtitle="Lead khớp điều kiện sẽ tự chuyển stage (theo thứ tự ưu tiên, quy tắc đầu khớp thắng). Chạy định kỳ + bấm Chạy ngay. Mọi lần chuyển đều ghi lịch sử “Tự động”."
        actions={canEdit && <div className="row g8"><Button icon="bolt" onClick={runNow} disabled={busy}>{busy ? 'Đang chạy…' : 'Chạy ngay'}</Button><Button variant="primary" icon="plus" onClick={() => setEditing('add')}>Thêm quy tắc</Button></div>} />
      {msg && <div className="t12" style={{ padding: '8px 12px', borderRadius: 8, marginBottom: 12, background: msg[0] === '✓' ? '#e3f5ec' : '#fef2f2', color: msg[0] === '✓' ? '#0a7d4f' : '#b91c1c' }}>{msg}</div>}
      {!canEdit && <div className="t12 muted mb12">Bạn chỉ xem được quy tắc (cần vai trò Leader/Manager/Admin để chỉnh).</div>}
      <Card pad={false} title={'Quy tắc (' + list.length + ')'}>
        <table className="tbl">
          <thead><tr><th>#</th><th>Tên quy tắc</th><th>Điều kiện</th><th>Áp dụng cho stage</th><th>→ Chuyển sang</th><th>Bật</th><th></th></tr></thead>
          <tbody>
            {sorted.map(r => (
              <tr key={r.id} style={{ opacity: r.enabled ? 1 : 0.5 }}>
                <td className="t12 muted">{r.priority}</td>
                <td className="t13 fw6">{r.name}</td>
                <td><span className="tag">{condLabel(r)}</span></td>
                <td className="t12">{(r.fromStages && r.fromStages.length) ? r.fromStages.map(stageName).join(', ') : <span className="muted">Mọi stage</span>}</td>
                <td><Badge tone="info">{stageName(r.toStage)}</Badge></td>
                <td>{canEdit ? <Switch on={!!r.enabled} onChange={() => toggle(r)} /> : (r.enabled ? <Badge tone="success" dot>Bật</Badge> : <Badge tone="neutral">Tắt</Badge>)}</td>
                <td className="num">{canEdit && <div className="row g4 jce"><Button size="sm" variant="plain" icon="edit" onClick={() => setEditing(r)}>Sửa</Button>{window.Perm && Perm.canDelete() && <Button size="sm" variant="plain" icon="trash" onClick={() => remove(r)}>Xóa</Button>}</div>}</td>
              </tr>
            ))}
            {list.length === 0 && <tr><td colSpan={7}><div className="t12 muted" style={{ padding: 24, textAlign: 'center' }}>Chưa có quy tắc. Bấm “Thêm quy tắc”.</div></td></tr>}
          </tbody>
        </table>
      </Card>
      {editing && <StageRuleForm rule={editing === 'add' ? null : editing} busy={busy} onClose={() => setEditing(null)} onSave={save} />}
    </div>
  );
}

function StageRuleForm({ rule, onClose, onSave, busy }) {
  const [f, setF] = useState(rule || { name: '', condType: 'has_phone', days: 14, toStage: 's_chat', fromStages: ['s_raw'], priority: 10, enabled: true });
  const set = (k, v) => setF(s => ({ ...s, [k]: v }));
  const leadStages = (AAU.stages || []).filter(s => ['lead', 'leadb'].includes(s.funnel));
  const allStages = (AAU.stages || []);
  const toggleFrom = id => setF(s => { const cur = s.fromStages || []; return { ...s, fromStages: cur.includes(id) ? cur.filter(x => x !== id) : [...cur, id] }; });
  const valid = (f.name || '').trim() && f.condType && f.toStage;
  return (
    <Modal title={rule ? 'Sửa quy tắc' : 'Thêm quy tắc'} onClose={onClose} width={580}
      footer={<><Button onClick={onClose}>Hủy</Button><Button variant="primary" onClick={() => valid && onSave({ ...f, days: f.condType === 'stale_days' ? (parseInt(f.days, 10) || 14) : undefined, priority: parseInt(f.priority, 10) || 10 })} disabled={!valid || busy}>{busy ? 'Đang lưu…' : 'Lưu'}</Button></>}>
      <div className="col g14">
        <Field label="Tên quy tắc"><Input value={f.name} onChange={v => set('name', v)} placeholder="VD: Có số điện thoại → Hot Lead Call" autoFocus /></Field>
        <div className="grid gc2 g14">
          <Field label="Điều kiện"><Select value={f.condType} onChange={v => set('condType', v)} options={COND_TYPES.map(c => ({ value: c.value, label: c.label }))} /></Field>
          {f.condType === 'stale_days'
            ? <Field label="Số ngày không tương tác"><Input value={String(f.days)} onChange={v => set('days', v)} /></Field>
            : <Field label="Thứ tự ưu tiên (nhỏ = ưu tiên trước)"><Input value={String(f.priority)} onChange={v => set('priority', v)} /></Field>}
        </div>
        {f.condType === 'stale_days' && <Field label="Thứ tự ưu tiên (nhỏ = ưu tiên trước)"><Input value={String(f.priority)} onChange={v => set('priority', v)} /></Field>}
        <Field label="→ Chuyển sang stage"><Select value={f.toStage} onChange={v => set('toStage', v)} options={allStages.map(s => ({ value: s.id, label: (s.code ? s.code + ' ' : '') + s.name }))} /></Field>
        <Field label="Áp dụng cho lead đang ở stage (chọn nhiều; bỏ trống = mọi stage)">
          <div className="grid gc3 g6" style={{ border: '1px solid var(--p-border-subdued, #e3e6ea)', borderRadius: 10, padding: 10, maxHeight: 200, overflow: 'auto' }}>
            {leadStages.map(s => (
              <label key={s.id} className="row g6 aic t12" style={{ cursor: 'pointer' }}>
                <input type="checkbox" checked={(f.fromStages || []).includes(s.id)} onChange={() => toggleFrom(s.id)} />
                <span>{(s.code ? s.code + ' ' : '') + s.name}</span>
              </label>
            ))}
          </div>
        </Field>
        <div className="t11 muted">Mẹo: để tránh kéo lead đã chốt về, chỉ chọn các stage đầu phễu (1.x/2.x).</div>
      </div>
    </Modal>
  );
}

Object.assign(window, { QCRulesets, QCDashboard, QCReports, AttributionHub, FunnelReconcileBody, RoasForecastBody, UserManagement, UserForm, RBACMatrix, SystemSettings, AutomationCenter, StageRules });
