// ============================================================================
// public/screens/settings.jsx — Settings (BYOI + BYOK extended)
// ----------------------------------------------------------------------------
// Tabs:
//   Workspace · Telephony · AI Providers · SIP Trunks · SIMs · Caller IDs
//   · AI Defaults · Training · Team · API Keys · Compliance · Notifications
//
// Component reuse: Tabs, Field, Btn, Card, Badge, DashboardSkeleton, Toggle,
// I (icons) — all globals from public/core/ui.jsx.
// VoaisAPI is the fetch helper from public/core/api.js.
//
// All read endpoints return masked secrets (api_key_mask, ami_secret_set,
// etc) so the browser never holds plaintext. The PATCH endpoints accept an
// empty-string secret to mean "leave as-is", so re-saving the form doesn't
// accidentally wipe a stored secret.
// ============================================================================

function SettingsScreen() {
  const [tab, setTab] = React.useState("workspace");
  const tabs = [
    { value: "workspace",    label: "Workspace"     },
    { value: "telephony",    label: "Telephony"     },
    { value: "ai-providers", label: "AI Providers"  },
    { value: "sip-trunks",   label: "SIP Trunks"    },
    { value: "sims",         label: "SIMs"          },
    { value: "caller-ids",   label: "Caller IDs"    },
    { value: "ai-defaults",  label: "AI Defaults"   },
    { value: "training",     label: "Training"      },
    { value: "team",         label: "Team"          },
    { value: "api-keys",     label: "API Keys"      },
    { value: "compliance",   label: "Compliance"    },
    { value: "notifications",label: "Notifications" },
  ];
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: "var(--gap-grid)" }}>
      <Tabs value={tab} onChange={setTab} options={tabs}/>
      {tab === "workspace"     && <WorkspaceTab/>}
      {tab === "telephony"     && <TelephonyTab/>}
      {tab === "ai-providers"  && <AiProvidersTab/>}
      {tab === "sip-trunks"    && <SipTrunksTab/>}
      {tab === "sims"          && <SimsTab/>}
      {tab === "caller-ids"    && <CallerIdsTab/>}
      {tab === "ai-defaults"   && <AiDefaultsTab/>}
      {tab === "training"      && <TrainingTab/>}
      {tab === "team"          && <TeamTab/>}
      {tab === "api-keys"      && <ApiKeysTab/>}
      {tab === "compliance"    && <ComplianceTab/>}
      {tab === "notifications" && <NotificationsTab/>}
    </div>
  );
}

// ─── tiny helper for save status pills ──────────────────────────────────
function SaveStatus({ status }) {
  if (!status) return null;
  const tone = status.ok ? "green" : "red";
  return <Badge tone={tone}>{status.msg}</Badge>;
}

function SectionHead({ title, subtitle, right }) {
  return (
    <div style={{ display: "flex", alignItems: "flex-end", gap: 12, marginBottom: 4 }}>
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{ fontSize: 14, fontWeight: 600 }}>{title}</div>
        {subtitle && <div style={{ fontSize: 11.5, color: "var(--ink-3)", marginTop: 2 }}>{subtitle}</div>}
      </div>
      {right}
    </div>
  );
}

// VoiceSelect — small dropdown that pulls voices for `providerKey` out of
// the AI providers list (which itself comes from the voices_catalog table).
// Falls back to a text input if no voices are seeded yet for that provider,
// so adding a new provider doesn't require a UI change.
function VoiceSelect({ providers, providerKey, value, onChange, fallbackPlaceholder }) {
  const provider = (providers || []).find(p => p.key === providerKey);
  const voices = (provider && provider.voices) || [];
  if (voices.length === 0) {
    return <input className="input" placeholder={fallbackPlaceholder || "voice id"} value={value || ""} onChange={e => onChange(e.target.value)}/>;
  }
  return (
    <select className="select" value={value || ""} onChange={e => onChange(e.target.value)}>
      <option value="">— pick a voice —</option>
      {voices.map(v => (
        <option key={v.id} value={v.id}>
          {v.name} · {v.gender} · {v.language}{v.tier === "premium" ? " · premium" : ""}
        </option>
      ))}
    </select>
  );
}

// ════════════════════════════════════════════════════════════════════════
// WORKSPACE
// ════════════════════════════════════════════════════════════════════════
function WorkspaceTab() {
  const [ws, setWs] = React.useState(null);
  const [saving, setSaving] = React.useState(false);
  const [status, setStatus] = React.useState(null);
  React.useEffect(() => {
    VoaisAPI.get("/api/settings/workspace").then(r => {
      if (r.ok && r.data?.ok) setWs(r.data.workspace);
    });
  }, []);
  const save = async () => {
    setSaving(true); setStatus(null);
    const r = await VoaisAPI.patch("/api/settings/workspace", {
      name: ws.name, timezone: ws.timezone, logo_url: ws.logo_url,
      currency: ws.currency, default_language: ws.default_language,
      industry: ws.industry, country: ws.country,
      phone: ws.phone, email: ws.email, accent_hex: ws.accent_hex,
    });
    setSaving(false);
    setStatus(r.ok ? { ok: true, msg: "Saved" } : { ok: false, msg: "Save failed" });
    setTimeout(() => setStatus(null), 2500);
  };
  if (!ws) return <DashboardSkeleton/>;
  const upd = (k, v) => setWs({ ...ws, [k]: v });
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: "var(--gap-grid)" }}>
      <Card>
        <SectionHead title="Workspace identity" subtitle="Display name, branding, and locale." right={<SaveStatus status={status}/>}/>
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12, marginTop: 12, maxWidth: 720 }}>
          <Field label="Company name">
            <input className="input" value={ws.name || ""} onChange={e => upd("name", e.target.value)}/>
          </Field>
          <Field label="Slug" hint="Read-only — used in URLs and login.">
            <input className="input" value={ws.slug || ""} disabled style={{ opacity: 0.5 }}/>
          </Field>
          <Field label="Logo URL">
            <input className="input" value={ws.logo_url || ""} onChange={e => upd("logo_url", e.target.value)} placeholder="https://..."/>
          </Field>
          <Field label="Accent colour (hex)" hint="Used for buttons, highlights.">
            <input className="input" value={ws.accent_hex || "#3B7BFF"} onChange={e => upd("accent_hex", e.target.value)} placeholder="#3B7BFF"/>
          </Field>
        </div>
      </Card>

      <Card>
        <SectionHead title="Contact" subtitle="Used on invoices and outgoing emails."/>
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12, marginTop: 12, maxWidth: 720 }}>
          <Field label="Email">
            <input className="input" type="email" value={ws.email || ""} onChange={e => upd("email", e.target.value)} placeholder="hello@company.com"/>
          </Field>
          <Field label="Phone">
            <input className="input" value={ws.phone || ""} onChange={e => upd("phone", e.target.value)} placeholder="+91..."/>
          </Field>
        </div>
      </Card>

      <Card>
        <SectionHead title="Locale & business" subtitle="Default timezone, currency, language and industry."/>
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12, marginTop: 12, maxWidth: 720 }}>
          <Field label="Timezone">
            <input className="input" value={ws.timezone || "Asia/Kolkata"} onChange={e => upd("timezone", e.target.value)}/>
          </Field>
          <Field label="Currency">
            <select className="select" value={ws.currency || "INR"} onChange={e => upd("currency", e.target.value)}>
              <option value="INR">INR (₹)</option>
              <option value="USD">USD ($)</option>
              <option value="EUR">EUR (€)</option>
              <option value="GBP">GBP (£)</option>
              <option value="AED">AED</option>
              <option value="SGD">SGD</option>
            </select>
          </Field>
          <Field label="Default language" hint="Used for new agents and replies.">
            <select className="select" value={ws.default_language || "hinglish"} onChange={e => upd("default_language", e.target.value)}>
              <option value="hinglish">Hinglish</option>
              <option value="hindi">Hindi</option>
              <option value="english">English</option>
              <option value="tamil">Tamil</option>
              <option value="telugu">Telugu</option>
              <option value="bengali">Bengali</option>
              <option value="marathi">Marathi</option>
              <option value="gujarati">Gujarati</option>
              <option value="kannada">Kannada</option>
              <option value="malayalam">Malayalam</option>
              <option value="punjabi">Punjabi</option>
            </select>
          </Field>
          <Field label="Country">
            <select className="select" value={ws.country || "IN"} onChange={e => upd("country", e.target.value)}>
              <option value="IN">India</option>
              <option value="US">United States</option>
              <option value="GB">United Kingdom</option>
              <option value="AE">UAE</option>
              <option value="SG">Singapore</option>
              <option value="CA">Canada</option>
              <option value="AU">Australia</option>
            </select>
          </Field>
          <Field label="Industry">
            <input className="input" value={ws.industry || ""} onChange={e => upd("industry", e.target.value)} placeholder="e.g. Real Estate, EdTech, Healthcare"/>
          </Field>
          <Field label="Account status">
            <input className="input" value={ws.status || "trial"} disabled style={{ opacity: 0.5 }}/>
          </Field>
        </div>
      </Card>

      <Card>
        <Btn kind="primary" onClick={save} disabled={saving}>
          {saving ? "Saving…" : "Save workspace settings"}
        </Btn>
      </Card>
    </div>
  );
}

