/*
 * DialerTab.jsx — Outbound Dialer Yönetim Paneli
 * Kampanya listesi, kişi tablosu, CSV/Excel yükleme,
 * Preview (manuel arama) ve Predictive (otomatik) modları.
 */
(function () {
 const { useState, useEffect, useRef, useCallback } = React;

 // Yardımcı: fetch wrapper 
 async function api(path, opts = {}) {
 const res = await authFetch(path, {
 headers: { "Content-Type": "application/json", ...opts.headers },
 ...opts,
 });
 if (!res.ok) {
 let msg = res.statusText;
 try { const j = await res.json(); msg = j.detail || JSON.stringify(j); } catch {}
 throw new Error(msg);
 }
 return res.json();
 }

 // Durum rozeti 
 function StatusBadge({ status }) {
 const map = {
 idle: { color: "#6b7280", label: "Hazır" },
 running: { color: "#22c55e", label: " Çalışıyor" },
 paused: { color: "#f59e0b", label: " Duraklatıldı" },
 completed: { color: "#3b82f6", label: " Tamamlandı" },
 };
 const s = map[status] || { color: "#6b7280", label: status };
 return (
 <span style={{
 background: s.color + "22", color: s.color,
 padding: "2px 10px", borderRadius: 20, fontSize: 12, fontWeight: 700,
 border: `1px solid ${s.color}55`,
 }}>{s.label}</span>
 );
 }

 // Kişi durum rozeti 
 function ContactBadge({ status }) {
 const map = {
 pending: { bg: "#374151", color: "#9ca3af", label: "Bekliyor" },
 calling: { bg: "#1e3a5f", color: "#60a5fa", label: "Arıyor" },
 answered: { bg: "#14532d", color: "#86efac", label: "Cevaplandı" },
 completed: { bg: "#1e3a5f", color: "#3b82f6", label: "Tamamlandı" },
 no_answer: { bg: "#422006", color: "#fbbf24", label: "Cevap Yok" },
 busy: { bg: "#3b0764", color: "#c084fc", label: "Meşgul" },
 failed: { bg: "#450a0a", color: "#f87171", label: "Başarısız" },
 dnc: { bg: "#3f3f46", color: "#a1a1aa", label: "DNC" },
 };
 const s = map[status] || { bg: "#374151", color: "#9ca3af", label: status };
 return (
 <span style={{
 background: s.bg, color: s.color,
 padding: "2px 8px", borderRadius: 12, fontSize: 11, fontWeight: 600,
 }}>{s.label}</span>
 );
 }

 // İstatistik kutusu 
 function StatBox({ label, value, color = "var(--text)" }) {
 return (
 <div style={{
 background: "var(--surface2)", borderRadius: 10, padding: "10px 16px",
 border: "1px solid var(--border)", textAlign: "center", minWidth: 90,
 }}>
 <div style={{ fontSize: 22, fontWeight: 600, color }}>{value ?? 0}</div>
 <div style={{ fontSize: 11, color: "var(--text-dim)", marginTop: 2 }}>{label}</div>
 </div>
 );
 }

 // Yeni Kampanya Modalı 
 function NewCampaignModal({ agents, onClose, onSaved }) {
 const [form, setForm] = useState({
 name: "", description: "", agent_type: "ai",
 agent_id: agents[0]?.id || "", queue_id: "",
 caller_id_number: "", caller_id_name: "", gateway: "default",
 mode: "preview", max_concurrent: 3, retry_attempts: 1,
 retry_delay_min: 30, leg_timeout: 30,
 });
 const [queues, setQueues] = useState([]);
 const [saving, setSaving] = useState(false);
 const [err, setErr] = useState("");

 const set = (k, v) => setForm(p => ({ ...p, [k]: v }));

 // Kuyruk listesini yukle
 useEffect(() => {
 api("/api/queues").then(setQueues).catch(() => {});
 }, []);

 async function save() {
 if (!form.name || !form.caller_id_number) {
 setErr("Ad ve Caller ID zorunludur."); return;
 }
 if (form.agent_type === "ai" && !form.agent_id) {
 setErr("AI modu icin asistan secimi zorunludur."); return;
 }
 if (form.agent_type === "human" && !form.queue_id) {
 setErr("Insan modu icin kuyruk secimi zorunludur."); return;
 }
 setSaving(true); setErr("");
 try {
 const body = {
 ...form,
 agent_id: form.agent_type === "ai" ? Number(form.agent_id) : null,
 queue_id: form.agent_type === "human" ? Number(form.queue_id) : null,
 };
 const created = await api("/api/campaigns", {
 method: "POST",
 body: JSON.stringify(body),
 });
 onSaved(created);
 } catch (e) { setErr(e.message); }
 finally { setSaving(false); }
 }

 const inp = {
 background: "var(--surface2)", border: "1px solid var(--border)",
 color: "var(--text)", padding: "7px 10px", borderRadius: 8, width: "100%",
 fontSize: 13, outline: "none",
 };

 return (
 <div style={{
 position: "fixed", inset: 0, background: "#000a",
 display: "flex", alignItems: "center", justifyContent: "center", zIndex: 1000,
 }}>
 <div style={{
 background: "var(--surface)", borderRadius: 14, padding: 28, width: 500,
 border: "1px solid var(--border)", maxHeight: "90vh", overflowY: "auto",
 }}>
 <div style={{ fontSize: 18, fontWeight: 700, marginBottom: 20 }}> Yeni Kampanya</div>

 {[
 ["Kampanya Adı *", "name", "text"],
 ["Açıklama", "description", "text"],
 ["Caller ID Numarası *", "caller_id_number", "text"],
 ["Caller ID Adı", "caller_id_name", "text"],
 ["Gateway", "gateway", "text"],
 ].map(([label, key, type]) => (
 <div key={key} style={{ marginBottom: 12 }}>
 <div style={{ fontSize: 12, color: "var(--text-dim)", marginBottom: 4 }}>{label}</div>
 <input type={type} value={form[key]} onChange={e => set(key, e.target.value)} style={inp} />
 </div>
 ))}

 {/* Arama Tipi */}
 <div style={{ marginBottom: 12 }}>
 <div style={{ fontSize: 12, color: "var(--text-dim)", marginBottom: 4 }}>Arama Tipi</div>
 <div style={{ display: "flex", gap: 6 }}>
 {[
 { val: "ai", label: "AI Asistan", icon: "" },
 { val: "human", label: "Insan Temsilci", icon: "" },
 ].map(opt => (
 <button key={opt.val} onClick={() => set("agent_type", opt.val)} style={{
 flex: 1, padding: "8px", borderRadius: 8, cursor: "pointer", fontSize: 13, fontWeight: 700,
 border: `1px solid ${form.agent_type === opt.val ? "var(--blue)" : "var(--border)"}`,
 background: form.agent_type === opt.val ? "rgba(59,130,246,0.1)" : "transparent",
 color: form.agent_type === opt.val ? "var(--blue)" : "var(--text-dim)",
 fontFamily: "var(--font)",
 }}>{opt.icon} {opt.label}</button>
 ))}
 </div>
 </div>

 {/* AI modu: Asistan secimi */}
 {form.agent_type === "ai" && (
 <div style={{ marginBottom: 12 }}>
 <div style={{ fontSize: 12, color: "var(--text-dim)", marginBottom: 4 }}>AI Asistan *</div>
 <select value={form.agent_id} onChange={e => set("agent_id", e.target.value)} style={inp}>
 {agents.map(a => <option key={a.id} value={a.id}>{a.name}</option>)}
 </select>
 </div>
 )}

 {/* Human modu: Kuyruk secimi */}
 {form.agent_type === "human" && (
 <div style={{ marginBottom: 12 }}>
 <div style={{ fontSize: 12, color: "var(--text-dim)", marginBottom: 4 }}>Kuyruk * (Bu kuyruktaki temsilciler kampanyayi gorebilir)</div>
 <select value={form.queue_id} onChange={e => set("queue_id", e.target.value)} style={inp}>
 <option value="">Kuyruk secin...</option>
 {queues.map(q => <option key={q.id} value={q.id}>{q.name}</option>)}
 </select>
 </div>
 )}

 <div style={{ marginBottom: 12 }}>
 <div style={{ fontSize: 12, color: "var(--text-dim)", marginBottom: 4 }}>Arama Modu</div>
 <select value={form.mode} onChange={e => set("mode", e.target.value)} style={inp}>
 <option value="preview">Preview (Manuel)</option>
 <option value="predictive">Predictive (Otomatik)</option>
 </select>
 </div>

 {form.mode === "predictive" && (
 <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 10, marginBottom: 12 }}>
 {[
 ["Eş Zamanlı Hat", "max_concurrent"],
 ["Tekrar Denemesi", "retry_attempts"],
 ["Tekrar Aralığı (dk)", "retry_delay_min"],
 ].map(([label, key]) => (
 <div key={key}>
 <div style={{ fontSize: 11, color: "var(--text-dim)", marginBottom: 4 }}>{label}</div>
 <input type="number" min={1} value={form[key]}
 onChange={e => set(key, Number(e.target.value))} style={inp} />
 </div>
 ))}
 </div>
 )}

 <div style={{ marginBottom: 18 }}>
 <div style={{ fontSize: 12, color: "var(--text-dim)", marginBottom: 4 }}>Zil Süresi (sn)</div>
 <input type="number" min={10} max={120} value={form.leg_timeout}
 onChange={e => set("leg_timeout", Number(e.target.value))} style={{ ...inp, width: 100 }} />
 </div>

 {err && <div style={{ color: "#f87171", fontSize: 13, marginBottom: 12 }}>{err}</div>}

 <div style={{ display: "flex", gap: 10, justifyContent: "flex-end" }}>
 <button onClick={onClose} style={{
 background: "var(--surface2)", border: "1px solid var(--border)",
 color: "var(--text)", padding: "8px 18px", borderRadius: 8, cursor: "pointer",
 }}>İptal</button>
 <button onClick={save} disabled={saving} style={{
 background: "var(--primary)", border: "none", color: "#fff",
 padding: "8px 20px", borderRadius: 8, cursor: "pointer", fontWeight: 700,
 }}>{saving ? "Kaydediliyor…" : "Oluştur"}</button>
 </div>
 </div>
 </div>
 );
 }

 // CSV Yükleme bileşeni 
 function UploadPanel({ campaign, onUploaded }) {
 const [dragging, setDragging] = useState(false);
 const [uploading, setUploading] = useState(false);
 const [msg, setMsg] = useState("");
 const fileRef = useRef();

 async function upload(file) {
 if (!file) return;
 setUploading(true); setMsg("");
 const fd = new FormData();
 fd.append("file", file);
 try {
 const res = await authFetch(`/api/campaigns/${campaign.id}/upload`, { method: "POST", body: fd });
 const j = await res.json();
 if (!res.ok) throw new Error(j.detail || "Yükleme hatası");
 setMsg(` ${j.inserted} kişi yüklendi.`);
 onUploaded();
 } catch (e) { setMsg(" " + e.message); }
 finally { setUploading(false); }
 }

 function onDrop(e) {
 e.preventDefault(); setDragging(false);
 const f = e.dataTransfer.files[0];
 if (f) upload(f);
 }

 return (
 <div style={{ marginBottom: 20 }}>
 <div
 onClick={() => fileRef.current?.click()}
 onDragOver={e => { e.preventDefault(); setDragging(true); }}
 onDragLeave={() => setDragging(false)}
 onDrop={onDrop}
 style={{
 border: `2px dashed ${dragging ? "var(--primary)" : "var(--border)"}`,
 borderRadius: 10, padding: "24px 20px", textAlign: "center",
 cursor: "pointer", transition: "border-color .2s",
 background: dragging ? "var(--primary)11" : "var(--surface2)",
 }}
 >
  <div style={{ fontSize: 14, fontWeight: 600, marginBottom: 4 }}>
 CSV veya Excel dosyasını buraya sürükleyin
 </div>
 <div style={{ fontSize: 12, color: "var(--text-dim)" }}>
 veya tıklayarak seçin • .csv, .xlsx, .xls
 </div>
 {uploading && <div style={{ marginTop: 8, color: "var(--primary)", fontSize: 13 }}>Yükleniyor…</div>}
 </div>
 <input ref={fileRef} type="file" accept=".csv,.xlsx,.xls"
 style={{ display: "none" }}
 onChange={e => { if (e.target.files[0]) upload(e.target.files[0]); }} />
 {msg && <div style={{ marginTop: 8, fontSize: 13, color: msg.startsWith("") ? "#22c55e" : "#f87171" }}>{msg}</div>}
 </div>
 );
 }

 // Kişi tablosu 
 function ContactsTable({ campaign, refreshKey, onRefresh }) {
 const [contacts, setContacts] = useState([]);
 const [total, setTotal] = useState(0);
 const [page, setPage] = useState(1);
 const [filter, setFilter] = useState("all");
 const [calling, setCalling] = useState({});
 const PER_PAGE = 50;

 const load = useCallback(async () => {
 try {
 const offset = (page - 1) * PER_PAGE;
 const st = filter === "all" ? "" : `&status=${filter}`;
 const r = await api(`/api/campaigns/${campaign.id}/contacts?limit=${PER_PAGE}&offset=${offset}${st}`);
 setContacts(r.contacts || []);
 setTotal(r.total || 0);
 } catch {}
 }, [campaign.id, page, filter, refreshKey]);

 useEffect(() => { load(); }, [load]);

 async function callContact(contact) {
 setCalling(p => ({ ...p, [contact.id]: true }));
 try {
 await api(`/api/campaigns/${campaign.id}/contacts/${contact.id}/call`, { method: "POST" });
 await load();
 onRefresh();
 } catch (e) { alert("Arama başlatılamadı: " + e.message); }
 finally { setCalling(p => ({ ...p, [contact.id]: false })); }
 }

 const pages = Math.ceil(total / PER_PAGE);
 const statusOptions = [
 { v: "all", l: "Tümü" }, { v: "pending", l: "Bekliyor" },
 { v: "calling", l: "Arıyor" }, { v: "answered", l: "Cevaplandı" },
 { v: "completed", l: "Tamamlandı" }, { v: "no_answer", l: "Cevap Yok" },
 { v: "failed", l: "Başarısız" }, { v: "dnc", l: "DNC" },
 ];

 return (
 <div>
 <div style={{ display: "flex", alignItems: "center", gap: 12, marginBottom: 12 }}>
 <div style={{ fontSize: 14, fontWeight: 700 }}>Kişiler ({total})</div>
 <select value={filter} onChange={e => { setFilter(e.target.value); setPage(1); }}
 style={{
 background: "var(--surface2)", border: "1px solid var(--border)",
 color: "var(--text)", padding: "4px 10px", borderRadius: 8, fontSize: 13,
 }}>
 {statusOptions.map(o => <option key={o.v} value={o.v}>{o.l}</option>)}
 </select>
 <button onClick={load} style={{
 background: "var(--surface2)", border: "1px solid var(--border)",
 color: "var(--text)", padding: "4px 12px", borderRadius: 8, cursor: "pointer", fontSize: 13,
 }}> Yenile</button>
 </div>

 {contacts.length === 0 ? (
 <div style={{ color: "var(--text-dim)", padding: 20, textAlign: "center" }}>
 Kişi bulunamadı.
 </div>
 ) : (
 <div style={{ overflowX: "auto" }}>
 <table style={{ width: "100%", borderCollapse: "collapse", fontSize: 13 }}>
 <thead>
 <tr style={{ borderBottom: "1px solid var(--border)" }}>
 {["Telefon", "Ad", "Not", "Durum", "Sebep", "Deneme", "Son Arama", ""].map(h => (
 <th key={h} style={{ textAlign: "left", padding: "6px 10px", color: "var(--text-dim)", fontWeight: 600, whiteSpace: "nowrap" }}>{h}</th>
 ))}
 </tr>
 </thead>
 <tbody>
 {contacts.map(c => (
 <tr key={c.id} style={{ borderBottom: "1px solid var(--border)22" }}>
 <td style={{ padding: "6px 10px", fontFamily: "monospace" }}>{c.phone}</td>
 <td style={{ padding: "6px 10px" }}>{c.name || "—"}</td>
 <td style={{ padding: "6px 10px", maxWidth: 160, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{c.note || "—"}</td>
 <td style={{ padding: "6px 10px" }}><ContactBadge status={c.status} /></td>
 <td style={{ padding: "6px 10px", color: "var(--text-dim)", fontSize: 11 }}>{c.hangup_cause || "—"}</td>
 <td style={{ padding: "6px 10px", textAlign: "center" }}>{c.attempts ?? 0}</td>
 <td style={{ padding: "6px 10px", color: "var(--text-dim)", fontSize: 12 }}>
 {fmtDateTime(c.last_attempt_at)}
 </td>
 <td style={{ padding: "6px 10px" }}>
 {campaign.mode === "preview" && campaign.status === "running" && c.status === "pending" && (
 <button
 onClick={() => callContact(c)}
 disabled={!!calling[c.id]}
 style={{
 background: calling[c.id] ? "var(--surface2)" : "#22c55e22",
 border: "1px solid #22c55e55", color: "#22c55e",
 padding: "3px 10px", borderRadius: 8, cursor: calling[c.id] ? "not-allowed" : "pointer",
 fontSize: 12, fontWeight: 700,
 }}
 >{calling[c.id] ? "Arıyor…" : " Ara"}</button>
 )}
 </td>
 </tr>
 ))}
 </tbody>
 </table>
 </div>
 )}

 {pages > 1 && (
 <div style={{ display: "flex", gap: 8, marginTop: 12, justifyContent: "center" }}>
 <button onClick={() => setPage(p => Math.max(1, p - 1))} disabled={page === 1}
 style={{ background: "var(--surface2)", border: "1px solid var(--border)", color: "var(--text)", padding: "4px 12px", borderRadius: 8, cursor: "pointer" }}>‹</button>
 <span style={{ padding: "4px 8px", fontSize: 13, color: "var(--text-dim)" }}>{page} / {pages}</span>
 <button onClick={() => setPage(p => Math.min(pages, p + 1))} disabled={page === pages}
 style={{ background: "var(--surface2)", border: "1px solid var(--border)", color: "var(--text)", padding: "4px 12px", borderRadius: 8, cursor: "pointer" }}>›</button>
 </div>
 )}
 </div>
 );
 }

 // Kampanya Detayı 
 function CampaignDetail({ campaign: initCamp, agents, onBack, wsEvents }) {
 const [camp, setCamp] = useState(initCamp);
 const [stats, setStats] = useState(null);
 const [tab, setTab] = useState("contacts"); // "contacts" | "upload"
 const [contactsKey, setContactsKey] = useState(0);
 const [busy, setBusy] = useState(false);

 const loadCamp = useCallback(async () => {
 try {
 const r = await api(`/api/campaigns/${initCamp.id}`);
 setCamp(r);
 setStats(r.live_stats || null);
 } catch {}
 }, [initCamp.id]);

 useEffect(() => { loadCamp(); }, [loadCamp]);

 // WS events: kampanya / kişi güncellemelerini dinle
 useEffect(() => {
 if (!wsEvents) return;
 const last = wsEvents[wsEvents.length - 1];
 if (!last) return;
 if (
 (last.type === "dialer_campaign_update" || last.type === "dialer_contact_update") &&
 last.campaign_id === camp.id
 ) {
 loadCamp();
 setContactsKey(k => k + 1);
 }
 }, [wsEvents, camp.id, loadCamp]);

 async function action(endpoint) {
 setBusy(true);
 try {
 await api(`/api/campaigns/${camp.id}/${endpoint}`, { method: "POST" });
 await loadCamp();
 } catch (e) { alert(e.message); }
 finally { setBusy(false); }
 }

 const agentName = agents.find(a => a.id === camp.agent_id)?.name || `Agent #${camp.agent_id}`;
 const live = stats || {};

 return (
 <div style={{ flex: 1, display: "flex", flexDirection: "column", gap: 0, minWidth: 0 }}>
 {/* Başlık */}
 <div style={{ display: "flex", alignItems: "center", gap: 12, marginBottom: 16, flexWrap: "wrap" }}>
 <button onClick={onBack} style={{
 background: "var(--surface2)", border: "1px solid var(--border)",
 color: "var(--text)", padding: "6px 12px", borderRadius: 8, cursor: "pointer", fontSize: 13,
 }}>← Geri</button>
 <div style={{ flex: 1 }}>
 <div style={{ display: "flex", alignItems: "center", gap: 10, flexWrap: "wrap" }}>
 <span style={{ fontSize: 18, fontWeight: 600 }}>{camp.name}</span>
 <StatusBadge status={camp.status} />
 <span style={{ fontSize: 12, color: "var(--text-dim)", background: "var(--surface2)", padding: "2px 8px", borderRadius: 8, border: "1px solid var(--border)" }}>
 {camp.mode === "predictive" ? " Predictive" : " Preview"}
 </span>
 <span style={{ fontSize: 12, color: "var(--text-dim)" }}>
 {camp.agent_type === "human" ? " Insan Temsilci" : ` ${agentName}`}
 </span>
 </div>
 {camp.description && (
 <div style={{ fontSize: 12, color: "var(--text-dim)", marginTop: 3 }}>{camp.description}</div>
 )}
 </div>

 {/* Kontrol butonları */}
 <div style={{ display: "flex", gap: 8 }}>
 {camp.status === "idle" || camp.status === "paused" ? (
 <button onClick={() => action("start")} disabled={busy} style={{
 background: "#22c55e22", border: "1px solid #22c55e55", color: "#22c55e",
 padding: "7px 16px", borderRadius: 8, cursor: "pointer", fontWeight: 700,
 }}> Başlat</button>
 ) : null}
 {camp.status === "running" ? (
 <button onClick={() => action("pause")} disabled={busy} style={{
 background: "#f59e0b22", border: "1px solid #f59e0b55", color: "#f59e0b",
 padding: "7px 16px", borderRadius: 8, cursor: "pointer", fontWeight: 700,
 }}> Duraklat</button>
 ) : null}
 {camp.status !== "idle" && camp.status !== "completed" ? (
 <button onClick={() => { if (confirm("Kampanya durdurulsun mu?")) action("stop"); }} disabled={busy} style={{
 background: "#ef444422", border: "1px solid #ef444455", color: "#ef4444",
 padding: "7px 16px", borderRadius: 8, cursor: "pointer", fontWeight: 700,
 }}> Durdur</button>
 ) : null}
 {camp.status !== "running" ? (
 <button onClick={() => { if (confirm("Tüm kişiler 'bekliyor' durumuna sıfırlansın mı?")) action("reset"); }} disabled={busy} style={{
 background: "var(--surface2)", border: "1px solid var(--border)", color: "var(--text)",
 padding: "7px 16px", borderRadius: 8, cursor: "pointer", fontWeight: 700,
 }}> Sıfırla</button>
 ) : null}
 </div>
 </div>

 {/* İstatistikler */}
 <div style={{ display: "flex", gap: 10, marginBottom: 20, flexWrap: "wrap" }}>
 <StatBox label="Toplam" value={camp.total_contacts} />
 <StatBox label="Bekliyor" value={live.pending ?? "—"} color="#9ca3af" />
 <StatBox label="Arıyor" value={live.calling ?? "—"} color="#60a5fa" />
 <StatBox label="Cevaplandı" value={live.answered ?? camp.answered_count} color="#86efac" />
 <StatBox label="Tamamlandı" value={live.completed ?? "—"} color="#3b82f6" />
 <StatBox label="Cevap Yok" value={live.no_answer ?? "—"} color="#fbbf24" />
 <StatBox label="Başarısız" value={camp.failed_count} color="#f87171" />
 </div>

 {/* Alt sekmeler */}
 <div style={{ display: "flex", gap: 8, marginBottom: 16 }}>
 {[["contacts", " Kişiler"], ["upload", " Yükle"]].map(([v, l]) => (
 <button key={v} onClick={() => setTab(v)} style={{
 background: tab === v ? "var(--primary)" : "var(--surface2)",
 border: tab === v ? "none" : "1px solid var(--border)",
 color: tab === v ? "#fff" : "var(--text)",
 padding: "6px 16px", borderRadius: 8, cursor: "pointer", fontWeight: 600, fontSize: 13,
 }}>{l}</button>
 ))}
 </div>

 {tab === "upload" && (
 <UploadPanel campaign={camp} onUploaded={() => { loadCamp(); setContactsKey(k => k + 1); }} />
 )}

 {tab === "contacts" && (
 <ContactsTable
 campaign={camp}
 refreshKey={contactsKey}
 onRefresh={() => { loadCamp(); setContactsKey(k => k + 1); }}
 />
 )}
 </div>
 );
 }

 // Kampanya listesi kartı 
 function CampaignCard({ campaign, agents, selected, onClick }) {
 const agentName = agents.find(a => a.id === campaign.agent_id)?.name || `Agent #${campaign.agent_id}`;
 const pct = campaign.total_contacts > 0
 ? Math.round(((campaign.called_count || 0) / campaign.total_contacts) * 100)
 : 0;

 return (
 <div
 onClick={onClick}
 style={{
 background: selected ? "var(--primary)22" : "var(--surface2)",
 border: `1px solid ${selected ? "var(--primary)" : "var(--border)"}`,
 borderRadius: 12, padding: "14px 16px", cursor: "pointer",
 marginBottom: 10, transition: "border-color .15s",
 }}
 >
 <div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-start", marginBottom: 6 }}>
 <div style={{ fontWeight: 700, fontSize: 14 }}>{campaign.name}</div>
 <StatusBadge status={campaign.status} />
 </div>
 <div style={{ fontSize: 12, color: "var(--text-dim)", marginBottom: 8 }}>
 {agentName} &nbsp;·&nbsp; {campaign.mode === "predictive" ? "Predictive" : "Preview"}
 </div>
 <div style={{ display: "flex", gap: 12, fontSize: 12, marginBottom: 8 }}>
 <span> {campaign.total_contacts} kişi</span>
 <span> {campaign.called_count || 0} aranan</span>
 <span> {campaign.answered_count || 0} cevap</span>
 </div>
 {campaign.total_contacts > 0 && (
 <div style={{ height: 4, background: "var(--border)", borderRadius: 4 }}>
 <div style={{ height: "100%", width: `${pct}%`, background: "var(--primary)", borderRadius: 4, transition: "width .3s" }} />
 </div>
 )}
 </div>
 );
 }

 // Ana DialerTab bileşeni 
 function DialerTab({ wsEvents }) {
 const [campaigns, setCampaigns] = useState([]);
 const [agents, setAgents] = useState([]);
 const [selected, setSelected] = useState(null);
 const [showNew, setShowNew] = useState(false);
 const [loading, setLoading] = useState(true);

 const loadAll = useCallback(async () => {
 try {
 const [camps, ags] = await Promise.all([
 api("/api/campaigns"),
 api("/api/agents"),
 ]);
 setCampaigns(Array.isArray(camps) ? camps : (camps.campaigns || []));
 setAgents(Array.isArray(ags) ? ags : (ags.agents || []));
 } catch (e) { console.error("Dialer yükleme hatası:", e); }
 finally { setLoading(false); }
 }, []);

 useEffect(() => { loadAll(); }, [loadAll]);

 // WS events: kampanya güncellemelerini dinle (liste yenileme)
 useEffect(() => {
 if (!wsEvents) return;
 const last = wsEvents[wsEvents.length - 1];
 if (!last) return;
 if (last.type === "dialer_campaign_update") {
 setCampaigns(prev => prev.map(c =>
 c.id === last.campaign_id ? { ...c, status: last.status ?? c.status, answered_count: last.answered ?? c.answered_count } : c
 ));
 }
 }, [wsEvents]);

 async function deleteCampaign(camp) {
 if (!confirm(`"${camp.name}" kampanyası silinsin mi? Tüm kişi verileri de silinir.`)) return;
 try {
 await api(`/api/campaigns/${camp.id}`, { method: "DELETE" });
 setCampaigns(prev => prev.filter(c => c.id !== camp.id));
 if (selected?.id === camp.id) setSelected(null);
 } catch (e) { alert(e.message); }
 }

 if (loading) return (
 <div style={{ display: "flex", alignItems: "center", justifyContent: "center", height: 200, color: "var(--text-dim)" }}>
 Yükleniyor…
 </div>
 );

 return (
 <div style={{ display: "flex", gap: 0, height: "100%", minHeight: 0 }}>
 {/* Sol panel: Kampanya listesi */}
 <div style={{
 width: 300, minWidth: 240, maxWidth: 340,
 borderRight: "1px solid var(--border)",
 display: "flex", flexDirection: "column",
 padding: "16px 14px",
 overflowY: "auto",
 }}>
 <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 14 }}>
 <div style={{ fontWeight: 600, fontSize: 16 }}> Dialer</div>
 <button onClick={() => setShowNew(true)} style={{
 background: "var(--primary)", border: "none", color: "#fff",
 padding: "6px 14px", borderRadius: 8, cursor: "pointer", fontWeight: 700, fontSize: 13,
 }}>+ Yeni</button>
 </div>

 {campaigns.length === 0 ? (
 <div style={{ color: "var(--text-dim)", fontSize: 13, textAlign: "center", marginTop: 40 }}>
 Henüz kampanya yok.<br />
 <span style={{ color: "var(--primary)", cursor: "pointer" }} onClick={() => setShowNew(true)}>Oluştur →</span>
 </div>
 ) : (
 campaigns.map(c => (
 <div key={c.id} style={{ position: "relative" }}>
 <CampaignCard
 campaign={c}
 agents={agents}
 selected={selected?.id === c.id}
 onClick={() => setSelected(c)}
 />
 <button
 onClick={e => { e.stopPropagation(); deleteCampaign(c); }}
 title="Sil"
 style={{
 position: "absolute", top: 10, right: 10,
 background: "none", border: "none", color: "var(--text-dim)",
 cursor: "pointer", fontSize: 14, padding: 0,
 opacity: 0.5,
 }}></button>
 </div>
 ))
 )}
 </div>

 {/* Sağ panel: Detay veya boş durum */}
 <div style={{ flex: 1, padding: "16px 20px", overflowY: "auto", display: "flex", flexDirection: "column" }}>
 {selected ? (
 <CampaignDetail
 key={selected.id}
 campaign={selected}
 agents={agents}
 onBack={() => setSelected(null)}
 wsEvents={wsEvents}
 />
 ) : (
 <div style={{
 flex: 1, display: "flex", alignItems: "center", justifyContent: "center",
 flexDirection: "column", gap: 16, color: "var(--text-dim)",
 }}>
  <div style={{ fontSize: 16, fontWeight: 700 }}>Outbound Dialer</div>
 <div style={{ fontSize: 13 }}>Sol panelden bir kampanya seçin veya yeni oluşturun.</div>
 <button onClick={() => setShowNew(true)} style={{
 background: "var(--primary)", border: "none", color: "#fff",
 padding: "10px 24px", borderRadius: 10, cursor: "pointer", fontWeight: 700, fontSize: 14,
 }}>+ Yeni Kampanya</button>
 </div>
 )}
 </div>

 {showNew && (
 <NewCampaignModal
 agents={agents}
 onClose={() => setShowNew(false)}
 onSaved={(newCamp) => {
 setCampaigns(prev => [newCamp, ...prev]);
 setShowNew(false);
 setSelected(newCamp);
 }}
 />
 )}
 </div>
 );
 }

 window.DialerTab = DialerTab;
})();
