// ---------- Do-not-call list (admins + clients) ----------
// Numbers every blast, retry and reblast skips, plus the calling rules all
// outbound calls follow (GET/POST/DELETE /contact-policy). Entries come from
// the post-call AI review (wrong number, asked not to be called, deceased,
// dispute) or are added by hand; removed entries stay as history.

const DNC_TEXT = {
  en: {
    title: "Do-not-call list",
    subtitle: "Numbers your blasts will not call again, and the calling rules every outbound call follows",
    rules: "Calling rules",
    window: "Calling hours",
    windowNow: (open) => (open ? "open now" : "closed now — calls wait until it opens"),
    attempts: "Max dial attempts per number per day",
    conversations: "Max conversations with the same person per 7 days",
    notAvailable: "Someone else answered (debtor not there): call again after",
    hours: "hours",
    noLimit: "no limit",
    add: "Add number",
    client: "Client",
    phone: "Phone number",
    reason: "Reason",
    customer: "Customer name",
    account: "Account no.",
    note: "Note",
    save: "Add to list",
    cancel: "Cancel",
    showRemoved: "Show removed / expired",
    search: "Search number, name, account",
    added: "Added",
    expires: "Expires",
    never: "never",
    source: "Source",
    aiReview: "AI call review",
    remove: "Remove",
    removed: "Removed",
    expired: "Expired",
    active: "Active",
    empty: "No numbers on the list.",
    confirmRemove: (p) => `Take ${p} off the do-not-call list? Future blasts will call it again.`,
    howItWorks: "Numbers are added automatically when the AI call review finds a wrong number, a request not to be called, a deceased account holder, or a disputed debt. Wrong numbers expire after 180 days because mobile numbers get reassigned; disputes are held for 30 days. A number listed for one customer is only skipped for that customer — if a later upload has a different name or account on the same number, it is called but flagged.",
  },
  ms: {
    title: "Senarai jangan hubungi",
    subtitle: "Nombor yang tidak akan dihubungi lagi oleh blast anda, dan peraturan panggilan untuk semua panggilan keluar",
    rules: "Peraturan panggilan",
    window: "Waktu panggilan",
    windowNow: (open) => (open ? "dibuka sekarang" : "ditutup sekarang — panggilan menunggu sehingga dibuka"),
    attempts: "Maksimum cubaan dail setiap nombor sehari",
    conversations: "Maksimum perbualan dengan orang yang sama dalam 7 hari",
    notAvailable: "Orang lain menjawab (penghutang tiada): hubungi semula selepas",
    hours: "jam",
    noLimit: "tiada had",
    add: "Tambah nombor",
    client: "Klien",
    phone: "Nombor telefon",
    reason: "Sebab",
    customer: "Nama pelanggan",
    account: "No. akaun",
    note: "Nota",
    save: "Tambah ke senarai",
    cancel: "Batal",
    showRemoved: "Tunjuk yang dibuang / tamat tempoh",
    search: "Cari nombor, nama, akaun",
    added: "Ditambah",
    expires: "Tamat",
    never: "tiada",
    source: "Sumber",
    aiReview: "Semakan panggilan AI",
    remove: "Buang",
    removed: "Dibuang",
    expired: "Tamat tempoh",
    active: "Aktif",
    empty: "Tiada nombor dalam senarai.",
    confirmRemove: (p) => `Buang ${p} daripada senarai jangan hubungi? Blast akan datang akan menghubunginya semula.`,
    howItWorks: "Nombor ditambah secara automatik apabila semakan panggilan AI mendapati nombor salah, permintaan supaya tidak dihubungi, pemegang akaun telah meninggal dunia, atau hutang dipertikaikan. Nombor salah tamat selepas 180 hari kerana nombor telefon boleh bertukar pemilik; pertikaian ditangguhkan 30 hari. Nombor yang disenaraikan untuk seorang pelanggan hanya dilangkau untuk pelanggan itu — jika muat naik kemudian mempunyai nama atau akaun berbeza pada nombor yang sama, ia akan dihubungi tetapi ditandakan.",
  },
};