// ════════════════════════════════════════════════════════════════════════
// TELEPHONY (BYOI Asterisk / Dinstar)
// ════════════════════════════════════════════════════════════════════════
function TelephonyTab() {
  const [cfg, setCfg] = React.useState(null);
  const [platform, setPlat] = React.useState(null);
  const [saving, setSaving] = React.useState(false);
  const [testing, setTesting] = React.useState(false);
  const [status, setStatus] = React.useState(null);
  const [testResult, setTestResult] = React.useState(null);

  // Track which secret inputs the user has typed into this session — if
  // they haven't touched it, we send "" on save which the API reads as
  // "leave as-is", protecting the existing stored secret.
  const [secretsTouched, setTouched] = React.useState({ ami_secret: false, ari_password: false });
  const [secrets, setSecrets] = React.useState({ ami_secret: "", ari_password: "" });

  const load = React.useCallback(() => {
    VoaisAPI.get("/api/settings/telephony").then(r => {
      if (r.ok && r.data?.ok) {
        setCfg(r.data.config);
        setPlat(r.data.platform_preview || null);
      }
    });
  }, []);
  React.useEffect(() => { load(); }, [load]);

  if (!cfg) return <DashboardSkeleton/>;

  const setField = (k, v) => setCfg({ ...cfg, [k]: v });

  const save = async () => {
    setSaving(true); setStatus(null);
    const payload = {
      mode: cfg.mode,
      ami_host: cfg.ami_host, ami_port: cfg.ami_port, ami_user: cfg.ami_user,
      ari_url: cfg.ari_url, ari_user: cfg.ari_user, ari_app: cfg.ari_app,
      external_media_host: cfg.external_media_host, external_media_port: cfg.external_media_port,
      trunk: cfg.trunk, ai_context: cfg.ai_context, dial_context: cfg.dial_context,
      dinstar_ip: cfg.dinstar_ip, gsm_ports: cfg.gsm_ports, gsm_prefix_template: cfg.gsm_prefix_template,
    };
    if (secretsTouched.ami_secret)  payload.ami_secret  = secrets.ami_secret;
    if (secretsTouched.ari_password) payload.ari_password = secrets.ari_password;
    const r = await VoaisAPI.patch("/api/settings/telephony", payload);
    setSaving(false);
    if (r.ok) {
      setStatus({ ok: true, msg: "Saved" });
      setSecrets({ ami_secret: "", ari_password: "" });
      setTouched({ ami_secret: false, ari_password: false });
      load();
    } else {
      setStatus({ ok: false, msg: r.data?.msg || "Save failed" });
    }
    setTimeout(() => setStatus(null), 2500);
  };

  const runTest = async () => {
    setTesting(true); setTestResult(null);
    const r = await VoaisAPI.post("/api/settings/telephony/test");
    setTesting(false);
    setTestResult({ ok: r.ok && r.data?.ok, msg: r.data?.msg || (r.ok ? "OK" : "Test failed"), ms: r.data?.ms });
    load();
  };

  const isSelf = cfg.mode === "self";

  return (
    <div style={{ display: "flex", flexDirection: "column", gap: "var(--gap-grid)" }}>
      <ConnectionStatusCard/>
      <Card>
        <SectionHead
          title="Telephony — Bring Your Own Infrastructure"
          subtitle="Choose whether this workspace dials through the shared platform Asterisk, or your own."
          right={<SaveStatus status={status}/>}
        />
        <div style={{ display: "flex", gap: 8, marginTop: 14 }}>
          <ModeCard
            active={cfg.mode === "platform"}
            onClick={() => setField("mode", "platform")}
            title="Use Platform Asterisk"
            desc="Use the shared platform GSM gateway. Easiest — nothing to configure."
            preview={platform ? `${platform.ami_host}:${platform.ami_port}` : null}
          />
          <ModeCard
            active={cfg.mode === "self"}
            onClick={() => setField("mode", "self")}
            title="Bring Your Own Asterisk"
            desc="Point us at your Asterisk + Dinstar. Full control, full responsibility."
          />
        </div>
      </Card>

      <WireGuardCard onEnrolled={load}/>

      {isSelf && (
        <Card>
          <SectionHead
            title="Asterisk AMI"
            subtitle="Manager interface — we use this to originate and hang up calls."
          />
          <div style={{ display: "grid", gridTemplateColumns: "2fr 1fr", gap: 12, marginTop: 12 }}>
            <Field label="AMI host">
              <input className="input" placeholder="e.g. 10.0.0.5 or asterisk.mycompany.com"
                value={cfg.ami_host || ""} onChange={e => setField("ami_host", e.target.value)}/>
            </Field>
            <Field label="AMI port">
              <input className="input" type="number" value={cfg.ami_port || 5038}
                onChange={e => setField("ami_port", Number(e.target.value))}/>
            </Field>
          </div>
          <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12 }}>
            <Field label="AMI username">
              <input className="input" placeholder="voiceapp" value={cfg.ami_user || ""}
                onChange={e => setField("ami_user", e.target.value)}/>
            </Field>
            <Field label="AMI secret" hint={cfg.ami_secret_set ? "A secret is saved. Type a new one to replace it." : "Not set"}>
              <input className="input" type="password" autoComplete="new-password"
                placeholder={cfg.ami_secret_set ? "•••• saved ••••" : ""}
                value={secrets.ami_secret}
                onChange={e => { setSecrets({ ...secrets, ami_secret: e.target.value }); setTouched({ ...secretsTouched, ami_secret: true }); }}/>
            </Field>
          </div>
        </Card>
      )}

      {isSelf && (
        <Card>
          <SectionHead
            title="Asterisk ARI"
            subtitle="Stasis app for AI calls — handles the external-media bridge."
          />
          <div style={{ display: "grid", gridTemplateColumns: "2fr 1fr", gap: 12, marginTop: 12 }}>
            <Field label="ARI URL">
              <input className="input" placeholder="http://10.0.0.5:8088" value={cfg.ari_url || ""}
                onChange={e => setField("ari_url", e.target.value)}/>
            </Field>
            <Field label="ARI app name">
              <input className="input" placeholder="voicegsm" value={cfg.ari_app || ""}
                onChange={e => setField("ari_app", e.target.value)}/>
            </Field>
          </div>
          <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12 }}>
            <Field label="ARI user">
              <input className="input" placeholder="voiceari" value={cfg.ari_user || ""}
                onChange={e => setField("ari_user", e.target.value)}/>
            </Field>
            <Field label="ARI password" hint={cfg.ari_password_set ? "A password is saved." : "Not set"}>
              <input className="input" type="password" autoComplete="new-password"
                placeholder={cfg.ari_password_set ? "•••• saved ••••" : ""}
                value={secrets.ari_password}
                onChange={e => { setSecrets({ ...secrets, ari_password: e.target.value }); setTouched({ ...secretsTouched, ari_password: true }); }}/>
            </Field>
          </div>

          <SectionHead
            title="External media"
            subtitle="Where Asterisk sends RTP audio for AI calls. Must be reachable from your Asterisk box."
          />
          <div style={{ display: "grid", gridTemplateColumns: "2fr 1fr", gap: 12, marginTop: 12 }}>
            <Field label="Host">
              <input className="input" placeholder="10.0.0.10 or media.mycompany.com"
                value={cfg.external_media_host || ""}
                onChange={e => setField("external_media_host", e.target.value)}/>
            </Field>
            <Field label="Port">
              <input className="input" type="number" value={cfg.external_media_port || 12000}
                onChange={e => setField("external_media_port", Number(e.target.value))}/>
            </Field>
          </div>

          <SectionHead
            title="Dialplan contexts"
            subtitle="From your extensions.conf — must already exist on the Asterisk box."
          />
          <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 12, marginTop: 12 }}>
            <Field label="Trunk">
              <input className="input" placeholder="1111" value={cfg.trunk || ""}
                onChange={e => setField("trunk", e.target.value)}/>
            </Field>
            <Field label="AI context">
              <input className="input" placeholder="gsm-ai-out" value={cfg.ai_context || ""}
                onChange={e => setField("ai_context", e.target.value)}/>
            </Field>
            <Field label="Dial context">
              <input className="input" placeholder="gsm-out" value={cfg.dial_context || ""}
                onChange={e => setField("dial_context", e.target.value)}/>
            </Field>
          </div>
        </Card>
      )}

      <Card>
        <SectionHead
          title="Dinstar GSM gateway"
          subtitle="Used to format outbound numbers with the right per-port prefix."
        />
        <div style={{ display: "grid", gridTemplateColumns: "2fr 1fr 1fr", gap: 12, marginTop: 12 }}>
          <Field label="Dinstar IP" hint="Informational — actual SIP routing happens via Asterisk pjsip.conf">
            <input className="input" placeholder="192.168.1.220" value={cfg.dinstar_ip || ""}
              onChange={e => setField("dinstar_ip", e.target.value)}/>
          </Field>
          <Field label="GSM ports" hint="CSV, e.g. 30,31">
            <input className="input" placeholder="30,31" value={cfg.gsm_ports || ""}
              onChange={e => setField("gsm_ports", e.target.value)}/>
          </Field>
          <Field label="Prefix template" hint="e.g. '70' means port 30 → prefix '7030'">
            <input className="input" placeholder="70" value={cfg.gsm_prefix_template || ""}
              onChange={e => setField("gsm_prefix_template", e.target.value)}/>
          </Field>
        </div>
      </Card>

      <Card>
        <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
          <Btn kind="primary" onClick={save} disabled={saving}>{saving ? "Saving…" : "Save changes"}</Btn>
          <Btn kind="ghost" onClick={runTest} disabled={testing || saving}>
            {testing ? "Testing…" : "Test connection"}
          </Btn>
          {testResult && (
            <Badge tone={testResult.ok ? "green" : "red"}>
              {testResult.ok ? `OK (${testResult.ms || 0}ms)` : testResult.msg}
            </Badge>
          )}
          {!testResult && cfg.last_test_at && (
            <span style={{ fontSize: 11.5, color: "var(--ink-3)" }}>
              Last test {new Date(cfg.last_test_at).toLocaleString("en-IN")} —
              {" "}<Badge tone={cfg.last_test_status === "ok" ? "green" : (cfg.last_test_status === "failed" ? "red" : "gray")}>
                {cfg.last_test_status}
              </Badge>
            </span>
          )}
        </div>
      </Card>
    </div>
  );
}

// Live connection indicators — WireGuard tunnel, AMI, ARI, GSM trunk. Each
// check runs server-side and is shown as a coloured dot so an operator can see
// at a glance what's connected.
function ConnectionStatusCard() {
  const [data, setData] = React.useState(null);
  const [loading, setLoading] = React.useState(false);

  const check = React.useCallback(() => {
    setLoading(true);
    VoaisAPI.get("/api/settings/telephony/status").then(r => {
      setLoading(false);
      if (r.ok && r.data?.ok) setData(r.data);
      else setData({ error: r.data?.msg || "Status check failed" });
    });
  }, []);
  React.useEffect(() => { check(); }, [check]);

  const ITEMS = [
    { key: "tunnel", label: "WireGuard tunnel" },
    { key: "ami",    label: "Asterisk AMI" },
    { key: "ari",    label: "Asterisk ARI" },
    { key: "gsm",    label: "GSM trunk" },
  ];
  const dot = (state) => {
    const c = state === "up" ? "var(--ok)" : state === "off" ? "var(--ink-3)"
            : state === "unknown" ? "var(--warn)" : "var(--err)";
    return <span style={{ width: 9, height: 9, borderRadius: 5, background: c, display: "inline-block",
      boxShadow: state === "up" ? "0 0 0 3px rgba(0,212,159,0.18)" : "none", flex: "0 0 auto" }}/>;
  };

  return (
    <Card>
      <SectionHead
        title="Connection status"
        subtitle="Live health of the link between this workspace and your GSM."
        right={
          <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
            {data && !data.error && (
              <Badge tone={data.allOk ? "green" : "red"}>{data.allOk ? "All systems go" : "Action needed"}</Badge>
            )}
            <Btn kind="ghost" size="sm" onClick={check} disabled={loading}>{loading ? "Checking…" : "Re-check"}</Btn>
          </div>
        }
      />
      {data?.error && <div style={{ marginTop: 10, fontSize: 12.5, color: "var(--err)" }}>{data.error}</div>}
      <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit,minmax(200px,1fr))", gap: 10, marginTop: 14 }}>
        {ITEMS.map(it => {
          const c = data && data.checks ? data.checks[it.key] : null;
          return (
            <div key={it.key} style={{ display: "flex", gap: 10, alignItems: "flex-start",
              padding: "10px 12px", border: "1px solid var(--line)", borderRadius: "var(--r-sm)", background: "var(--surface-2)" }}>
              <div style={{ marginTop: 4 }}>{dot(c ? c.state : (loading ? "unknown" : "down"))}</div>
              <div style={{ minWidth: 0 }}>
                <div style={{ fontSize: 12.5, fontWeight: 600 }}>{it.label}</div>
                <div style={{ fontSize: 11, color: "var(--ink-3)", marginTop: 2, wordBreak: "break-word" }}>
                  {c ? c.detail : (loading ? "Checking…" : "—")}
                </div>
              </div>
            </div>
          );
        })}
      </div>
    </Card>
  );
}

// WireGuard tunnel — self-service GSM onboarding. Tenant pastes their edge
// box's public key; the server assigns an overlay IP and registers the peer.
function WireGuardCard({ onEnrolled }) {
  const [st, setSt] = React.useState(null);     // server status payload
  const [pubkey, setPubkey] = React.useState("");
  const [busy, setBusy] = React.useState(false);
  const [err, setErr] = React.useState(null);

  const load = React.useCallback(() => {
    VoaisAPI.get("/api/settings/telephony/wireguard").then(r => {
      if (r.ok && r.data?.ok) setSt(r.data);
    });
  }, []);
  React.useEffect(() => { load(); }, [load]);

  if (!st) return null;

  const enroll = async () => {
    setErr(null);
    const key = pubkey.trim();
    if (!/^[A-Za-z0-9+/]{43}=$/.test(key)) {
      setErr("That doesn't look like a WireGuard public key (44 characters ending in '=').");
      return;
    }
    setBusy(true);
    const r = await VoaisAPI.post("/api/settings/telephony/wireguard/enroll", { public_key: key });
    setBusy(false);
    if (r.ok && r.data?.ok) { setPubkey(""); setSt(s => ({ ...s, ...r.data })); onEnrolled && onEnrolled(); }
    else setErr(r.data?.msg || "Enrollment failed.");
  };

  const revoke = async () => {
    if (!window.confirm("Disconnect this tunnel? Your box will lose its connection until you re-enroll.")) return;
    setBusy(true);
    const r = await VoaisAPI.del("/api/settings/telephony/wireguard");
    setBusy(false);
    if (r.ok) { load(); onEnrolled && onEnrolled(); }
  };

  const mono = { fontFamily: "var(--font-mono)", fontSize: 12, wordBreak: "break-all" };
  const enrolled = !!st.overlay_ip;

  return (
    <Card>
      <SectionHead
        title="WireGuard tunnel — connect your GSM"
        subtitle="The secure link from your edge box to our server. Nothing on your network is exposed publicly."
        right={enrolled ? <Badge tone="green">Connected</Badge> : <Badge tone="gray">Not connected</Badge>}
      />

      {!st.ready && (
        <div style={{ marginTop: 12, fontSize: 12.5, color: "var(--err)" }}>
          The WireGuard hub isn't configured on the server yet. Ask your administrator to run
          <code> deploy/wireguard/hub-setup.sh</code>.
        </div>
      )}

      {st.ready && (
        <div style={{ display: "grid", gap: 12, marginTop: 12 }}>
          <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12 }}>
            <Field label="Hub endpoint (give this to your box)">
              <div className="input" style={mono}>{st.hub?.endpoint}</div>
            </Field>
            <Field label="Hub public key">
              <div className="input" style={mono}>{st.hub?.publicKey}</div>
            </Field>
          </div>

          {!enrolled && (
            <>
              <Field label="Your edge box public key"
                hint="Run setup.sh on the box (step 3 of the guide), then paste 'cat /etc/wireguard/box.pub' here.">
                <input className="input" style={mono} placeholder="Ki9c…base64…="
                  value={pubkey} onChange={e => setPubkey(e.target.value)}/>
              </Field>
              {err && <div style={{ fontSize: 12.5, color: "var(--err)" }}>{err}</div>}
              <div style={{ display: "flex", gap: 10, alignItems: "center" }}>
                <Btn kind="primary" onClick={enroll} disabled={busy}>{busy ? "Connecting…" : "Connect / Enroll"}</Btn>
                <a className="btn-link" href="/docs" target="_blank" rel="noreferrer"
                  style={{ fontSize: 12.5, color: "var(--accent)" }}>Open full setup guide ↗</a>
                <a href="/downloads/voais-edge-setup.tar.gz"
                  style={{ fontSize: 12.5, color: "var(--accent)" }}>Download setup bundle ↓</a>
              </div>
            </>
          )}

          {enrolled && (
            <>
              <div style={{ display: "grid", gridTemplateColumns: "1fr 2fr", gap: 12 }}>
                <Field label="Your overlay IP"><div className="input" style={mono}>{st.overlay_ip}</div></Field>
                <Field label="Box public key (registered)"><div className="input" style={mono}>{st.public_key}</div></Field>
              </div>
              {st.setup_command && (
                <Field label="Re-run on your box with your overlay IP">
                  <pre style={{ ...mono, background: "var(--surface-2)", border: "1px solid var(--line)",
                    borderRadius: "var(--r-sm)", padding: 10, margin: 0, whiteSpace: "pre-wrap" }}>{st.setup_command}</pre>
                </Field>
              )}
              {err && <div style={{ fontSize: 12.5, color: "var(--err)" }}>{err}</div>}
              <div style={{ display: "flex", gap: 10, alignItems: "center" }}>
                <Btn kind="ghost" onClick={() => setSt(s => ({ ...s, overlay_ip: null }))} disabled={busy}>Replace box key</Btn>
                <Btn kind="danger" onClick={revoke} disabled={busy}>Revoke tunnel</Btn>
                <a href="/docs" target="_blank" rel="noreferrer" style={{ fontSize: 12.5, color: "var(--accent)" }}>Setup guide ↗</a>
              </div>
            </>
          )}
        </div>
      )}
    </Card>
  );
}

function ModeCard({ active, onClick, title, desc, preview }) {
  return (
    <button onClick={onClick} className={"mode-card" + (active ? " active" : "")}
      style={{
        flex: 1, textAlign: "left", padding: 14, borderRadius: "var(--r-md)",
        border: "1px solid " + (active ? "var(--accent)" : "var(--line)"),
        background: active ? "var(--accent-soft)" : "var(--surface-2)",
        cursor: "pointer", color: "var(--ink)", fontFamily: "inherit",
      }}>
      <div style={{ fontSize: 13, fontWeight: 600, display: "flex", alignItems: "center", gap: 8 }}>
        <span style={{
          width: 14, height: 14, borderRadius: 7,
          border: "2px solid " + (active ? "var(--accent)" : "var(--line-strong)"),
          background: active ? "var(--accent)" : "transparent",
        }}/>
        {title}
      </div>
      <div style={{ fontSize: 11.5, color: "var(--ink-3)", marginTop: 6 }}>{desc}</div>
      {preview && <div style={{ fontSize: 11, color: "var(--ink-3)", marginTop: 6, fontFamily: "var(--font-mono)" }}>{preview}</div>}
    </button>
  );
}