function DoNotCallView({ mode, clients = [], lang = "en" }) {
  const L = DNC_TEXT[lang === "ms" ? "ms" : "en"];
  const isAdmin = mode !== "client";
  const [data, setData] = React.useState(null);
  const [err, setErr] = React.useState("");
  const [loading, setLoading] = React.useState(false);
  const [reloadKey, setReloadKey] = React.useState(0);
  const [showRemoved, setShowRemoved] = React.useState(false);
  const [clientFilter, setClientFilter] = React.useState("");
  const [search, setSearch] = React.useState("");
  const [showAdd, setShowAdd] = React.useState(false);
  const [form, setForm] = React.useState({ clientId: "", phone: "", reason: "do_not_call", customerName: "", account: "", note: "" });
  const [saving, setSaving] = React.useState(false);

  React.useEffect(() => {
    let cancelled = false;
    setLoading(true);
    const params = new URLSearchParams();
    if (showRemoved) params.set("all", "1");
    if (clientFilter) params.set("clientId", clientFilter);
    voxApi(`/contact-policy?${params.toString()}`)
      .then((res) => { if (!cancelled) { setData(res); setErr(""); } })
      .catch((e) => { if (!cancelled) setErr(e.message); })
      .finally(() => { if (!cancelled) setLoading(false); });
    return () => { cancelled = true; };
  }, [showRemoved, clientFilter, reloadKey]);

  const reasonLabel = (key) => {
    const r = data?.reasons?.[key];
    return r ? (lang === "ms" ? r.labelMs : r.label) : key;
  };
  const reasonTone = (key) => (key === "wrong_number" ? "warn" : key === "dispute" ? "accent" : "err");
  const fmtDate = (iso) => (iso ? new Date(iso).toLocaleDateString("en-MY", { day: "numeric", month: "short", year: "numeric" }) : "—");

  const entries = React.useMemo(() => {
    const q = search.trim().toLowerCase();
    return (data?.entries || []).filter((e) => !q
      || [e.phone, e.customerName, e.account, e.clientName].some((v) => String(v || "").toLowerCase().includes(q)));
  }, [data, search]);

  async function save() {
    if (!form.phone.trim()) return;
    if (isAdmin && !form.clientId) { alert(L.client); return; }
    setSaving(true);
    try {
      await voxApi("/contact-policy", { method: "POST", body: JSON.stringify(form) });
      setShowAdd(false);
      setForm({ clientId: "", phone: "", reason: "do_not_call", customerName: "", account: "", note: "" });
      setReloadKey((k) => k + 1);
    } catch (e) {
      alert(e.message);
    } finally {
      setSaving(false);
    }
  }

  async function remove(entry) {
    if (!window.confirm(L.confirmRemove(entry.phone))) return;
    try {
      await voxApi(`/contact-policy/${encodeURIComponent(entry.id)}`, { method: "DELETE" });
      setReloadKey((k) => k + 1);
    } catch (e) {
      alert(e.message);
    }
  }

  const rules = data?.rules;
  const sortedClients = [...clients].sort((a, b) => String(a.company || a.name).localeCompare(String(b.company || b.name)));

  return (
    <div>
      <div className="ph">
        <div>
          <h1 className="ph-title">{L.title}</h1>
          <div className="ph-subtitle">{L.subtitle}</div>
        </div>
        <div className="ph-actions">
          <Btn variant="ghost" icon="refresh" size="sm" onClick={() => setReloadKey((k) => k + 1)} disabled={loading} />
          <Btn variant="primary" icon="plus" size="sm" onClick={() => setShowAdd((v) => !v)}>{L.add}</Btn>
        </div>
      </div>

      {rules && (
        <Card title={L.rules} style={{ marginBottom: 16 }}>
          <div className="stat-grid" style={{ gridTemplateColumns: "repeat(auto-fit, minmax(200px, 1fr))" }}>
            <div className="stat">
              <div className="stat-label">{L.window}</div>
              <div className="stat-value" style={{ fontSize: 20 }}>{String(rules.windowStartHour).padStart(2, "0")}:00 – {String(rules.windowEndHour).padStart(2, "0")}:00</div>
              <div className="text-11 mt-2" style={{ color: rules.window?.open ? "var(--ok)" : "var(--warn)" }}>{L.windowNow(rules.window?.open)}</div>
            </div>
            <div className="stat">
              <div className="stat-label">{L.attempts}</div>
              <div className="stat-value" style={{ fontSize: 20 }}>{rules.maxAttemptsPerDay > 0 ? rules.maxAttemptsPerDay : L.noLimit}</div>
            </div>
            <div className="stat">
              <div className="stat-label">{L.conversations}</div>
              <div className="stat-value" style={{ fontSize: 20 }}>{rules.maxConversationsPerWeek > 0 ? rules.maxConversationsPerWeek : L.noLimit}</div>
            </div>
            <div className="stat">
              <div className="stat-label">{L.notAvailable}</div>
              <div className="stat-value" style={{ fontSize: 20 }}>{rules.notAvailableRetryHours} {L.hours}</div>
            </div>
          </div>
          <div className="muted text-11 mt-3">{L.howItWorks}</div>
        </Card>
      )}

      {showAdd && (
        <Card title={L.add} style={{ marginBottom: 16 }}>
          <div className="row gap-3" style={{ flexWrap: "wrap", alignItems: "flex-end" }}>
            {isAdmin && (
              <Field label={L.client}>
                <Select value={form.clientId} onChange={(e) => setForm({ ...form, clientId: e.target.value })}>
                  <option value="">—</option>
                  {sortedClients.map((c) => <option key={c.id} value={c.id}>{c.company || c.name}</option>)}
                </Select>
              </Field>
            )}
            <Field label={L.phone}><Input value={form.phone} placeholder="+60123456789" onChange={(e) => setForm({ ...form, phone: e.target.value })} /></Field>
            <Field label={L.reason}>
              <Select value={form.reason} onChange={(e) => setForm({ ...form, reason: e.target.value })}>
                {Object.keys(data?.reasons || {}).map((k) => <option key={k} value={k}>{reasonLabel(k)}</option>)}
              </Select>
            </Field>
            <Field label={L.customer}><Input value={form.customerName} onChange={(e) => setForm({ ...form, customerName: e.target.value })} /></Field>
            <Field label={L.account}><Input value={form.account} onChange={(e) => setForm({ ...form, account: e.target.value })} /></Field>
            <Field label={L.note}><Input value={form.note} onChange={(e) => setForm({ ...form, note: e.target.value })} /></Field>
            <Btn variant="primary" size="sm" onClick={save} disabled={saving || !form.phone.trim()}>{L.save}</Btn>
            <Btn variant="ghost" size="sm" onClick={() => setShowAdd(false)}>{L.cancel}</Btn>
          </div>
        </Card>
      )}

      <Card style={{ marginBottom: 16 }}>
        <div className="row gap-3" style={{ flexWrap: "wrap", alignItems: "flex-end" }}>
          {isAdmin && (
            <Field label={L.client}>
              <Select value={clientFilter} onChange={(e) => setClientFilter(e.target.value)}>
                <option value="">All</option>
                {sortedClients.map((c) => <option key={c.id} value={c.id}>{c.company || c.name}</option>)}
              </Select>
            </Field>
          )}
          <Field label=" "><Input value={search} placeholder={L.search} onChange={(e) => setSearch(e.target.value)} /></Field>
          <label className="row gap-2 text-12" style={{ alignItems: "center", paddingBottom: 8 }}>
            <Toggle checked={showRemoved} onChange={setShowRemoved} /> {L.showRemoved}
          </label>
          <div className="muted text-12" style={{ marginLeft: "auto" }}>{loading ? "…" : `${entries.length}`}</div>
        </div>
      </Card>

      {err && <div className="text-12 mb-3" style={{ color: "var(--err)" }}>{err}</div>}

      <Card pad="none">
        <div style={{ overflowX: "auto" }}>
          <table className="tbl">
            <thead>
              <tr>
                <th>{L.phone}</th>
                {isAdmin && <th>{L.client}</th>}
                <th>{L.customer}</th><th>{L.account}</th><th>{L.reason}</th>
                <th>{L.source}</th><th>{L.added}</th><th>{L.expires}</th><th />
              </tr>
            </thead>
            <tbody>
              {entries.map((e) => (
                <tr key={e.id} style={e.active ? undefined : { opacity: 0.55 }}>
                  <td className="mono text-12 strong">{e.phone}</td>
                  {isAdmin && <td className="text-12">{e.clientName}</td>}
                  <td className="text-12">{e.customerName || "—"}</td>
                  <td className="mono text-12">{e.account || "—"}</td>
                  <td className="text-12"><Badge tone={reasonTone(e.reason)}>{reasonLabel(e.reason)}</Badge></td>
                  <td className="text-11 muted" title={e.note || ""}>
                    {e.auto ? L.aiReview : (e.createdBy || "—")}
                    {e.sourceCallIds?.length ? <div className="mono">{e.sourceCallIds[e.sourceCallIds.length - 1]}</div> : null}
                  </td>
                  <td className="text-12">{fmtDate(e.createdAt)}</td>
                  <td className="text-12">
                    {e.removedAt ? `${L.removed} ${fmtDate(e.removedAt)}${e.removedBy ? ` · ${e.removedBy}` : ""}`
                      : !e.active ? `${L.expired} ${fmtDate(e.expiresAt)}`
                      : e.expiresAt ? fmtDate(e.expiresAt) : L.never}
                  </td>
                  <td className="right">
                    {e.active && <Btn variant="ghost" size="sm" onClick={() => remove(e)}>{L.remove}</Btn>}
                  </td>
                </tr>
              ))}
              {entries.length === 0 && <tr><td colSpan={isAdmin ? 9 : 8} className="muted text-12">{L.empty}</td></tr>}
            </tbody>
          </table>
        </div>
      </Card>
    </div>
  );
}

Object.assign(window, { DoNotCallView });