// ════════════════════════════════════════════════════════════════════════
// AI PROVIDERS (BYOK)
// ════════════════════════════════════════════════════════════════════════
function AiProvidersTab() {
  const [data, setData] = React.useState(null);
  const [editing, setEditing] = React.useState(null);  // provider object

  const load = React.useCallback(() => {
    VoaisAPI.get("/api/settings/ai-providers").then(r => {
      if (r.ok && r.data?.ok) setData(r.data);
    });
  }, []);
  React.useEffect(() => { load(); }, [load]);

  if (!data) return <DashboardSkeleton/>;

  const setDefault = async (key) => {
    await VoaisAPI.patch("/api/settings/ai-defaults", { "ai:default_model": key });
    load();
  };

  return (
    <div style={{ display: "flex", flexDirection: "column", gap: "var(--gap-grid)" }}>
      <Card>
        <SectionHead
          title="AI Providers — Bring Your Own Key"
          subtitle="Paste API keys for the AI providers you want to use. Hidrogen is the default. Keys are encrypted at rest (AES-256-GCM)."
        />
      </Card>

      {data.providers.map(p => (
        <Card key={p.key}>
          <div style={{ display: "flex", alignItems: "center", gap: 12 }}>
            <div style={{ flex: 1, minWidth: 0 }}>
              <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
                <span style={{ fontSize: 14, fontWeight: 600 }}>{p.display_name}</span>
                <Badge tone="gray">{p.category}</Badge>
                {p.requires_byo_key
                  ? <Badge tone="yellow">BYOK</Badge>
                  : <Badge tone="green">included</Badge>}
                {p.api_key_set && <Badge tone="green">key saved</Badge>}
                {data.default_model && p.models.some(m => m.id === data.default_model) && (
                  <Badge tone="blue">default</Badge>
                )}
              </div>
              <div style={{ fontSize: 11.5, color: "var(--ink-3)", marginTop: 4, fontFamily: "var(--font-mono)" }}>
                {p.api_key_mask || "no key set"}
                {p.default_model && <span> · model: {p.default_model}</span>}
                {p.default_voice && <span> · voice: {p.default_voice}</span>}
              </div>
            </div>
            <Btn kind="ghost" size="sm" onClick={() => setEditing(p)}>Configure</Btn>
          </div>
        </Card>
      ))}

      {editing && <AiProviderEditor provider={editing} onClose={() => setEditing(null)} onSaved={() => { setEditing(null); load(); }}/>}
    </div>
  );
}

function AiProviderEditor({ provider, onClose, onSaved }) {
  const [apiKey, setApiKey] = React.useState("");
  const [model, setModel] = React.useState(provider.default_model || (provider.models[0] && provider.models[0].id) || "");
  const [voice, setVoice] = React.useState(provider.default_voice || "");
  const [enabled, setEnabled] = React.useState(provider.enabled);
  const [saving, setSaving] = React.useState(false);

  // Build the API key hint dynamically with a doc-link for providers we know.
  const docLinks = {
    hidrogen:   "https://api.hidrogen.in/docs",
    openai:     "https://platform.openai.com/api-keys",
    anthropic:  "https://console.anthropic.com/settings/keys",
    gemini:     "https://aistudio.google.com/apikey",
    sarvam:     "https://dashboard.sarvam.ai/admin",
    elevenlabs: "https://elevenlabs.io/app/settings/api-keys",
    deepgram:   "https://console.deepgram.com",
  };

  const save = async () => {
    setSaving(true);
    // base_url is intentionally not exposed in the UI — provider docs are
    // maintained centrally; sending `null` so the server clears any stale
    // value from a previous version that *did* expose it.
    const payload = { default_model: model, default_voice: voice || null, base_url: null, enabled };
    if (apiKey.trim()) payload.api_key = apiKey.trim();
    const r = await VoaisAPI.put("/api/settings/ai-providers/" + provider.key, payload);
    setSaving(false);
    if (r.ok) onSaved();
  };

  const removeKey = async () => {
    if (!confirm("Clear the saved API key for " + provider.display_name + "?")) return;
    const r = await VoaisAPI.put("/api/settings/ai-providers/" + provider.key, { api_key: null });
    if (r.ok) onSaved();
  };

  const voices = provider.voices || [];
  const supportsVoice = voices.length > 0 || provider.category === "realtime" || provider.category === "tts";

  return (
    <ModalShell title={"Configure " + provider.display_name} onClose={onClose}>
      <div style={{ display: "flex", flexDirection: "column", gap: 14 }}>
        <Field
          label="API key"
          hint={
            provider.api_key_set
              ? "Saved (masked: " + provider.api_key_mask + "). Leave blank to keep, paste a new key to replace."
              : docLinks[provider.key]
                ? "Generate one at " + docLinks[provider.key]
                : "Paste from " + provider.display_name + " dashboard."
          }>
          <input className="input" type="password" autoComplete="new-password"
            placeholder={provider.api_key_set ? "•••• saved ••••" : (provider.key === "hidrogen" ? "hi_..." : "sk_...")}
            value={apiKey} onChange={e => setApiKey(e.target.value)}/>
        </Field>

        <Field label="Default model" hint="Used when a campaign or agent doesn't pin one.">
          {provider.models.length > 0 ? (
            <select className="select" value={model} onChange={e => setModel(e.target.value)}>
              {provider.models.map(m => <option key={m.id} value={m.id}>{m.name}{m.context ? ` (${m.context.toLocaleString()} ctx)` : ""}</option>)}
            </select>
          ) : (
            <input className="input" value={model} onChange={e => setModel(e.target.value)}
              placeholder="e.g. smart, fast"/>
          )}
        </Field>

        {supportsVoice && (
          <Field label="Default voice" hint="Used for TTS and real-time speech-to-speech calls.">
            {voices.length > 0 ? (
              <select className="select" value={voice} onChange={e => setVoice(e.target.value)}>
                <option value="">— pick a voice —</option>
                {voices.map(v => (
                  <option key={v.id} value={v.id}>
                    {v.name} · {v.gender} · {v.language}{v.tier === "premium" ? " · premium" : ""}
                  </option>
                ))}
              </select>
            ) : (
              <input className="input" placeholder="e.g. priya, alloy" value={voice}
                onChange={e => setVoice(e.target.value)}/>
            )}
          </Field>
        )}

        <Field label="Enabled">
          <Toggle value={enabled} onChange={setEnabled}/>
        </Field>

        <div style={{ display: "flex", gap: 8, justifyContent: "flex-end" }}>
          {provider.api_key_set && <Btn kind="ghost" onClick={removeKey}>Clear key</Btn>}
          <Btn kind="ghost" onClick={onClose}>Cancel</Btn>
          <Btn kind="primary" onClick={save} disabled={saving}>{saving ? "Saving…" : "Save"}</Btn>
        </div>
      </div>
    </ModalShell>
  );
}

// Lightweight modal shell — uses the styles.css `.modal-backdrop`/`.modal-card`
// pattern already in the app (agents.jsx defines a similar `Modal` we don't
// want to re-import here to keep this file self-contained).
function ModalShell({ title, onClose, children }) {
  return (
    <div className="modal-backdrop" onClick={onClose}
      style={{ position: "fixed", inset: 0, background: "rgba(0,0,0,0.5)", zIndex: 100,
               display: "flex", alignItems: "center", justifyContent: "center", padding: 20 }}>
      <div className="modal-card" onClick={e => e.stopPropagation()}
        style={{ background: "var(--surface)", border: "1px solid var(--line)",
                 borderRadius: "var(--r-lg)", width: "100%", maxWidth: 540,
                 maxHeight: "90vh", overflow: "auto", padding: 20 }}>
        <div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 16 }}>
          <div style={{ flex: 1, fontSize: 15, fontWeight: 600 }}>{title}</div>
          <Btn kind="ghost" size="sm" onClick={onClose}><I.x size={13}/></Btn>
        </div>
        {children}
      </div>
    </div>
  );
}

// ════════════════════════════════════════════════════════════════════════
// SIP TRUNKS
// ════════════════════════════════════════════════════════════════════════
function SipTrunksTab() {
  const [trunks, setTrunks] = React.useState(null);
  const [editing, setEditing] = React.useState(null);
  const load = React.useCallback(() => {
    VoaisAPI.get("/api/settings/sip-trunks").then(r => {
      if (r.ok && r.data?.ok) setTrunks(r.data.trunks);
    });
  }, []);
  React.useEffect(() => { load(); }, [load]);

  if (!trunks) return <DashboardSkeleton/>;

  const remove = async (id) => {
    if (!confirm("Delete this SIP trunk?")) return;
    await VoaisAPI.del("/api/settings/sip-trunks/" + id);
    load();
  };

  return (
    <div style={{ display: "flex", flexDirection: "column", gap: "var(--gap-grid)" }}>
      <Card>
        <SectionHead
          title="SIP Trunks"
          subtitle="Telephony providers: Exotel, CallerDesk, Twilio, Plivo, Telnyx, or your own Asterisk/FreeSWITCH."
          right={<Btn kind="primary" size="sm" onClick={() => setEditing({ provider: "exotel", transport: "udp", port: 5060, codec: "PCMU", dtmf_mode: "rfc2833", channel_capacity: 10 })}>Add trunk</Btn>}
        />
      </Card>

      {trunks.length === 0 ? (
        <Card><div style={{ padding: 24, textAlign: "center", color: "var(--ink-3)", fontSize: 13 }}>
          No SIP trunks yet. Add one to start placing calls through Exotel, CallerDesk, or your own Asterisk.
        </div></Card>
      ) : (
        <Card padded={false}>
          <table className="data-table" style={{ width: "100%", fontSize: 13 }}>
            <thead><tr>
              <th style={{ paddingLeft: 16 }}>Name</th>
              <th>Provider</th><th>Server</th><th>Channels</th><th>Status</th><th></th>
            </tr></thead>
            <tbody>{trunks.map(t => (
              <tr key={t.id}>
                <td style={{ paddingLeft: 16, fontWeight: 500 }}>
                  {t.name} {t.is_default && <Badge tone="blue">default</Badge>}
                </td>
                <td><Badge tone="gray">{t.provider}</Badge></td>
                <td style={{ fontFamily: "var(--font-mono)", fontSize: 11 }}>{t.server}:{t.port}/{t.transport}</td>
                <td>{t.channel_capacity}</td>
                <td><Badge tone={t.status === "healthy" ? "green" : (t.status === "offline" ? "red" : "yellow")}>{t.status}</Badge></td>
                <td style={{ textAlign: "right", paddingRight: 12 }}>
                  <Btn kind="ghost" size="sm" onClick={() => setEditing(t)}>Edit</Btn>
                  <Btn kind="ghost" size="sm" onClick={() => remove(t.id)}><I.trash size={12}/></Btn>
                </td>
              </tr>
            ))}</tbody>
          </table>
        </Card>
      )}

      {editing && <SipTrunkEditor trunk={editing} onClose={() => setEditing(null)} onSaved={() => { setEditing(null); load(); }}/>}
    </div>
  );
}

function SipTrunkEditor({ trunk, onClose, onSaved }) {
  const [t, setT] = React.useState({ ...trunk });
  const [password, setPassword] = React.useState("");
  const [saving, setSaving] = React.useState(false);
  const isNew = !t.id;

  const save = async () => {
    setSaving(true);
    const payload = { ...t };
    if (password) payload.password = password;
    delete payload.id; delete payload.created_at; delete payload.last_check_at;
    delete payload.uptime_pct; delete payload.status; delete payload.password_set; delete payload.trunk_name;
    const r = isNew
      ? await VoaisAPI.post("/api/settings/sip-trunks", payload)
      : await VoaisAPI.patch("/api/settings/sip-trunks/" + t.id, payload);
    setSaving(false);
    if (r.ok) onSaved();
  };

  const update = (k, v) => setT({ ...t, [k]: v });

  return (
    <ModalShell title={isNew ? "Add SIP trunk" : "Edit " + t.name} onClose={onClose}>
      <div style={{ display: "flex", flexDirection: "column", gap: 14 }}>
        <Field label="Name">
          <input className="input" value={t.name || ""} placeholder="My Exotel trunk" onChange={e => update("name", e.target.value)}/>
        </Field>
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12 }}>
          <Field label="Provider">
            <select className="select" value={t.provider} onChange={e => update("provider", e.target.value)}>
              <option value="exotel">Exotel</option>
              <option value="twilio">Twilio</option>
              <option value="plivo">Plivo</option>
              <option value="telnyx">Telnyx</option>
              <option value="asterisk">Asterisk</option>
              <option value="freeswitch">FreeSWITCH</option>
              <option value="dinstar">Dinstar</option>
              <option value="vicidial">VICIdial</option>
              <option value="other">Other</option>
            </select>
          </Field>
          <Field label="Transport">
            <select className="select" value={t.transport || "udp"} onChange={e => update("transport", e.target.value)}>
              <option value="udp">UDP</option>
              <option value="tcp">TCP</option>
              <option value="tls">TLS</option>
              <option value="wss">WSS</option>
            </select>
          </Field>
        </div>
        <div style={{ display: "grid", gridTemplateColumns: "2fr 1fr", gap: 12 }}>
          <Field label="Server">
            <input className="input" value={t.server || ""} placeholder="sip.exotel.com" onChange={e => update("server", e.target.value)}/>
          </Field>
          <Field label="Port">
            <input className="input" type="number" value={t.port || 5060} onChange={e => update("port", Number(e.target.value))}/>
          </Field>
        </div>
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12 }}>
          <Field label="Username">
            <input className="input" value={t.username || ""} onChange={e => update("username", e.target.value)}/>
          </Field>
          <Field label="Password" hint={t.password_set ? "A password is saved." : "Provider's SIP password"}>
            <input className="input" type="password" autoComplete="new-password"
              placeholder={t.password_set ? "•••• saved ••••" : ""}
              value={password} onChange={e => setPassword(e.target.value)}/>
          </Field>
        </div>
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 12 }}>
          <Field label="Codec">
            <input className="input" value={t.codec || "PCMU"} onChange={e => update("codec", e.target.value)}/>
          </Field>
          <Field label="DTMF mode">
            <input className="input" value={t.dtmf_mode || "rfc2833"} onChange={e => update("dtmf_mode", e.target.value)}/>
          </Field>
          <Field label="Channels">
            <input className="input" type="number" value={t.channel_capacity || 10} onChange={e => update("channel_capacity", Number(e.target.value))}/>
          </Field>
        </div>
        <Field label="Set as default trunk">
          <Toggle value={!!t.is_default} onChange={(v) => update("is_default", v)}/>
        </Field>
        <div style={{ display: "flex", gap: 8, justifyContent: "flex-end" }}>
          <Btn kind="ghost" onClick={onClose}>Cancel</Btn>
          <Btn kind="primary" onClick={save} disabled={saving}>{saving ? "Saving…" : "Save"}</Btn>
        </div>
      </div>
    </ModalShell>
  );
}

// ════════════════════════════════════════════════════════════════════════
// SIMs
// ════════════════════════════════════════════════════════════════════════
function SimsTab() {
  const [sims, setSims] = React.useState(null);
  const [editing, setEditing] = React.useState(null);
  const load = React.useCallback(() => {
    VoaisAPI.get("/api/settings/sims").then(r => {
      if (r.ok && r.data?.ok) setSims(r.data.sims);
    });
  }, []);
  React.useEffect(() => { load(); }, [load]);

  if (!sims) return <DashboardSkeleton/>;

  const remove = async (id) => {
    if (!confirm("Delete this SIM?")) return;
    await VoaisAPI.del("/api/settings/sims/" + id);
    load();
  };
  const toggle = async (s) => {
    await VoaisAPI.patch("/api/settings/sims/" + s.id, { active: !s.active });
    load();
  };

  return (
    <div style={{ display: "flex", flexDirection: "column", gap: "var(--gap-grid)" }}>
      <Card>
        <SectionHead
          title="GSM SIM ports"
          subtitle="Each row maps a Dinstar SIM port to its dialing prefix. Active SIMs are used in auto round-robin."
          right={<Btn kind="primary" size="sm" onClick={() => setEditing({ port: "", label: "", prefix: "", active: true })}>Add SIM</Btn>}
        />
      </Card>

      {sims.length === 0 ? (
        <Card><div style={{ padding: 24, textAlign: "center", color: "var(--ink-3)", fontSize: 13 }}>
          No SIMs configured yet. Add one row per Dinstar port (e.g. port 30 → prefix 7030).
        </div></Card>
      ) : (
        <Card padded={false}>
          <table className="data-table" style={{ width: "100%", fontSize: 13 }}>
            <thead><tr>
              <th style={{ paddingLeft: 16 }}>Port</th>
              <th>Label</th><th>Phone</th><th>Carrier</th><th>Prefix</th>
              <th>Active</th><th></th>
            </tr></thead>
            <tbody>{sims.map(s => (
              <tr key={s.id}>
                <td style={{ paddingLeft: 16, fontWeight: 600, fontFamily: "var(--font-mono)" }}>{s.port}</td>
                <td>{s.label}</td>
                <td style={{ fontFamily: "var(--font-mono)", fontSize: 11 }}>{s.phone_number || "—"}</td>
                <td style={{ fontSize: 11, color: "var(--ink-3)" }}>{s.carrier || "—"}</td>
                <td style={{ fontFamily: "var(--font-mono)" }}>{s.prefix}</td>
                <td><Toggle value={s.active} onChange={() => toggle(s)}/></td>
                <td style={{ textAlign: "right", paddingRight: 12 }}>
                  <Btn kind="ghost" size="sm" onClick={() => setEditing(s)}>Edit</Btn>
                  <Btn kind="ghost" size="sm" onClick={() => remove(s.id)}><I.trash size={12}/></Btn>
                </td>
              </tr>
            ))}</tbody>
          </table>
        </Card>
      )}

      {editing && <SimEditor sim={editing} onClose={() => setEditing(null)} onSaved={() => { setEditing(null); load(); }}/>}
    </div>
  );
}

function SimEditor({ sim, onClose, onSaved }) {
  const [s, setS] = React.useState({ ...sim });
  const [saving, setSaving] = React.useState(false);
  const [err, setErr] = React.useState("");
  const isNew = !s.id;

  const save = async () => {
    setSaving(true); setErr("");
    const payload = { ...s };
    delete payload.id; delete payload.created_at; delete payload.last_used_at;
    const r = isNew
      ? await VoaisAPI.post("/api/settings/sims", payload)
      : await VoaisAPI.patch("/api/settings/sims/" + s.id, payload);
    setSaving(false);
    if (r.ok) onSaved();
    else setErr(r.data?.msg || "Save failed");
  };
  const update = (k, v) => setS({ ...s, [k]: v });

  return (
    <ModalShell title={isNew ? "Add SIM" : "Edit SIM port " + s.port} onClose={onClose}>
      <div style={{ display: "flex", flexDirection: "column", gap: 14 }}>
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12 }}>
          <Field label="Port" hint="Physical Dinstar port number">
            <input className="input" type="number" value={s.port} onChange={e => update("port", Number(e.target.value))} disabled={!isNew}/>
          </Field>
          <Field label="Prefix" hint="e.g. 7030 — what the Dinstar strips to route to this port">
            <input className="input" value={s.prefix || ""} onChange={e => update("prefix", e.target.value)}/>
          </Field>
        </div>
        <Field label="Label">
          <input className="input" value={s.label || ""} placeholder="e.g. Airtel Mumbai #1" onChange={e => update("label", e.target.value)}/>
        </Field>
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12 }}>
          <Field label="Phone number">
            <input className="input" value={s.phone_number || ""} placeholder="+91..." onChange={e => update("phone_number", e.target.value)}/>
          </Field>
          <Field label="Carrier">
            <input className="input" value={s.carrier || ""} placeholder="Airtel / Jio / Vi" onChange={e => update("carrier", e.target.value)}/>
          </Field>
        </div>
        <Field label="Notes">
          <input className="input" value={s.notes || ""} onChange={e => update("notes", e.target.value)}/>
        </Field>
        <Field label="Active (include in auto round-robin)">
          <Toggle value={!!s.active} onChange={(v) => update("active", v)}/>
        </Field>
        {err && <div style={{ fontSize: 12, color: "#f87171" }}>{err}</div>}
        <div style={{ display: "flex", gap: 8, justifyContent: "flex-end" }}>
          <Btn kind="ghost" onClick={onClose}>Cancel</Btn>
          <Btn kind="primary" onClick={save} disabled={saving}>{saving ? "Saving…" : "Save"}</Btn>
        </div>
      </div>
    </ModalShell>
  );
}

// ════════════════════════════════════════════════════════════════════════
// CALLER IDs
// ════════════════════════════════════════════════════════════════════════
function CallerIdsTab() {
  const [list, setList] = React.useState(null);
  const [trunks, setTrunks] = React.useState([]);
  const [editing, setEditing] = React.useState(null);
  const load = React.useCallback(() => {
    VoaisAPI.get("/api/settings/caller-ids").then(r => {
      if (r.ok && r.data?.ok) setList(r.data.caller_ids);
    });
    VoaisAPI.get("/api/settings/sip-trunks").then(r => {
      if (r.ok && r.data?.ok) setTrunks(r.data.trunks);
    });
  }, []);
  React.useEffect(() => { load(); }, [load]);

  if (!list) return <DashboardSkeleton/>;

  const remove = async (id) => {
    if (!confirm("Delete this caller ID?")) return;
    await VoaisAPI.del("/api/settings/caller-ids/" + id);
    load();
  };

  return (
    <div style={{ display: "flex", flexDirection: "column", gap: "var(--gap-grid)" }}>
      <Card>
        <SectionHead
          title="Caller IDs"
          subtitle="Numbers shown to the receiver when you dial out. Must be verified with the provider."
          right={<Btn kind="primary" size="sm" onClick={() => setEditing({})}>Add caller ID</Btn>}
        />
      </Card>

      {list.length === 0 ? (
        <Card><div style={{ padding: 24, textAlign: "center", color: "var(--ink-3)", fontSize: 13 }}>
          No caller IDs configured.
        </div></Card>
      ) : (
        <Card padded={false}>
          <table className="data-table" style={{ width: "100%", fontSize: 13 }}>
            <thead><tr>
              <th style={{ paddingLeft: 16 }}>Number</th>
              <th>Label</th><th>Trunk</th><th>Verified</th><th></th>
            </tr></thead>
            <tbody>{list.map(c => (
              <tr key={c.id}>
                <td style={{ paddingLeft: 16, fontFamily: "var(--font-mono)", fontWeight: 600 }}>
                  {c.number} {c.is_default && <Badge tone="blue">default</Badge>}
                </td>
                <td>{c.label || "—"}</td>
                <td style={{ fontSize: 11, color: "var(--ink-3)" }}>{c.trunk_name || "any"}</td>
                <td><Badge tone={c.verified ? "green" : "yellow"}>{c.verified ? "verified" : "unverified"}</Badge></td>
                <td style={{ textAlign: "right", paddingRight: 12 }}>
                  <Btn kind="ghost" size="sm" onClick={() => setEditing(c)}>Edit</Btn>
                  <Btn kind="ghost" size="sm" onClick={() => remove(c.id)}><I.trash size={12}/></Btn>
                </td>
              </tr>
            ))}</tbody>
          </table>
        </Card>
      )}

      {editing && <CallerIdEditor callerId={editing} trunks={trunks} onClose={() => setEditing(null)} onSaved={() => { setEditing(null); load(); }}/>}
    </div>
  );
}

function CallerIdEditor({ callerId, trunks, onClose, onSaved }) {
  const [c, setC] = React.useState({ ...callerId });
  const [saving, setSaving] = React.useState(false);
  const isNew = !c.id;
  const save = async () => {
    setSaving(true);
    const payload = { number: c.number, label: c.label, sip_trunk_id: c.sip_trunk_id || null, verified: !!c.verified, is_default: !!c.is_default };
    const r = isNew
      ? await VoaisAPI.post("/api/settings/caller-ids", payload)
      : await VoaisAPI.patch("/api/settings/caller-ids/" + c.id, payload);
    setSaving(false);
    if (r.ok) onSaved();
  };
  return (
    <ModalShell title={isNew ? "Add caller ID" : "Edit caller ID"} onClose={onClose}>
      <div style={{ display: "flex", flexDirection: "column", gap: 14 }}>
        <Field label="Number" hint="Include country code, e.g. +911234567890">
          <input className="input" value={c.number || ""} onChange={e => setC({ ...c, number: e.target.value })}/>
        </Field>
        <Field label="Label">
          <input className="input" value={c.label || ""} placeholder="Sales line" onChange={e => setC({ ...c, label: e.target.value })}/>
        </Field>
        <Field label="SIP trunk" hint="Optional — pin to a specific trunk">
          <select className="select" value={c.sip_trunk_id || ""} onChange={e => setC({ ...c, sip_trunk_id: e.target.value ? Number(e.target.value) : null })}>
            <option value="">— any trunk —</option>
            {trunks.map(t => <option key={t.id} value={t.id}>{t.name} ({t.provider})</option>)}
          </select>
        </Field>
        <Field label="Verified with provider">
          <Toggle value={!!c.verified} onChange={(v) => setC({ ...c, verified: v })}/>
        </Field>
        <Field label="Set as default">
          <Toggle value={!!c.is_default} onChange={(v) => setC({ ...c, is_default: v })}/>
        </Field>
        <div style={{ display: "flex", gap: 8, justifyContent: "flex-end" }}>
          <Btn kind="ghost" onClick={onClose}>Cancel</Btn>
          <Btn kind="primary" onClick={save} disabled={saving}>{saving ? "Saving…" : "Save"}</Btn>
        </div>
      </div>
    </ModalShell>
  );
}

// ════════════════════════════════════════════════════════════════════════
// AI DEFAULTS
// ════════════════════════════════════════════════════════════════════════
function AiDefaultsTab() {
  const [d, setD] = React.useState(null);
  const [providers, setProviders] = React.useState([]);
  const [saving, setSaving] = React.useState(false);
  const [status, setStatus] = React.useState(null);

  const load = React.useCallback(() => {
    Promise.all([
      VoaisAPI.get("/api/settings/ai-defaults"),
      VoaisAPI.get("/api/settings/ai-providers"),
    ]).then(([dRes, pRes]) => {
      if (dRes.ok && dRes.data?.ok) setD(dRes.data.defaults || {});
      if (pRes.ok && pRes.data?.ok) setProviders(pRes.data.providers || []);
    });
  }, []);
  React.useEffect(() => { load(); }, [load]);

  if (!d) return <DashboardSkeleton/>;

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

  const save = async () => {
    setSaving(true); setStatus(null);
    const r = await VoaisAPI.patch("/api/settings/ai-defaults", d);
    setSaving(false);
    setStatus(r.ok ? { ok: true, msg: "Saved" } : { ok: false, msg: "Save failed" });
    setTimeout(() => setStatus(null), 2500);
  };

  // Build a flat list of model ids for the default-model dropdown.
  const allModels = [];
  providers.forEach(p => {
    p.models.forEach(m => allModels.push({ id: m.id, label: `${p.display_name} · ${m.name}` }));
  });

  return (
    <div style={{ display: "flex", flexDirection: "column", gap: "var(--gap-grid)" }}>
      <Card>
        <SectionHead
          title="AI defaults"
          subtitle="Used for every AI call unless the campaign / agent overrides them."
          right={<SaveStatus status={status}/>}
        />
        <div style={{ display: "flex", flexDirection: "column", gap: 14, marginTop: 14, maxWidth: 720 }}>
          <Field label="Default model" hint="Used when a campaign or agent doesn't pin one.">
            <select className="select" value={d["ai:default_model"] || ""} onChange={e => set("ai:default_model", e.target.value)}>
              <option value="">— pick one —</option>
              {allModels.map(m => <option key={m.id} value={m.id}>{m.label}</option>)}
            </select>
          </Field>
          <Field label="System prompt" hint="The persona / instructions the AI follows on every call.">
            <textarea className="input" rows={6} value={d["ai:system_prompt"] || ""} onChange={e => set("ai:system_prompt", e.target.value)}
              placeholder="You are a helpful, friendly AI assistant on a phone call. Keep replies short, clear and conversational."/>
          </Field>
          <Field label="Opening greeting" hint="The first thing the AI says when the call connects.">
            <input className="input" value={d["ai:greeting"] || ""} onChange={e => set("ai:greeting", e.target.value)}
              placeholder="Hello! How can I help you today?"/>
          </Field>
          <Field label="Protect greeting" hint="Drop caller audio while the greeting plays so it can't be cut short.">
            <Toggle value={d["ai:protect_greeting"] !== "false"} onChange={(v) => set("ai:protect_greeting", v ? "true" : "false")}/>
          </Field>
        </div>
      </Card>

      <Card>
        <SectionHead title="Turn-taking (VAD)" subtitle="How quickly the AI decides the caller has finished speaking."/>
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 12, marginTop: 12, maxWidth: 720 }}>
          <Field label="Silence (ms)" hint="600 is snappy, 1500 is laggy">
            <input className="input" type="number" value={d["ai:vad_silence_ms"] || "600"} onChange={e => set("ai:vad_silence_ms", e.target.value)}/>
          </Field>
          <Field label="Threshold (0..1)" hint="Higher = needs louder caller voice to start">
            <input className="input" type="number" step="0.05" value={d["ai:vad_threshold"] || "0.5"} onChange={e => set("ai:vad_threshold", e.target.value)}/>
          </Field>
          <Field label="Prefix padding (ms)">
            <input className="input" type="number" value={d["ai:vad_prefix_ms"] || "300"} onChange={e => set("ai:vad_prefix_ms", e.target.value)}/>
          </Field>
        </div>
      </Card>

      <Card>
        <SectionHead title="Voice defaults" subtitle="Default voices used by each provider when not overridden by a campaign or agent."/>
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12, marginTop: 12, maxWidth: 720 }}>
          <Field label="Hidrogen voice">
            <VoiceSelect providers={providers} providerKey="hidrogen" value={d["ai:hidrogen_voice"]} onChange={(v) => set("ai:hidrogen_voice", v)}/>
          </Field>
          <Field label="Gemini voice">
            <VoiceSelect providers={providers} providerKey="gemini" value={d["ai:gemini_voice"]} onChange={(v) => set("ai:gemini_voice", v)} fallbackPlaceholder="Sulafat"/>
          </Field>
          <Field label="Gemini style" hint="Free-form vibe instruction sent to Gemini.">
            <input className="input" placeholder="calm, warm and professional" value={d["ai:gemini_style"] || ""} onChange={e => set("ai:gemini_style", e.target.value)}/>
          </Field>
          <Field label="Sarvam voice">
            <VoiceSelect providers={providers} providerKey="sarvam" value={d["ai:sarvam_voice"]} onChange={(v) => set("ai:sarvam_voice", v)} fallbackPlaceholder="anushka"/>
          </Field>
          <Field label="Sarvam language" hint="ISO code, e.g. en-IN, hi-IN, ta-IN">
            <input className="input" placeholder="en-IN" value={d["ai:sarvam_language"] || ""} onChange={e => set("ai:sarvam_language", e.target.value)}/>
          </Field>
        </div>
      </Card>

      <Card>
        <Btn kind="primary" onClick={save} disabled={saving}>{saving ? "Saving…" : "Save AI defaults"}</Btn>
      </Card>
    </div>
  );
}

// ════════════════════════════════════════════════════════════════════════
// TRAINING (quick-add) — for full KB management, link to KB screen
// ════════════════════════════════════════════════════════════════════════
function TrainingTab() {
  const [items, setItems] = React.useState(null);
  const [adding, setAdding] = React.useState(null); // "text" | "url" | "qa"

  const load = React.useCallback(() => {
    VoaisAPI.get("/api/settings/training").then(r => {
      if (r.ok && r.data?.ok) setItems(r.data.items);
    });
  }, []);
  React.useEffect(() => { load(); }, [load]);

  if (!items) return <DashboardSkeleton/>;

  const remove = async (id) => {
    if (!confirm("Remove this training item?")) return;
    await VoaisAPI.del("/api/settings/training/" + id);
    load();
  };

  return (
    <div style={{ display: "flex", flexDirection: "column", gap: "var(--gap-grid)" }}>
      <Card>
        <SectionHead
          title="Training (quick-add)"
          subtitle="Drop snippets, URLs, or Q&A pairs your AI should know. For PDFs and large corpora, use the full Knowledge Base."
        />
        <div style={{ display: "flex", gap: 8, marginTop: 12, flexWrap: "wrap" }}>
          <Btn kind="primary" size="sm" onClick={() => setAdding("text")}>+ Text snippet</Btn>
          <Btn kind="ghost"   size="sm" onClick={() => setAdding("url")}>+ Website URL</Btn>
          <Btn kind="ghost"   size="sm" onClick={() => setAdding("qa")}>+ Q&A pair</Btn>
          <div style={{ flex: 1 }}/>
          <Btn kind="ghost" size="sm" onClick={() => window.dispatchEvent(new CustomEvent("voais:navigate", { detail: { route: "kb" } }))}>
            Open full Knowledge Base →
          </Btn>
        </div>
      </Card>

      {items.length === 0 ? (
        <Card><div style={{ padding: 24, textAlign: "center", color: "var(--ink-3)", fontSize: 13 }}>
          Nothing here yet. Add a text snippet, URL, or Q&A pair above.
        </div></Card>
      ) : (
        <Card padded={false}>
          <table className="data-table" style={{ width: "100%", fontSize: 13 }}>
            <thead><tr>
              <th style={{ paddingLeft: 16 }}>Title</th>
              <th>Type</th><th>Status</th><th>Added</th><th></th>
            </tr></thead>
            <tbody>{items.map(it => (
              <tr key={it.id}>
                <td style={{ paddingLeft: 16, fontWeight: 500, maxWidth: 400, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>
                  {it.name}
                  {it.source_url && <div style={{ fontSize: 10.5, color: "var(--ink-3)", fontFamily: "var(--font-mono)" }}>{it.source_url}</div>}
                </td>
                <td><Badge tone="gray">{it.type}</Badge></td>
                <td><Badge tone={it.index_status === "indexed" ? "green" : (it.index_status === "failed" ? "red" : "yellow")}>{it.index_status}</Badge></td>
                <td style={{ fontSize: 11, color: "var(--ink-3)" }}>{new Date(it.created_at).toLocaleDateString("en-IN")}</td>
                <td style={{ textAlign: "right", paddingRight: 12 }}>
                  <Btn kind="ghost" size="sm" onClick={() => remove(it.id)}><I.trash size={12}/></Btn>
                </td>
              </tr>
            ))}</tbody>
          </table>
        </Card>
      )}

      {adding && <TrainingAddModal kind={adding} onClose={() => setAdding(null)} onSaved={() => { setAdding(null); load(); }}/>}
    </div>
  );
}

function TrainingAddModal({ kind, onClose, onSaved }) {
  const [form, setForm] = React.useState({ title: "", content: "", url: "", question: "", answer: "" });
  const [saving, setSaving] = React.useState(false);
  const [err, setErr] = React.useState("");
  const save = async () => {
    setSaving(true); setErr("");
    const payload = { kind, title: form.title || null };
    if (kind === "text") payload.content = form.content;
    else if (kind === "url") payload.url = form.url;
    else { payload.question = form.question; payload.answer = form.answer; }
    const r = await VoaisAPI.post("/api/settings/training", payload);
    setSaving(false);
    if (r.ok) onSaved();
    else setErr(r.data?.msg || "Save failed");
  };
  const titleLabel = kind === "text" ? "Text snippet" : (kind === "url" ? "Website URL" : "Q&A pair");
  return (
    <ModalShell title={"Add " + titleLabel} onClose={onClose}>
      <div style={{ display: "flex", flexDirection: "column", gap: 14 }}>
        <Field label="Title (optional)">
          <input className="input" value={form.title} onChange={e => setForm({ ...form, title: e.target.value })} placeholder="A short label for this item"/>
        </Field>
        {kind === "text" && (
          <Field label="Content">
            <textarea className="input" rows={8} value={form.content} onChange={e => setForm({ ...form, content: e.target.value })}
              placeholder="Paste anything — product details, policies, FAQ answers…"/>
          </Field>
        )}
        {kind === "url" && (
          <Field label="URL" hint="We'll fetch and index it in the background.">
            <input className="input" value={form.url} onChange={e => setForm({ ...form, url: e.target.value })}
              placeholder="https://yoursite.com/about"/>
          </Field>
        )}
        {kind === "qa" && (
          <React.Fragment>
            <Field label="Question">
              <input className="input" value={form.question} onChange={e => setForm({ ...form, question: e.target.value })}
                placeholder="What's your return policy?"/>
            </Field>
            <Field label="Answer">
              <textarea className="input" rows={5} value={form.answer} onChange={e => setForm({ ...form, answer: e.target.value })}
                placeholder="We accept returns within 30 days…"/>
            </Field>
          </React.Fragment>
        )}
        {err && <div style={{ fontSize: 12, color: "#f87171" }}>{err}</div>}
        <div style={{ display: "flex", gap: 8, justifyContent: "flex-end" }}>
          <Btn kind="ghost" onClick={onClose}>Cancel</Btn>
          <Btn kind="primary" onClick={save} disabled={saving}>{saving ? "Saving…" : "Add"}</Btn>
        </div>
      </div>
    </ModalShell>
  );
}

// ════════════════════════════════════════════════════════════════════════
// TEAM — preserved from original
// ════════════════════════════════════════════════════════════════════════
function TeamTab() {
  const [team, setTeam] = React.useState(null);
  const [email, setEmail] = React.useState("");
  const [role, setRole] = React.useState("agent");
  const load = () => VoaisAPI.get("/api/settings/team").then(r => { if (r.ok && r.data?.ok) setTeam(r.data); });
  React.useEffect(() => { load(); }, []);
  const invite = async () => {
    if (!email.trim()) return;
    await VoaisAPI.post("/api/settings/team", { email, role });
    setEmail(""); load();
  };
  if (!team) return <DashboardSkeleton/>;
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: "var(--gap-grid)" }}>
      <Card>
        <div style={{ display: "flex", gap: 8, alignItems: "end" }}>
          <Field label="Invite by email">
            <input className="input" value={email} onChange={e => setEmail(e.target.value)} placeholder="colleague@company.com"/>
          </Field>
          <Field label="Role">
            <select className="select" value={role} onChange={e => setRole(e.target.value)}>
              <option value="admin">Admin</option>
              <option value="manager">Manager</option>
              <option value="agent">Agent</option>
              <option value="viewer">Viewer</option>
            </select>
          </Field>
          <Btn kind="primary" onClick={invite}>Invite</Btn>
        </div>
      </Card>
      <Card padded={false}>
        <table className="data-table" style={{ width: "100%", fontSize: 13 }}>
          <thead><tr>
            <th style={{ paddingLeft: 16 }}>Member</th><th>Role</th><th>Status</th><th>Last login</th>
          </tr></thead>
          <tbody>{team.members?.map(m => (
            <tr key={m.id}>
              <td style={{ paddingLeft: 16 }}>
                <div style={{ fontWeight: 500 }}>{m.name || m.email}</div>
                <div style={{ fontSize: 11, color: "var(--ink-3)" }}>{m.email}</div>
              </td>
              <td><Badge tone="gray">{m.role}</Badge></td>
              <td><Badge tone={m.is_active ? "green" : "red"}>{m.is_active ? "Active" : "Deactivated"}</Badge></td>
              <td style={{ fontSize: 11, color: "var(--ink-3)" }}>{m.last_login_at ? new Date(m.last_login_at).toLocaleDateString("en-IN") : "Never"}</td>
            </tr>
          ))}</tbody>
        </table>
      </Card>
      {team.invites?.length > 0 && (
        <Card padded={false}>
          <div style={{ padding: "12px 16px", fontSize: 13, fontWeight: 600, color: "var(--ink-3)" }}>Pending invites</div>
          <table className="data-table" style={{ width: "100%", fontSize: 13 }}>
            <tbody>{team.invites.map(i => (
              <tr key={i.id}>
                <td style={{ paddingLeft: 16 }}>{i.email}</td>
                <td><Badge tone="gray">{i.role}</Badge></td>
                <td><Badge tone="yellow">{i.status}</Badge></td>
                <td style={{ fontSize: 11, color: "var(--ink-3)" }}>Expires {new Date(i.expires_at).toLocaleDateString("en-IN")}</td>
              </tr>
            ))}</tbody>
          </table>
        </Card>
      )}
    </div>
  );
}

// ════════════════════════════════════════════════════════════════════════
// API KEYS — preserved
// ════════════════════════════════════════════════════════════════════════
function ApiKeysTab() {
  const [keys, setKeys] = React.useState(null);
  const [name, setName] = React.useState("");
  const [newKey, setNewKey] = React.useState(null);
  const load = () => VoaisAPI.get("/api/settings/api-keys").then(r => { if (r.ok && r.data?.ok) setKeys(r.data.keys); });
  React.useEffect(() => { load(); }, []);
  const create = async () => {
    if (!name.trim()) return;
    const r = await VoaisAPI.post("/api/settings/api-keys", { name });
    if (r.ok && r.data?.ok) { setNewKey(r.data.key); setName(""); load(); }
  };
  const revoke = async (id) => {
    if (!confirm("Revoke this key?")) return;
    await VoaisAPI.del("/api/settings/api-keys/" + id);
    load();
  };
  if (!keys) return <DashboardSkeleton/>;
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: "var(--gap-grid)" }}>
      <Card>
        <div style={{ display: "flex", gap: 8, alignItems: "end" }}>
          <Field label="Key name">
            <input className="input" value={name} onChange={e => setName(e.target.value)} placeholder="e.g. Production API"/>
          </Field>
          <Btn kind="primary" onClick={create}>Create key</Btn>
        </div>
        {newKey && (
          <div className="auth-banner" style={{ marginTop: 10, background: "var(--accent-soft)" }}>
            <span style={{ fontFamily: "var(--font-mono)", fontSize: 12, wordBreak: "break-all" }}>{newKey}</span>
          </div>
        )}
      </Card>
      <Card padded={false}>
        <table className="data-table" style={{ width: "100%", fontSize: 13 }}>
          <thead><tr>
            <th style={{ paddingLeft: 16 }}>Name</th><th>Key</th><th>Created</th><th>Last used</th><th></th>
          </tr></thead>
          <tbody>{keys.map(k => (
            <tr key={k.id}>
              <td style={{ paddingLeft: 16, fontWeight: 500 }}>{k.name}</td>
              <td style={{ fontFamily: "var(--font-mono)", fontSize: 11 }}>{k.key_prefix}</td>
              <td style={{ fontSize: 11, color: "var(--ink-3)" }}>{new Date(k.created_at).toLocaleDateString("en-IN")}</td>
              <td style={{ fontSize: 11, color: "var(--ink-3)" }}>{k.last_used_at ? new Date(k.last_used_at).toLocaleDateString("en-IN") : "Never"}</td>
              <td><Btn kind="ghost" size="sm" onClick={() => revoke(k.id)}><I.trash size={12}/></Btn></td>
            </tr>
          ))}</tbody>
        </table>
      </Card>
    </div>
  );
}

// ════════════════════════════════════════════════════════════════════════
// COMPLIANCE — preserved
// ════════════════════════════════════════════════════════════════════════
function ComplianceTab() {
  const [data, setData] = React.useState(null);
  const [saving, setSaving] = React.useState(false);
  const [form, setForm] = React.useState({
    weekday_start: "09:00", weekday_end: "21:00",
    weekend_start: "10:00", weekend_end: "19:00",
    timezone: "Asia/Kolkata",
  });
  React.useEffect(() => {
    VoaisAPI.get("/api/settings/compliance").then(r => {
      if (r.ok && r.data?.ok) {
        setData(r.data);
        if (r.data.calling_hours?.[0]) {
          const h = r.data.calling_hours[0];
          setForm({
            weekday_start: h.weekday_start?.slice(0,5) || "09:00",
            weekday_end:   h.weekday_end?.slice(0,5)   || "21:00",
            weekend_start: h.weekend_start?.slice(0,5) || "10:00",
            weekend_end:   h.weekend_end?.slice(0,5)   || "19:00",
            timezone:      h.timezone || "Asia/Kolkata",
          });
        }
      }
    });
  }, []);
  const save = async () => {
    setSaving(true);
    await VoaisAPI.patch("/api/settings/compliance", form);
    setSaving(false);
  };
  if (!data) return <DashboardSkeleton/>;
  return (
    <Card>
      <div style={{ display: "flex", flexDirection: "column", gap: 14, maxWidth: 480 }}>
        <div style={{ fontSize: 14, fontWeight: 600 }}>TRAI-compliant calling hours</div>
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 14 }}>
          <Field label="Weekday start"><input className="input" type="time" value={form.weekday_start} onChange={e => setForm({ ...form, weekday_start: e.target.value })}/></Field>
          <Field label="Weekday end"><input className="input" type="time" value={form.weekday_end} onChange={e => setForm({ ...form, weekday_end: e.target.value })}/></Field>
          <Field label="Weekend start"><input className="input" type="time" value={form.weekend_start} onChange={e => setForm({ ...form, weekend_start: e.target.value })}/></Field>
          <Field label="Weekend end"><input className="input" type="time" value={form.weekend_end} onChange={e => setForm({ ...form, weekend_end: e.target.value })}/></Field>
        </div>
        <Field label="Timezone"><input className="input" value={form.timezone} onChange={e => setForm({ ...form, timezone: e.target.value })}/></Field>
        <div style={{ fontSize: 12, color: "var(--ink-3)" }}>DNC list: {data.dnc_count} numbers registered</div>
        <Btn kind="primary" onClick={save} disabled={saving}>{saving ? "Saving…" : "Save"}</Btn>
      </div>
    </Card>
  );
}

// ════════════════════════════════════════════════════════════════════════
// NOTIFICATIONS — preserved
// ════════════════════════════════════════════════════════════════════════
function NotificationsTab() {
  return (
    <Card>
      <div style={{ padding: 24, textAlign: "center", color: "var(--ink-3)", fontSize: 13 }}>
        Notification preferences will be configurable once the notification system is wired to email/Slack/WhatsApp delivery.
      </div>
    </Card>
  );
}

window.SettingsScreen = SettingsScreen;
