// support.jsx — internal support center. Lives under view === "support".
// Two tabs: Tickets (triage queue with detail panel) and Customers
// (admin: assign plan, suspend, top up credits, change password).
//
// Visual language: mirrors the project task module's epic-grouped table
// design — each status becomes a "group card" with a colored left stripe
// + table inside, and the customers tab is a real <table class="t"> like
// the project task table. This keeps a single visual language across
// Flowboard's modules so users don't context-switch.

const SUPPORT_STATUSES = [
  { id: "open",                 label: "Open",                 color: "#579bfc" },
  { id: "in_progress",          label: "In progress",          color: "#fdab3d" },
  { id: "waiting_on_customer",  label: "Waiting on customer",  color: "#a25ddc" },
  { id: "resolved",             label: "Resolved",             color: "#00c875" },
  { id: "closed",               label: "Closed",               color: "#9aa0ae" },
];
const SUPPORT_PRIORITIES = ["low", "normal", "high", "urgent"];

// tiny helper: stack of avatar bubbles for assignee column
function SupAvatar({ name, color, size = 22 }) {
  const initials = (name || "?").split(/\s+/).map(p => p[0]).slice(0, 2).join("").toUpperCase();
  return (
    <span style={{
      width: size, height: size, borderRadius: "50%",
      background: color || "var(--brand)", color: "white",
      display: "inline-flex", alignItems: "center", justifyContent: "center",
      fontSize: Math.round(size * 0.45), fontWeight: 700,
      flexShrink: 0,
    }}>{initials}</span>
  );
}

function SupportView({ currentUserId, activeTab, onTabChange }) {
  // Tab is now controlled by the main app sidebar's Support submenu
  // (deep links to /support/<tab>). Fall back to internal state if the
  // parent doesn't pass it (older callers).
  const [internalTab, setInternalTab] = React.useState("dashboard");
  const tab    = activeTab   || internalTab;
  const setTab = onTabChange || setInternalTab;
  // SLA simulator offset, in virtual minutes. 0 = real time. The drawer's
  // +5/+15/+1h buttons advance this so reviewers can watch the breach
  // cascade fire without waiting for wall-clock time.
  const [simNowMin, setSimNowMin] = React.useState(0);
  function advanceSim(min) { setSimNowMin(s => s + min); }
  function resetSim() { setSimNowMin(0); }

  return (
    <div className="sup-root">
      {/* Mount the module's CSS once at the root so it's present for EVERY
          tab and — crucially — for the modals that portal to document.body
          (New ticket, customer editor). Previously SUP_EXTRA_CSS was only
          injected by the Dashboard/Canned/KB/Reports tabs, so opening the
          New Ticket modal from the Tickets tab rendered it completely
          unstyled. A <style> tag styles the whole document regardless of
          where it's mounted, so one copy here covers all cases. */}
      <style>{SUP_EXTRA_CSS}</style>
      <div className="sup-header">
        <div className="sup-title-row">
          <h1 className="sup-title"><span className="sup-title-icon">🎧</span> Support center</h1>
          <div className="sup-meta">All customer tickets, in one place.</div>
        </div>
        <div className="sup-tabs">
          <button className={`sup-tab ${tab === "dashboard" ? "is-active" : ""}`} onClick={() => setTab("dashboard")}>Dashboard</button>
          <button className={`sup-tab ${tab === "tickets"   ? "is-active" : ""}`} onClick={() => setTab("tickets")}>Tickets</button>
          <button className={`sup-tab ${tab === "customers" ? "is-active" : ""}`} onClick={() => setTab("customers")}>Customers</button>
          <button className={`sup-tab ${tab === "canned"    ? "is-active" : ""}`} onClick={() => setTab("canned")}>Canned</button>
          <button className={`sup-tab ${tab === "kb"        ? "is-active" : ""}`} onClick={() => setTab("kb")}>Knowledge base</button>
          <button className={`sup-tab ${tab === "reports"   ? "is-active" : ""}`} onClick={() => setTab("reports")}>Reports &amp; CSAT</button>
          <button className={`sup-tab ${tab === "settings"  ? "is-active" : ""}`} onClick={() => setTab("settings")}>Plans &amp; types</button>
          <button className={`sup-tab ${tab === "team"      ? "is-active" : ""}`} onClick={() => setTab("team")}>Team &amp; SLA</button>
        </div>
      </div>
      {tab === "dashboard" && <SupDashboardTab onJump={setTab}/>}
      {tab === "tickets"   && <TicketsTab currentUserId={currentUserId}
                                           simNowMin={simNowMin}
                                           onAdvanceSim={advanceSim}
                                           onResetSim={resetSim}/>}
      {tab === "customers" && <CustomersTab/>}
      {tab === "canned"    && <CannedTab/>}
      {tab === "kb"        && <KnowledgeBaseTab/>}
      {tab === "reports"   && <ReportsTab/>}
      {tab === "settings"  && <SettingsTab/>}
      {tab === "team"      && (typeof SlaTeamSettings === "function"
                                 ? <SlaTeamSettings/>
                                 : <div className="sup-empty">SLA module not loaded.</div>)}
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// Dashboard — KPI overview derived from /support/stats.
// ─────────────────────────────────────────────────────────────
function SupDashboardTab({ onJump }) {
  const [s, setS] = React.useState(null);
  const [err, setErr] = React.useState(null);
  React.useEffect(() => {
    let alive = true;
    api.support.stats()
      .then(r => { if (alive) setS(r); })
      .catch(e => { if (alive) setErr((e && e.message) || "Could not load stats"); });
    return () => { alive = false; };
  }, []);
  if (err) return <div className="sup-empty">{err}</div>;
  if (!s) return <div className="sup-empty">Loading dashboard…</div>;
  const t = s.totals || {};
  const fmtMin = (m) => {
    const n = Math.round(Number(m) || 0);
    if (!n) return "—";
    if (n < 60) return n + "m";
    const h = Math.floor(n / 60), mm = n % 60;
    return mm ? `${h}h ${mm}m` : `${h}h`;
  };
  const avgCsat = s.csat && s.csat.avg_csat ? Number(s.csat.avg_csat).toFixed(1) : "—";
  const cards = [
    { label: "Open tickets",   value: Number(t.open_total) || 0, tone: "brand", jump: "tickets" },
    { label: "Urgent open",    value: Number(t.urgent_open) || 0, tone: (Number(t.urgent_open) ? "danger" : "ok") },
    { label: "Created today",  value: Number(t.created_today) || 0 },
    { label: "Avg resolve",    value: fmtMin(t.avg_resolve_min) },
    { label: "Resolved",       value: Number(t.resolved_total) || 0, tone: "ok" },
    { label: "CSAT",           value: avgCsat + (avgCsat !== "—" ? " ★" : ""), tone: "ok", jump: "reports" },
  ];
  return (
    <div className="sup-dash">
      <div className="sup-dash-kpis">
        {cards.map((c, i) => (
          <button key={i} className={`sup-dash-kpi ${c.tone ? "tone-" + c.tone : ""}`}
                  onClick={() => c.jump && onJump && onJump(c.jump)}
                  style={{ cursor: c.jump ? "pointer" : "default" }}>
            <div className="sup-dash-kpi-value">{c.value}</div>
            <div className="sup-dash-kpi-label">{c.label}</div>
          </button>
        ))}
      </div>
      <div className="sup-dash-row">
        <div className="sup-dash-card">
          <h3>By status</h3>
          {(s.by_status || []).length === 0 ? <div className="sup-empty-sm">No tickets yet.</div> :
            (s.by_status || []).map(r => (
              <div key={r.status} className="sup-dash-bar-row">
                <span className="sup-dash-bar-label">{r.status}</span>
                <span className="sup-dash-bar-count">{r.n}</span>
              </div>
            ))}
        </div>
        <div className="sup-dash-card">
          <h3>Agent load (open)</h3>
          {(s.agents || []).length === 0 ? <div className="sup-empty-sm">No assigned tickets.</div> :
            (s.agents || []).map(a => (
              <div key={a.id} className="sup-dash-bar-row">
                <span className="sup-dash-bar-label">{a.name}</span>
                <span className="sup-dash-bar-count">{a.open_n}</span>
              </div>
            ))}
        </div>
      </div>
      <style>{SUP_EXTRA_CSS}</style>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// Canned responses — saved reply templates.
// ─────────────────────────────────────────────────────────────
function CannedTab() {
  const [items, setItems] = React.useState(null);
  const [editing, setEditing] = React.useState(null); // {id?, title, body}
  const reload = () => api.support.listCanned().then(setItems).catch(() => setItems([]));
  React.useEffect(() => { reload(); }, []);
  async function save() {
    if (!editing.title || !editing.body) return;
    try {
      if (editing.id) await api.support.patchCanned(editing.id, { title: editing.title, body: editing.body });
      else await api.support.createCanned({ title: editing.title, body: editing.body });
      setEditing(null); reload();
    } catch (e) {
      const m = (e && e.body && (e.body.message || e.body.error)) || "Could not save";
      if (window.fbToast) window.fbToast(m, 3500);
    }
  }
  async function remove(id) {
    if (!window.confirm("Delete this canned response?")) return;
    await api.support.deleteCanned(id); reload();
  }
  function copy(body) {
    try { navigator.clipboard.writeText(body); if (window.fbToast) window.fbToast("Copied to clipboard", 1800); } catch {}
  }
  if (!items) return <div className="sup-empty">Loading…</div>;
  return (
    <div className="sup-canned">
      <div className="sup-section-head">
        <div><b>{items.length}</b> canned response{items.length === 1 ? "" : "s"}</div>
        <button className="btn btn-primary" onClick={() => setEditing({ title: "", body: "" })}>+ New response</button>
      </div>
      {items.length === 0 && <div className="sup-empty">No saved replies yet. Create one agents can insert with a click.</div>}
      <div className="sup-canned-list">
        {items.map(c => (
          <div key={c.id} className="sup-canned-card">
            <div className="sup-canned-card-head">
              <b>{c.title}</b>
              <div className="sup-canned-actions">
                <button className="btn-sm" onClick={() => copy(c.body)}>Copy</button>
                <button className="btn-sm" onClick={() => setEditing({ id: c.id, title: c.title, body: c.body })}>Edit</button>
                <button className="btn-sm" onClick={() => remove(c.id)}>Delete</button>
              </div>
            </div>
            <div className="sup-canned-body">{c.body}</div>
          </div>
        ))}
      </div>
      {editing && (
        <SupEditorModal title={editing.id ? "Edit canned response" : "New canned response"}
          subtitle="Reusable reply agents can insert with one click"
          onClose={() => setEditing(null)} onSave={save}>
          <label className="sup-field"><span>Title</span>
            <input value={editing.title} onChange={e => setEditing({ ...editing, title: e.target.value })}
                   placeholder="e.g. Refund acknowledged"/></label>
          <label className="sup-field"><span className="sup-field-head">Body
              <ProofreadButton text={editing.body} onApply={v => setEditing({ ...editing, body: v })}/></span>
            <textarea rows={6} value={editing.body} onChange={e => setEditing({ ...editing, body: e.target.value })}
                      placeholder="Hi {{name}}, thanks for reaching out…"/></label>
        </SupEditorModal>
      )}
      <style>{SUP_EXTRA_CSS}</style>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// Knowledge base — internal + public help articles.
// ─────────────────────────────────────────────────────────────
function KnowledgeBaseTab() {
  const [items, setItems] = React.useState(null);
  const [q, setQ] = React.useState("");
  const [editing, setEditing] = React.useState(null);
  const reload = (query) => api.support.listKb(query).then(setItems).catch(() => setItems([]));
  React.useEffect(() => { reload(); }, []);
  React.useEffect(() => { const t = setTimeout(() => reload(q), 250); return () => clearTimeout(t); }, [q]);
  async function save() {
    if (!editing.title || !editing.body) return;
    try {
      if (editing.id) await api.support.patchKb(editing.id, editing);
      else await api.support.createKb(editing);
      setEditing(null); reload(q);
    } catch (e) {
      const m = (e && e.body && (e.body.message || e.body.error)) || "Could not save";
      if (window.fbToast) window.fbToast(m, 3500);
    }
  }
  async function remove(id) {
    if (!window.confirm("Delete this article?")) return;
    await api.support.deleteKb(id); reload(q);
  }
  if (!items) return <div className="sup-empty">Loading…</div>;
  return (
    <div className="sup-kb">
      <div className="sup-section-head">
        <input className="search-input" placeholder="Search articles…" value={q} onChange={e => setQ(e.target.value)}
               style={{ maxWidth: 280 }}/>
        <button className="btn btn-primary" onClick={() => setEditing({ title: "", body: "", category: "", is_public: 0 })}>+ New article</button>
      </div>
      {items.length === 0 && <div className="sup-empty">No articles{q ? " match your search" : " yet"}.</div>}
      <div className="sup-kb-list">
        {items.map(a => (
          <div key={a.id} className="sup-kb-card">
            <div className="sup-kb-card-head">
              <div>
                <b>{a.title}</b>
                {a.category && <span className="sup-kb-cat">{a.category}</span>}
                <span className={`sup-kb-vis ${a.is_public ? "pub" : "int"}`}>{a.is_public ? "Public" : "Internal"}</span>
              </div>
              <div className="sup-canned-actions">
                <button className="btn-sm" onClick={() => setEditing({ id: a.id, title: a.title, body: a.body, category: a.category || "", is_public: a.is_public })}>Edit</button>
                <button className="btn-sm" onClick={() => remove(a.id)}>Delete</button>
              </div>
            </div>
            <div className="sup-canned-body">{(a.body || "").slice(0, 240)}{(a.body || "").length > 240 ? "…" : ""}</div>
          </div>
        ))}
      </div>
      {editing && (
        <SupEditorModal title={editing.id ? "Edit article" : "New article"}
          subtitle="Internal note or public help-centre article"
          onClose={() => setEditing(null)} onSave={save}>
          <label className="sup-field"><span>Title</span>
            <input value={editing.title} onChange={e => setEditing({ ...editing, title: e.target.value })}/></label>
          <div style={{ display: "grid", gridTemplateColumns: "1fr auto", gap: 12, alignItems: "end" }}>
            <label className="sup-field"><span>Category</span>
              <input value={editing.category} onChange={e => setEditing({ ...editing, category: e.target.value })}
                     placeholder="e.g. Billing"/></label>
            <label style={{ display: "flex", alignItems: "center", gap: 8, fontSize: 13, paddingBottom: 8 }}>
              <input type="checkbox" checked={!!editing.is_public}
                     onChange={e => setEditing({ ...editing, is_public: e.target.checked ? 1 : 0 })}/>
              Public
            </label>
          </div>
          <label className="sup-field"><span className="sup-field-head">Body
              <ProofreadButton text={editing.body} onApply={v => setEditing({ ...editing, body: v })}/></span>
            <textarea rows={8} value={editing.body} onChange={e => setEditing({ ...editing, body: e.target.value })}/></label>
        </SupEditorModal>
      )}
      <style>{SUP_EXTRA_CSS}</style>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// Reports & CSAT.
// ─────────────────────────────────────────────────────────────
function ReportsTab() {
  const [s, setS] = React.useState(null);
  React.useEffect(() => { api.support.stats().then(setS).catch(() => setS({})); }, []);
  if (!s) return <div className="sup-empty">Loading reports…</div>;
  const t = s.totals || {};
  const csat = s.csat || {};
  const avg = csat.avg_csat ? Number(csat.avg_csat).toFixed(2) : null;
  const resolvedRate = t.total ? Math.round((Number(t.resolved_total) / Number(t.total)) * 100) : 0;
  return (
    <div className="sup-dash">
      <div className="sup-dash-kpis">
        <div className="sup-dash-kpi"><div className="sup-dash-kpi-value">{Number(t.total) || 0}</div><div className="sup-dash-kpi-label">Total tickets</div></div>
        <div className="sup-dash-kpi tone-ok"><div className="sup-dash-kpi-value">{resolvedRate}%</div><div className="sup-dash-kpi-label">Resolution rate</div></div>
        <div className="sup-dash-kpi"><div className="sup-dash-kpi-value">{avg ? avg + " ★" : "—"}</div><div className="sup-dash-kpi-label">Avg CSAT</div></div>
        <div className="sup-dash-kpi"><div className="sup-dash-kpi-value">{Number(csat.responses) || 0}</div><div className="sup-dash-kpi-label">CSAT responses</div></div>
      </div>
      <div className="sup-dash-card">
        <h3>Tickets by status</h3>
        {(s.by_status || []).map(r => (
          <div key={r.status} className="sup-dash-bar-row">
            <span className="sup-dash-bar-label">{r.status}</span>
            <span className="sup-dash-bar-count">{r.n}</span>
          </div>
        ))}
      </div>
      <div className="sup-dash-card">
        <h3>Tickets by priority</h3>
        {(s.by_priority || []).map(r => (
          <div key={r.priority} className="sup-dash-bar-row">
            <span className="sup-dash-bar-label">{r.priority}</span>
            <span className="sup-dash-bar-count">{r.n}</span>
          </div>
        ))}
      </div>
      <style>{SUP_EXTRA_CSS}</style>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// New ticket — agent opens a ticket on behalf of a customer.
// ─────────────────────────────────────────────────────────────
function NewTicketModal({ currentUserId, onClose, onCreated }) {
  const [customers, setCustomers] = React.useState([]);
  const [types, setTypes]     = React.useState([]);
  const [agents, setAgents]   = React.useState([]);
  const [form, setForm] = React.useState({
    customer_id: "", subject: "", body: "", type_id: "", priority: "normal",
    assigned_to: currentUserId || "",
  });
  const [busy, setBusy] = React.useState(false);
  const [err, setErr]   = React.useState("");

  React.useEffect(() => {
    Promise.all([
      api.support.listCustomers().catch(() => []),
      api.support.listTypes().catch(() => []),
      api.support.listAgents().catch(() => []),
    ]).then(([c, t, a]) => { setCustomers(c || []); setTypes(t || []); setAgents(a || []); });
  }, []);

  async function submit() {
    if (busy) return;
    if (!form.customer_id) { setErr("Pick a customer"); return; }
    if (!form.subject.trim()) { setErr("Subject is required"); return; }
    setBusy(true); setErr("");
    try {
      const r = await api.support.createTicket({
        customer_id: form.customer_id,
        subject: form.subject.trim(),
        body: form.body || null,
        type_id: form.type_id || null,
        priority: form.priority,
        assigned_to: form.assigned_to || null,
      });
      if (window.fbToast) window.fbToast("Ticket created", 2200);
      onCreated && onCreated(r && r.id);
    } catch (e) {
      setErr((e && e.body && (e.body.detail || e.body.message || e.body.error)) || (e && e.message) || "Could not create ticket");
    } finally { setBusy(false); }
  }

  return (
    <SupEditorModal
      title="New ticket"
      subtitle="Raise a ticket on a customer's behalf"
      onClose={onClose}
      onSave={submit}
      saveLabel="Create ticket"
      busyLabel="Creating…"
      busy={busy}
      maxWidth={540}
    >
      <label className="sup-field"><span>Customer *</span>
        <select value={form.customer_id} onChange={e => setForm({ ...form, customer_id: e.target.value })}>
          <option value="">— Select customer —</option>
          {customers.map(c => (
            <option key={c.id} value={c.id}>
              {c.name}{c.company ? ` · ${c.company}` : ""}{c.email ? ` (${c.email})` : ""}
            </option>
          ))}
        </select>
      </label>
      <label className="sup-field"><span>Subject *</span>
        <input value={form.subject} onChange={e => setForm({ ...form, subject: e.target.value })}
               placeholder="Short summary of the issue"/></label>
      <label className="sup-field"><span className="sup-field-head">Description
          <ProofreadButton text={form.body} onApply={v => setForm({ ...form, body: v })}/></span>
        <textarea rows={5} value={form.body} onChange={e => setForm({ ...form, body: e.target.value })}
                  placeholder="What's the customer reporting?"/></label>
      <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12 }}>
        <label className="sup-field"><span>Type</span>
          <select value={form.type_id} onChange={e => setForm({ ...form, type_id: e.target.value })}>
            <option value="">— None —</option>
            {types.map(t => (
              <option key={t.id} value={t.id}>
                {t.label}{t.credit_cost ? ` (${t.credit_cost} cr)` : ""}
              </option>
            ))}
          </select>
        </label>
        <label className="sup-field"><span>Priority</span>
          <select value={form.priority} onChange={e => setForm({ ...form, priority: e.target.value })}>
            {(typeof SUPPORT_PRIORITIES !== "undefined" ? SUPPORT_PRIORITIES : ["low","normal","high","urgent"])
              .map(p => <option key={p} value={p}>{p}</option>)}
          </select>
        </label>
      </div>
      <label className="sup-field"><span>Assign to</span>
        <select value={form.assigned_to} onChange={e => setForm({ ...form, assigned_to: e.target.value })}>
          <option value="">— Unassigned —</option>
          {agents.map(a => <option key={a.id} value={a.id}>{a.name}</option>)}
        </select>
      </label>
      {err && <div className="sup-modal-err">{err}</div>}
    </SupEditorModal>
  );
}

// ─────────────────────────────────────────────────────────────
// AI writing assistant — one-click grammar/spelling fix. Calls the
// free LanguageTool proxy (/api/ai/proofread) and applies the
// corrected text via onApply. Shows a toast with the fix count.
// ─────────────────────────────────────────────────────────────
function ProofreadButton({ text, onApply, style, label = "✨ Fix grammar" }) {
  const [busy, setBusy] = React.useState(false);
  async function run() {
    if (busy) return;
    const src = (text || "").trim();
    if (!src) { if (window.fbToast) window.fbToast("Nothing to check yet", 1800); return; }
    setBusy(true);
    try {
      const r = await api.ai.proofread(text);
      if (!r || !r.applied) {
        if (window.fbToast) window.fbToast("No issues found ✓", 2200);
      } else {
        onApply && onApply(r.corrected);
        if (window.fbToast) window.fbToast(`Fixed ${r.applied} issue${r.applied === 1 ? "" : "s"} ✨`, 2600);
      }
    } catch (e) {
      if (window.fbToast) window.fbToast("Writing assistant unavailable — try again", 3000);
    } finally { setBusy(false); }
  }
  return (
    <button type="button" className="btn-sm sup-ai-btn" onClick={run} disabled={busy}
            style={style} title="Fix grammar & spelling with the free writing assistant">
      {busy ? "Checking…" : label}
    </button>
  );
}

// Shared modal shell for every Support editor (canned, KB, new ticket,
// customer). Polished dialog: blurred scrim, lift-in animation, pinned
// header/footer with a scrollable body, ESC-to-close, and a bottom-sheet
// layout on phones. Pass a custom `footer` node to override the default
// Cancel / Save buttons.
function SupEditorModal({
  title, subtitle, children, onClose, onSave,
  saveLabel = "Save", busyLabel = "Saving…", busy = false,
  maxWidth = 560, footer,
}) {
  React.useEffect(() => {
    const onKey = (e) => { if (e.key === "Escape" && onClose) onClose(); };
    document.addEventListener("keydown", onKey);
    return () => document.removeEventListener("keydown", onKey);
  }, [onClose]);
  return ReactDOM.createPortal(
    <div className="sup-modal-backdrop" onClick={onClose}>
      <div className="sup-modal" style={{ maxWidth }} role="dialog" aria-modal="true"
           onClick={e => e.stopPropagation()}>
        <div className="sup-modal-head">
          <div className="sup-modal-titles">
            <div className="sup-modal-title">{title}</div>
            {subtitle ? <div className="sup-modal-sub">{subtitle}</div> : null}
          </div>
          <button className="sup-modal-close" onClick={onClose} aria-label="Close">×</button>
        </div>
        <div className="sup-modal-body">{children}</div>
        <div className="sup-modal-foot">
          {footer || (
            <>
              <button className="btn" onClick={onClose} disabled={busy}>Cancel</button>
              <button className="btn btn-primary" onClick={onSave} disabled={busy}>
                {busy ? busyLabel : saveLabel}
              </button>
            </>
          )}
        </div>
      </div>
    </div>,
    document.body
  );
}

const SUP_EXTRA_CSS = `
/* New Support tabs — share the 28px content gutter + card language of
   the Tickets tab so everything lines up across the module. */
.sup-dash, .sup-canned, .sup-kb {
  padding: 18px 28px 40px;
  display: flex; flex-direction: column; gap: 14px;
}
@media (max-width: 760px) {
  .sup-dash, .sup-canned, .sup-kb { padding: 14px 14px 40px; }
}

/* KPI strip */
.sup-dash-kpis {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 12px;
}
.sup-dash-kpi {
  text-align: left; padding: 16px 18px;
  border: 1px solid var(--border); border-radius: var(--r-md);
  background: var(--bg-surface, #fff);
  box-shadow: var(--shadow-sm);
  transition: transform .1s ease, box-shadow .12s ease, border-color .1s ease;
}
.sup-dash-kpi[style*="pointer"]:hover {
  transform: translateY(-1px);
  box-shadow: var(--shadow-md);
  border-color: var(--border-strong, var(--brand));
}
.sup-dash-kpi-value {
  font-size: 26px; font-weight: 800; color: var(--ink-strong);
  font-variant-numeric: tabular-nums; letter-spacing: -0.01em; line-height: 1.1;
}
.sup-dash-kpi-label { font-size: 11.5px; color: var(--ink-muted); margin-top: 5px; font-weight: 500; }
.sup-dash-kpi.tone-brand  .sup-dash-kpi-value { color: var(--brand-dark, #0073ea); }
.sup-dash-kpi.tone-danger .sup-dash-kpi-value { color: #b41f37; }
.sup-dash-kpi.tone-ok     .sup-dash-kpi-value { color: #066039; }

/* Two-up breakdown cards */
.sup-dash-row { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
@media (max-width: 760px) { .sup-dash-row { grid-template-columns: 1fr; } }
.sup-dash-card {
  border: 1px solid var(--border); border-radius: var(--r-md);
  background: var(--bg-surface, #fff); box-shadow: var(--shadow-sm);
  padding: 0; overflow: hidden;
}
.sup-dash-card h3 {
  margin: 0; padding: 12px 16px;
  font-size: 13px; font-weight: 700; color: var(--ink-strong);
  border-bottom: 1px solid var(--border-row); background: #fafbfc;
}
.sup-dash-bar-row {
  display: flex; align-items: center; justify-content: space-between;
  padding: 10px 16px; border-bottom: 1px solid var(--border-row); font-size: 12.5px;
}
.sup-dash-bar-row:last-child { border-bottom: none; }
.sup-dash-bar-label { color: var(--ink-strong); text-transform: capitalize; font-weight: 500; }
.sup-dash-bar-count { font-weight: 800; color: var(--ink-strong); font-variant-numeric: tabular-nums; }
.sup-empty-sm { color: var(--ink-muted); font-size: 12.5px; padding: 16px; text-align: center; font-style: italic; }

/* Section head (count + new button) */
.sup-section-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; flex-wrap: wrap;
}
.sup-section-head > div:first-child { font-size: 13px; color: var(--ink-muted); }

/* Canned + KB list cards */
.sup-canned-list, .sup-kb-list { display: flex; flex-direction: column; gap: 10px; }
.sup-canned-card, .sup-kb-card {
  border: 1px solid var(--border); border-radius: var(--r-md);
  background: var(--bg-surface, #fff); box-shadow: var(--shadow-sm);
  padding: 14px 16px;
  transition: box-shadow .12s ease, border-color .1s ease;
}
.sup-canned-card:hover, .sup-kb-card:hover { box-shadow: var(--shadow-md); border-color: var(--border-strong, var(--border)); }
.sup-canned-card-head, .sup-kb-card-head {
  display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 8px;
}
.sup-canned-card-head > b, .sup-kb-card-head > div > b { font-size: 13.5px; color: var(--ink-strong); }
.sup-canned-actions { display: flex; gap: 6px; flex-shrink: 0; }
.btn-sm {
  font-size: 11.5px; font-weight: 600; padding: 5px 10px;
  border: 1px solid var(--border); border-radius: var(--r-sm, 6px);
  background: var(--bg-surface, #fff); color: var(--ink-strong); cursor: pointer;
  transition: background .1s, border-color .1s;
}
.btn-sm:hover { background: var(--bg-subtle, #f7f8fb); border-color: var(--border-strong, var(--border)); }
.sup-canned-body { font-size: 12.5px; color: var(--ink-muted); white-space: pre-wrap; line-height: 1.5; }
.sup-kb-cat {
  margin-left: 8px; font-size: 10.5px; font-weight: 700;
  padding: 2px 8px; border-radius: 999px; background: var(--bg-subtle, #eef0f5); color: var(--ink-muted);
  vertical-align: middle;
}
.sup-kb-vis { margin-left: 6px; font-size: 10px; font-weight: 700; padding: 2px 8px; border-radius: 999px; vertical-align: middle; }
.sup-kb-vis.pub { background: #e6f9ef; color: #066039; }
.sup-kb-vis.int { background: #fff3e0; color: #8c4a00; }

/* Editor modal fields */
.sup-field { display: flex; flex-direction: column; gap: 6px; margin-bottom: 14px; font-size: 13px; }
.sup-field > span { font-weight: 600; color: var(--ink-strong); }
.sup-field input, .sup-field select, .sup-field textarea {
  padding: 9px 11px; border: 1px solid var(--border); border-radius: var(--r-md);
  font-family: inherit; font-size: 13px; color: var(--ink-strong);
  background: var(--bg-surface, #fff);
  transition: border-color .12s, box-shadow .12s;
}
.sup-field input::placeholder, .sup-field textarea::placeholder { color: var(--ink-faint, #9aa3b2); }
.sup-field input:focus, .sup-field select:focus, .sup-field textarea:focus {
  outline: none; border-color: var(--brand); box-shadow: 0 0 0 3px var(--brand-soft);
}
.sup-field textarea { resize: vertical; min-height: 64px; line-height: 1.5; }
.sup-field select {
  appearance: none; -webkit-appearance: none; cursor: pointer; padding-right: 32px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%236b7280' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 11px center;
}

/* Field header row — label text on the left, "Fix grammar" on the right */
.sup-field-head {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
}

/* AI writing-assistant button (free-tier grammar/spelling) */
.sup-ai-btn {
  display: inline-flex; align-items: center; gap: 5px;
  font-weight: 600; font-size: 12px; white-space: nowrap;
  color: var(--brand-dark, #0073ea);
  background: var(--brand-soft, #e6f0ff);
  border: 1px solid transparent; border-radius: var(--r-md);
  padding: 4px 10px; cursor: pointer;
  transition: background .12s ease, color .12s ease, opacity .12s ease;
}
.sup-ai-btn:hover:not(:disabled) { background: var(--brand, #0073ea); color: #fff; }
.sup-ai-btn:disabled { opacity: .6; cursor: default; }

/* ─── Unified Support modal shell ─────────────────────────────
   One polished dialog used by New ticket, canned/KB editors and the
   customer editor. Fades in over a blurred scrim, lifts up on entry,
   keeps header + footer pinned while the body scrolls, and drops to a
   bottom-sheet on phones. */
@keyframes sup-modal-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes sup-modal-pop  { from { opacity: 0; transform: translateY(14px) scale(.985); } to { opacity: 1; transform: none; } }
@keyframes sup-modal-sheet { from { transform: translateY(100%); } to { transform: none; } }

.sup-modal-backdrop {
  position: fixed; inset: 0; z-index: 1200;
  display: flex; align-items: center; justify-content: center;
  padding: 24px;
  background: rgba(15, 22, 40, .48);
  -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px);
  animation: sup-modal-fade .16s ease;
}
.sup-modal {
  width: 100%; max-width: 560px;
  max-height: calc(100vh - 48px);
  display: flex; flex-direction: column;
  background: var(--bg-surface, #fff);
  border: 1px solid var(--border);
  border-radius: 16px;
  box-shadow: 0 24px 70px rgba(15, 22, 40, .34);
  overflow: hidden;
  animation: sup-modal-pop .2s cubic-bezier(.16, .84, .44, 1);
}
.sup-modal-head {
  display: flex; align-items: flex-start; gap: 12px;
  padding: 18px 20px 14px;
  border-bottom: 1px solid var(--border-row, var(--border));
}
.sup-modal-titles { flex: 1; min-width: 0; }
.sup-modal-title {
  font-size: 16px; font-weight: 800; letter-spacing: -0.01em;
  color: var(--ink-strong); line-height: 1.25;
}
.sup-modal-sub { font-size: 12.5px; color: var(--ink-muted); margin-top: 3px; line-height: 1.4; }
.sup-modal-close {
  flex: none; width: 30px; height: 30px; border-radius: 8px;
  border: 1px solid transparent; background: transparent;
  font-size: 20px; line-height: 1; color: var(--ink-muted);
  display: flex; align-items: center; justify-content: center; cursor: pointer;
  transition: background .12s ease, color .12s ease;
}
.sup-modal-close:hover { background: var(--bg-subtle, #eef0f5); color: var(--ink-strong); }
.sup-modal-body {
  padding: 18px 20px; overflow-y: auto;
  display: flex; flex-direction: column;
}
.sup-modal-body > .sup-field:last-child { margin-bottom: 0; }
.sup-modal-foot {
  display: flex; justify-content: flex-end; gap: 8px;
  padding: 14px 20px;
  border-top: 1px solid var(--border-row, var(--border));
  background: var(--bg-subtle, #fafbfc);
}
.sup-modal-err {
  margin-top: 4px; padding: 9px 11px; border-radius: var(--r-md);
  font-size: 12.5px; font-weight: 500;
  color: #b41f37; background: #fdecef; border: 1px solid #f6c9d2;
}

@media (max-width: 600px) {
  .sup-modal-backdrop { padding: 0; align-items: flex-end; }
  .sup-modal {
    max-width: none; max-height: 92vh;
    border-radius: 16px 16px 0 0;
    animation: sup-modal-sheet .24s cubic-bezier(.16, .84, .44, 1);
  }
}
`;

// ─────────────────────────────────────────────────────────────
// Tickets
// ─────────────────────────────────────────────────────────────
function TicketsTab({ currentUserId, simNowMin = 0, onAdvanceSim, onResetSim }) {
  const [tickets, setTickets] = React.useState(null);
  const [openId, setOpenId]   = React.useState(null);
  const [creating, setCreating] = React.useState(false);
  const [filters, setFilters] = React.useState({ status: "", priority: "", q: "" });

  // Esc closes the drawer
  React.useEffect(() => {
    if (!openId) return;
    function onKey(e) { if (e.key === "Escape") setOpenId(null); }
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [openId]);

  async function load() {
    try {
      const params = {};
      if (filters.status)   params.status = filters.status;
      if (filters.priority) params.priority = filters.priority;
      if (filters.q)        params.q = filters.q;
      setTickets(await api.support.listTickets(params));
    } catch (e) { setTickets([]); }
  }
  React.useEffect(() => { load(); /* eslint-disable-next-line */ }, [filters.status, filters.priority]);
  React.useEffect(() => {
    const t = setTimeout(load, 250); return () => clearTimeout(t);
    /* eslint-disable-next-line */
  }, [filters.q]);

  // Group tickets by status so each status renders as its own task-table-
  // style card (mirrors the .epic-group / .t pattern from project tasks).
  // We honour the order of SUPPORT_STATUSES so Open is always at the top.
  const grouped = React.useMemo(() => {
    if (!tickets) return null;
    const map = new Map(SUPPORT_STATUSES.map(s => [s.id, []]));
    const stray = [];
    for (const t of tickets) {
      if (map.has(t.status)) map.get(t.status).push(t);
      else stray.push(t);
    }
    const arr = SUPPORT_STATUSES.map(s => ({ ...s, items: map.get(s.id) || [] }));
    if (stray.length) arr.push({ id: "_other", label: "Other", color: "#9aa0ae", items: stray });
    return arr.filter(g => g.items.length > 0);
  }, [tickets]);

  const totalCount = tickets ? tickets.length : 0;

  return (
    <div className="sup-tickets">
      <div className="sup-tickets-toolbar">
        <input type="text" className="sup-search"
               placeholder="Search subject or body…"
               value={filters.q} onChange={e => setFilters(f => ({ ...f, q: e.target.value }))}/>
        <select value={filters.status} onChange={e => setFilters(f => ({ ...f, status: e.target.value }))}>
          <option value="">All statuses</option>
          {SUPPORT_STATUSES.map(s => <option key={s.id} value={s.id}>{s.label}</option>)}
        </select>
        <select value={filters.priority} onChange={e => setFilters(f => ({ ...f, priority: e.target.value }))}>
          <option value="">All priorities</option>
          {SUPPORT_PRIORITIES.map(p => <option key={p} value={p}>{p}</option>)}
        </select>
        <div style={{ marginLeft: "auto", display: "flex", alignItems: "center", gap: 10 }}>
          {tickets && <span className="sup-toolbar-count">{totalCount} ticket{totalCount === 1 ? "" : "s"}</span>}
          <button className="btn" onClick={load}>Refresh</button>
          <button className="btn btn-primary" onClick={() => setCreating(true)}>+ New ticket</button>
        </div>
      </div>

      {creating && (
        <NewTicketModal currentUserId={currentUserId}
          onClose={() => setCreating(false)}
          onCreated={(id) => { setCreating(false); load(); if (id) setOpenId(id); }}/>
      )}

      <div className="sup-ticket-grid is-full">
        <div className="sup-ticket-col">
          {tickets === null ? (
            <div className="sup-empty">Loading…</div>
          ) : tickets.length === 0 ? (
            <div className="sup-empty">No tickets match your filters.</div>
          ) : (
            grouped.map(group => (
              <SupTicketGroup
                key={group.id}
                group={group}
                openId={openId}
                onOpen={(id) => setOpenId(id)}
                simNowMin={simNowMin}
              />
            ))
          )}
        </div>
      </div>

      {/* Slide-in drawer for the selected ticket */}
      {openId && (
        <div className="sup-drawer-root" onClick={() => setOpenId(null)}>
          <div className="sup-drawer-backdrop"/>
          <div className="sup-drawer" onClick={e => e.stopPropagation()}>
            <button className="sup-drawer-close" aria-label="Close" onClick={() => setOpenId(null)}>
              <svg width="18" height="18" viewBox="0 0 16 16" fill="none">
                <path d="M4 4l8 8M12 4l-8 8" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round"/>
              </svg>
            </button>
            <SupTicketDetail
              key={openId}
              id={openId}
              currentUserId={currentUserId}
              onChanged={load}
              onClose={() => setOpenId(null)}
              simNowMin={simNowMin}
              onAdvanceSim={onAdvanceSim}
              onResetSim={onResetSim}
            />
          </div>
        </div>
      )}
    </div>
  );
}

// SupTicketGroup — one status group rendered as a task-table card. The
// header stripe is colored by the status; the table inside borrows .t
// styling from the main task table so rows scan identically.
function SupTicketGroup({ group, openId, onOpen, simNowMin = 0 }) {
  const [collapsed, setCollapsed] = React.useState(false);
  const accent = group.color;
  return (
    <div className={`sup-group ${collapsed ? "is-collapsed" : ""}`}
         style={{ "--sup-group-color": accent }}>
      <div className="sup-group-head" onClick={() => setCollapsed(c => !c)}>
        <svg className="sup-group-chev" viewBox="0 0 16 16" fill="none">
          <path d="M5 6l3 3 3-3" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"/>
        </svg>
        <span className="sup-group-title">{group.label}</span>
        <span className="sup-group-count">{group.items.length}</span>
      </div>
      {!collapsed && (
        <div className="sup-group-table-wrap">
          <table className="sup-t">
            <thead>
              <tr>
                <th className="sup-th-name">Subject</th>
                <th className="sup-th-cell">Customer</th>
                <th className="sup-th-cell">Project</th>
                <th className="sup-th-cell">Type</th>
                <th className="sup-th-center">Priority</th>
                <th className="sup-th-center">Assignee</th>
                <th className="sup-th-center">SLA</th>
                <th className="sup-th-center">Credits</th>
                <th className="sup-th-cell">Created</th>
              </tr>
            </thead>
            <tbody>
              {group.items.map(t => (
                <tr key={t.id}
                    className={`sup-tr ${openId === t.id ? "is-selected" : ""}`}
                    onClick={() => onOpen(t.id)}>
                  <td className="sup-td-name">
                    <div className="sup-td-name-wrap">
                      <span className="sup-td-name-text">{t.subject}</span>
                      {t.linked_task_id && <span className="sup-task-pill" title="Escalated to engineering">🔗</span>}
                    </div>
                    <div className="sup-td-id">{t.id}</div>
                  </td>
                  <td className="sup-td-cell">
                    <div className="sup-td-customer">{t.customer_name || "—"}</div>
                    {t.company && <div className="sup-td-customer-sub">{t.company}</div>}
                  </td>
                  <td className="sup-td-cell">
                    {t.project_name ? (
                      <span className="sup-proj-pill"
                            style={t.project_color ? { background: t.project_color + "22", color: t.project_color } : undefined}>
                        {t.project_name}
                      </span>
                    ) : <span className="sup-faint">—</span>}
                  </td>
                  <td className="sup-td-cell">{t.type_label || <span className="sup-faint">—</span>}</td>
                  <td className="sup-td-center">
                    <span className={`sup-prio sup-prio-${t.priority}`}>{t.priority}</span>
                  </td>
                  <td className="sup-td-center">
                    {t.assignee_name
                      ? <SupAvatar name={t.assignee_name} color={t.assignee_color}/>
                      : <span className="sup-faint">—</span>}
                  </td>
                  <td className="sup-td-center">
                    {typeof SlaPill === "function"
                      ? <SlaPill ticket={t}
                                 customer={{ planId: t.customer_plan_id || t.plan_id || null }}
                                 simNowMin={simNowMin} compact/>
                      : <span className="sup-faint">—</span>}
                  </td>
                  <td className="sup-td-center">
                    <span className="sup-credits-pill">{t.credits_charged || 0}</span>
                  </td>
                  <td className="sup-td-cell sup-td-meta">
                    {fmtRel ? fmtRel(t.created_at) : (t.created_at || "")}
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      )}
    </div>
  );
}

function SupTicketDetail({ id, currentUserId, onChanged, onClose, simNowMin = 0, onAdvanceSim, onResetSim }) {
  const [t, setT]     = React.useState(null);
  const [reply, setReply] = React.useState("");
  const [busy, setBusy]   = React.useState(false);

  async function load() {
    try { setT(await api.support.getTicket(id)); }
    catch (e) { console.warn(e); }
  }
  React.useEffect(() => { load(); }, [id]);

  async function setStatus(s)   { await api.support.patchTicket(id, { status: s }); load(); onChanged && onChanged(); }
  async function setPriority(p) { await api.support.patchTicket(id, { priority: p }); load(); onChanged && onChanged(); }
  async function assignSelf()   { await api.support.patchTicket(id, { assigned_to: currentUserId }); load(); onChanged && onChanged(); }
  async function unassign()     { await api.support.patchTicket(id, { assigned_to: null }); load(); onChanged && onChanged(); }
  async function send() {
    if (!reply.trim()) return;
    setBusy(true);
    try { await api.support.replyTicket(id, reply.trim()); setReply(""); await load(); onChanged && onChanged(); }
    finally { setBusy(false); }
  }
  async function attach(file) {
    try { await api.support.attachTicket(id, file); await load(); }
    catch (e) { alert("Upload failed: " + e.message); }
  }

  if (!t) return <div className="sup-detail-empty">Loading…</div>;

  return (
    <div className="sup-detail">
      <div className="sup-detail-head">
        <div>
          <div className="sup-detail-id">{t.id}</div>
          <h3>{t.subject}</h3>
          <div className="sup-detail-cust">
            <b>{t.customer_name}</b>
            <span>{t.customer_email}</span>
            {t.customer_company && <span>· {t.customer_company}</span>}
          </div>
        </div>
        <button className="btn" onClick={onClose}>Close</button>
      </div>

      <div className="sup-detail-controls">
        <label>Status
          <select value={t.status} onChange={e => setStatus(e.target.value)}>
            {SUPPORT_STATUSES.map(s => <option key={s.id} value={s.id}>{s.label}</option>)}
          </select>
        </label>
        <label>Priority
          <select value={t.priority} onChange={e => setPriority(e.target.value)}>
            {SUPPORT_PRIORITIES.map(p => <option key={p} value={p}>{p}</option>)}
          </select>
        </label>
        <div className="sup-detail-assignee">
          {t.assignee_name
            ? <>Assigned to <b>{t.assignee_name}</b> <button className="btn" onClick={unassign}>Unassign</button></>
            : <button className="btn" onClick={assignSelf}>Assign to me</button>}
        </div>
        {t.type_label && <span className="sup-detail-tag">{t.type_label} · {t.credits_charged} credits</span>}
      </div>

      <SupEscalatePanel t={t} onChanged={() => { load(); onChanged && onChanged(); }}/>

      {/* ── SLA strip (drawer headline panel) ── */}
      {typeof SlaStrip === "function" && (
        <div style={{ margin: "14px 18px 0" }}>
          <SlaStrip ticket={t}
                    customer={{ planId: t.customer_plan_id || t.plan_id || null }}
                    simNowMin={simNowMin}
                    onAdvance={onAdvanceSim} onReset={onResetSim}/>
        </div>
      )}

      {/* ── Responder chain ── */}
      {typeof SlaResponderChain === "function" && (
        <div className="sup-detail-section">
          <div className="sup-detail-section-head">
            <span className="sup-detail-section-title">Responder chain</span>
            <span className="sup-detail-section-sub">L1 → L2 → L3 · promotes if unavailable</span>
          </div>
          <SlaResponderChain ticket={t} simNowMin={simNowMin}/>
        </div>
      )}

      {/* ── Notifications fired (simulated) ── */}
      {typeof SlaNotificationLog === "function" && (
        <div className="sup-detail-section">
          <div className="sup-detail-section-head">
            <span className="sup-detail-section-title">Notifications fired</span>
            <span className="sup-detail-section-sub">Email + WhatsApp · simulated cascade</span>
          </div>
          <SlaNotificationLog ticket={t}
                              customer={{ planId: t.customer_plan_id || t.plan_id || null }}
                              simNowMin={simNowMin}/>
        </div>
      )}

      {t.body && <div className="sup-detail-body">{t.body}</div>}

      {t.attachments && t.attachments.length > 0 && (
        <div className="sup-attachments">
          {t.attachments.map(a => (
            <SupAttachment key={a.id} a={a}/>
          ))}
        </div>
      )}

      <div className="sup-thread">
        {(t.comments || []).map(c => (
          <div key={c.id} className={`sup-comment is-${c.author_kind}`}>
            <div className="sup-comment-meta">
              {c.author_kind === "customer" ? "Customer" : "You / agent"} · {fmtRel ? fmtRel(c.created_at) : c.created_at}
            </div>
            <div className="sup-comment-body">{c.body}</div>
          </div>
        ))}
        {(!t.comments || !t.comments.length) && <div className="sup-thread-empty">No replies yet.</div>}
      </div>

      <div className="sup-reply">
        <textarea rows={3} placeholder="Reply to the customer…"
                  value={reply} onChange={e => setReply(e.target.value)}/>
        <div className="sup-reply-actions">
          <label className="btn">
            📎 Attach
            <input type="file" style={{ display: "none" }}
                   onChange={(e) => { if (e.target.files && e.target.files[0]) attach(e.target.files[0]); e.target.value = ""; }}/>
          </label>
          <ProofreadButton text={reply} onApply={setReply}/>
          <button className="btn btn-primary" disabled={busy || !reply.trim()} onClick={send}>
            {busy ? "Sending…" : "Send reply"}
          </button>
        </div>
      </div>
    </div>
  );
}

// SupEscalatePanel — turn a customer ticket into a project task and assign
// it to a developer. If the ticket already has a linked task we just
// surface the link instead of letting the agent create a duplicate.
function SupEscalatePanel({ t, onChanged }) {
  const [open, setOpen]   = React.useState(false);
  const [projects, setProjects] = React.useState([]);
  const [users, setUsers]       = React.useState([]);
  const [projectId, setProjectId] = React.useState(t.project_id || "");
  const [name, setName]         = React.useState(t.subject || "");
  const [description, setDescription] = React.useState(t.body || "");
  const [priority, setPriority] = React.useState("medium");
  const [assignees, setAssignees] = React.useState([]);
  const [busy, setBusy]         = React.useState(false);
  const [error, setError]       = React.useState("");

  React.useEffect(() => {
    if (!open) return;
    api.support.listSupportProjects().then(setProjects).catch(() => setProjects([]));
    api.users.list().then(rows => setUsers(rows.filter(u => u.status !== "deactivated"))).catch(() => setUsers([]));
  }, [open]);

  // If a customer-linked project list comes through, prefer that. Otherwise
  // fall back to all workspace projects (the linker is admin-only anyway).
  React.useEffect(() => {
    if (!open || !t.customer_id) return;
    api.support.listCustomerProjects(t.customer_id).then(rows => {
      if (rows && rows.length) {
        setProjects(rows);
        if (!projectId && rows.length) setProjectId(rows[0].id);
      }
    }).catch(() => {});
    // eslint-disable-next-line
  }, [open, t.customer_id]);

  async function escalate() {
    setError("");
    if (!projectId) { setError("Pick a project."); return; }
    if (!name.trim()) { setError("Task name is required."); return; }
    setBusy(true);
    try {
      await api.support.escalateTicket(t.id, {
        project_id: projectId,
        name: name.trim(),
        description,
        priority,
        assignees,
      });
      onChanged && onChanged();
      setOpen(false);
    } catch (e) {
      if (e && e.status === 409) {
        setError("This ticket has already been escalated.");
      } else {
        setError(e.message || "Could not escalate.");
      }
    } finally { setBusy(false); }
  }

  if (t.linked_task_id) {
    return (
      <div className="sup-escalate-bar">
        <span className="sup-escalate-label">🔗 Escalated to project task</span>
        <code className="sup-escalate-code">{t.linked_task_id}</code>
        {t.linked_task_name && <span className="sup-escalate-name">{t.linked_task_name}</span>}
        {t.linked_task_status && <span className={`sup-mini-status sup-status-${t.linked_task_status}`}>{t.linked_task_status}</span>}
      </div>
    );
  }

  if (!open) {
    return (
      <div className="sup-escalate-bar">
        <span className="sup-escalate-label">No engineering task yet.</span>
        <button className="btn btn-primary" onClick={() => setOpen(true)}>
          🚀 Escalate to project
        </button>
      </div>
    );
  }

  function toggleAssignee(uid) {
    setAssignees(arr => arr.includes(uid) ? arr.filter(x => x !== uid) : [...arr, uid]);
  }

  return (
    <div className="sup-escalate-form">
      <div className="sup-escalate-head">
        <h4>Escalate to a project task</h4>
        <button className="btn" onClick={() => setOpen(false)} disabled={busy}>Cancel</button>
      </div>
      <div className="sup-escalate-grid">
        <label>Project
          <select value={projectId} onChange={e => setProjectId(e.target.value)}>
            <option value="">— Pick a project —</option>
            {projects.map(p => <option key={p.id} value={p.id}>{p.name}</option>)}
          </select>
        </label>
        <label>Priority
          <select value={priority} onChange={e => setPriority(e.target.value)}>
            <option value="critical">Critical</option>
            <option value="high">High</option>
            <option value="medium">Medium</option>
            <option value="low">Low</option>
            <option value="none">None</option>
          </select>
        </label>
      </div>
      <label className="sup-escalate-full">Task name
        <input type="text" value={name} onChange={e => setName(e.target.value)}/>
      </label>
      <label className="sup-escalate-full">Description
        <textarea rows={4} value={description} onChange={e => setDescription(e.target.value)}/>
      </label>
      <div className="sup-escalate-assignees">
        <div className="sup-escalate-assignees-head">Assign to</div>
        <div className="sup-escalate-chips">
          {users.map(u => (
            <label key={u.id} className={`sup-assignee-chip ${assignees.includes(u.id) ? "is-on" : ""}`}>
              <input type="checkbox" checked={assignees.includes(u.id)} onChange={() => toggleAssignee(u.id)}/>
              <span style={{ background: u.color || "var(--brand)" }}>{(u.name || "?").slice(0, 1)}</span>
              {u.name}
            </label>
          ))}
        </div>
      </div>
      {error && <div className="sup-escalate-error">{error}</div>}
      <div className="sup-escalate-foot">
        <button className="btn btn-primary" onClick={escalate} disabled={busy || !projectId || !name.trim()}>
          {busy ? "Creating task…" : "Create task & assign"}
        </button>
      </div>
    </div>
  );
}

function SupAttachment({ a }) {
  if (a.kind === "image") return <a href={a.url} target="_blank" rel="noopener noreferrer" className="sup-att sup-att-image"><img src={a.url} alt={a.original_name}/></a>;
  if (a.kind === "video") return <video src={a.url} controls className="sup-att sup-att-video"/>;
  return <a href={a.url} target="_blank" rel="noopener noreferrer" className="sup-att sup-att-file">📎 {a.original_name}</a>;
}

// ─────────────────────────────────────────────────────────────
// Customers tab — list + create modal
// ─────────────────────────────────────────────────────────────
function CustomersTab() {
  const [rows, setRows] = React.useState(null);
  const [plans, setPlans] = React.useState([]);
  const [composing, setComposing] = React.useState(false);
  const [editId, setEditId] = React.useState(null);

  async function load() {
    try {
      const [list, p] = await Promise.all([api.support.listCustomers(), api.support.listPlans()]);
      setRows(list); setPlans(p);
    } catch (e) { setRows([]); }
  }
  React.useEffect(() => { load(); }, []);

  async function suspend(id, on) {
    await api.support.patchCustomer(id, { status: on ? "suspended" : "active" });
    load();
  }
  async function topup(c) {
    const v = prompt(`Top-up credits for ${c.name}\nCurrently: ${c.credits_remaining}`, String(c.monthly_credits || 100));
    if (v == null) return;
    const n = parseInt(v, 10);
    if (!Number.isFinite(n) || n < 0) return;
    await api.support.patchCustomer(c.id, { credits_remaining: n });
    load();
  }
  async function setPlan(c, planId) {
    await api.support.patchCustomer(c.id, { plan_id: planId || null });
    load();
  }
  async function remove(id) {
    if (!confirm("Delete this customer? Their tickets will go too.")) return;
    await api.support.removeCustomer(id);
    load();
  }

  return (
    <div className="sup-customers">
      <div className="sup-tickets-toolbar">
        <div style={{ flex: 1 }}/>
        <button className="btn btn-primary" onClick={() => setComposing(true)}>+ New customer</button>
      </div>

      {rows === null ? (
        <div className="sup-empty">Loading…</div>
      ) : rows.length === 0 ? (
        <div className="sup-empty">No customers yet — click <b>+ New customer</b> to create one.</div>
      ) : (
        <div className="sup-group" style={{ "--sup-group-color": "var(--brand)" }}>
          <div className="sup-group-head">
            <span className="sup-group-title">Customers</span>
            <span className="sup-group-count">{rows.length}</span>
          </div>
          <div className="sup-group-table-wrap">
            <table className="sup-t sup-t-customers">
              <thead>
                <tr>
                  <th className="sup-th-name">Customer</th>
                  <th className="sup-th-cell">Plan</th>
                  <th className="sup-th-center">Credits</th>
                  <th className="sup-th-center">Tickets</th>
                  <th className="sup-th-cell">Last seen</th>
                  <th className="sup-th-center">Status</th>
                  <th className="sup-th-cell sup-th-actions">Actions</th>
                </tr>
              </thead>
              <tbody>
                {rows.map(c => (
                  <tr key={c.id} className="sup-tr">
                    <td className="sup-td-name">
                      <div className="sup-td-customer">{c.name}</div>
                      <div className="sup-td-customer-sub">
                        {c.email}{c.company ? ` · ${c.company}` : ""}
                      </div>
                    </td>
                    <td className="sup-td-cell">
                      <select className="sup-inline-select" value={c.plan_id || ""}
                              onChange={e => setPlan(c, e.target.value)}>
                        <option value="">— No plan —</option>
                        {plans.map(p => <option key={p.id} value={p.id}>{p.name} ({p.monthly_credits}/mo)</option>)}
                      </select>
                    </td>
                    <td className="sup-td-center">
                      <span className="sup-credits-pill">{c.credits_remaining}</span>
                      {c.monthly_credits ? <span className="sup-cust-cap"> / {c.monthly_credits}</span> : null}
                      <button className="sup-cust-mini" onClick={() => topup(c)}>Top up</button>
                    </td>
                    <td className="sup-td-center">
                      <b>{c.ticket_count}</b>
                      <span className="sup-cust-cap"> ({c.open_count} open)</span>
                    </td>
                    <td className="sup-td-cell sup-td-meta">
                      {c.last_login_at ? (fmtRel ? fmtRel(c.last_login_at) : c.last_login_at) : "Never"}
                    </td>
                    <td className="sup-td-center">
                      <span className={`sup-pill sup-pill-${c.status}`}>{c.status}</span>
                    </td>
                    <td className="sup-td-cell">
                      <div className="sup-cust-actions">
                        <button className="btn" onClick={() => setEditId(c.id)}>Edit</button>
                        <button className="btn" onClick={() => suspend(c.id, c.status !== "suspended")}>
                          {c.status === "suspended" ? "Reactivate" : "Suspend"}
                        </button>
                        <button className="btn sup-cust-del" onClick={() => remove(c.id)}>Delete</button>
                      </div>
                    </td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        </div>
      )}

      {composing && <CustomerEditor plans={plans} onClose={() => setComposing(false)} onSaved={() => { setComposing(false); load(); }}/>}
      {editId && <CustomerEditor id={editId} plans={plans} onClose={() => setEditId(null)} onSaved={() => { setEditId(null); load(); }}/>}
    </div>
  );
}

function CustomerEditor({ id, plans, onClose, onSaved }) {
  const [form, setForm] = React.useState({ name: "", email: "", company: "", plan_id: "", password: "" });
  const [allProjects, setAllProjects] = React.useState([]);
  const [linkedIds, setLinkedIds]     = React.useState([]);
  const isNew = !id;

  React.useEffect(() => {
    api.support.listSupportProjects().then(setAllProjects).catch(() => setAllProjects([]));
    if (!isNew) {
      api.support.listCustomerProjects(id).then(rows => setLinkedIds(rows.map(r => r.id))).catch(() => {});
      // Hydrate the form from the existing customer row so editing actually
      // shows current values rather than blanks. (List view loads the
      // customer rows already; we re-fetch the single row here for the
      // editor only — keeps the components decoupled.)
      api.support.listCustomers().then(rows => {
        const c = rows.find(r => r.id === id);
        if (c) setForm({
          name: c.name || "", email: c.email || "", company: c.company || "",
          plan_id: c.plan_id || "", password: "",
        });
      }).catch(() => {});
    }
    // eslint-disable-next-line
  }, [id]);

  function toggleProject(pid) {
    setLinkedIds(arr => arr.includes(pid) ? arr.filter(x => x !== pid) : [...arr, pid]);
  }

  async function save() {
    try {
      const payload = {
        name: form.name.trim(),
        email: form.email.trim(),
        company: form.company.trim() || null,
        plan_id: form.plan_id || null,
      };
      if (form.password) payload.password = form.password;
      let savedId = id;
      if (isNew) {
        if (!payload.password || payload.password.length < 6) { alert("Set a password (min 6 chars)."); return; }
        const r = await api.support.createCustomer(payload);
        savedId = r && r.id;
      } else {
        await api.support.patchCustomer(id, payload);
      }
      // Persist the linked-projects set whenever we have a saved id.
      if (savedId) {
        try { await api.support.setCustomerProjects(savedId, linkedIds); }
        catch (e) { console.warn("Could not save linked projects:", e.message); }
      }
      onSaved && onSaved();
    } catch (e) {
      alert("Save failed: " + e.message);
    }
  }

  return (
    <SupEditorModal
      title={isNew ? "New customer" : "Edit customer"}
      subtitle={isNew ? "They'll sign in at /portal/" : null}
      onClose={onClose}
      onSave={save}
      saveLabel={isNew ? "Create customer" : "Save changes"}
      maxWidth={480}
    >
      <label className="sup-field"><span>Name</span>
        <input value={form.name} onChange={e => setForm(f => ({ ...f, name: e.target.value }))}/>
      </label>
      <label className="sup-field"><span>Email</span>
        <input type="email" value={form.email} onChange={e => setForm(f => ({ ...f, email: e.target.value }))}/>
      </label>
      <label className="sup-field"><span>Company</span>
        <input value={form.company} onChange={e => setForm(f => ({ ...f, company: e.target.value }))}/>
      </label>
      <label className="sup-field"><span>Plan</span>
        <select value={form.plan_id} onChange={e => setForm(f => ({ ...f, plan_id: e.target.value }))}>
          <option value="">— No plan —</option>
          {plans.map(p => <option key={p.id} value={p.id}>{p.name} ({p.monthly_credits}/mo)</option>)}
        </select>
      </label>
      <label className="sup-field">
        <span>{isNew ? "Initial password" : "New password (leave blank to keep)"}</span>
        <input type="text" value={form.password} onChange={e => setForm(f => ({ ...f, password: e.target.value }))}/>
      </label>

      <div className="sup-cust-projects">
        <div className="sup-cust-projects-head">
          Linked projects
          <span className="sup-cust-projects-hint">
            {linkedIds.length === 0
              ? "— pick at least one so they can raise tickets"
              : `${linkedIds.length} selected`}
          </span>
        </div>
        <div className="sup-cust-projects-list">
          {allProjects.length === 0
            ? <div className="sup-cust-projects-empty">No projects in this workspace yet.</div>
            : allProjects.map(p => (
                <label key={p.id} className={`sup-cust-project-chip ${linkedIds.includes(p.id) ? "is-on" : ""}`}>
                  <input type="checkbox" checked={linkedIds.includes(p.id)} onChange={() => toggleProject(p.id)}/>
                  <span className="sup-cust-project-dot" style={{ background: p.color || "var(--brand)" }}/>
                  {p.name}
                </label>
              ))}
        </div>
      </div>
    </SupEditorModal>
  );
}

// ─────────────────────────────────────────────────────────────
// Plans + ticket types editor
// ─────────────────────────────────────────────────────────────
function SettingsTab() {
  const [plans, setPlans] = React.useState([]);
  const [types, setTypes] = React.useState([]);
  async function load() {
    setPlans(await api.support.listPlans());
    setTypes(await api.support.listTypes());
  }
  React.useEffect(() => { load(); }, []);

  async function patchPlan(p, body)  { await api.support.patchPlan(p.id, body); load(); }
  async function removePlan(p)       { if (!confirm(`Delete plan "${p.name}"?`)) return; await api.support.removePlan(p.id); load(); }
  async function addPlan()           { const name = prompt("Plan name"); if (!name) return; const credits = parseInt(prompt("Monthly credits", "100"), 10) || 0; await api.support.createPlan({ name, monthly_credits: credits }); load(); }
  async function patchType(t, body)  { await api.support.patchType(t.id, body); load(); }
  async function removeType(t)       { if (!confirm(`Delete type "${t.label}"?`)) return; await api.support.removeType(t.id); load(); }
  async function addType()           { const label = prompt("Type label"); if (!label) return; const cost = parseInt(prompt("Credit cost", "5"), 10) || 1; await api.support.createType({ label, credit_cost: cost }); load(); }

  return (
    <div className="sup-settings">
      <div className="sup-group" style={{ "--sup-group-color": "#00c875" }}>
        <div className="sup-group-head">
          <span className="sup-group-title">Support plans</span>
          <span className="sup-group-count">{plans.length}</span>
          <button className="btn" style={{ marginLeft: "auto" }} onClick={addPlan}>+ Add plan</button>
        </div>
        <div className="sup-group-table-wrap">
          <table className="sup-t sup-t-settings">
            <thead>
              <tr>
                <th className="sup-th-name">Name</th>
                <th className="sup-th-center" style={{ width: 120 }}>Credits / month</th>
                <th className="sup-th-cell">Description</th>
                <th className="sup-th-cell sup-th-actions" style={{ width: 100 }}></th>
              </tr>
            </thead>
            <tbody>
              {plans.map(p => (
                <tr key={p.id} className="sup-tr">
                  <td className="sup-td-name">
                    <input className="sup-inline-input" value={p.name}
                           onBlur={e => patchPlan(p, { name: e.target.value })}
                           onChange={e => setPlans(ps => ps.map(x => x.id === p.id ? { ...x, name: e.target.value } : x))}/>
                  </td>
                  <td className="sup-td-center">
                    <input type="number" className="sup-inline-input sup-inline-num" value={p.monthly_credits} min={0}
                           onBlur={e => patchPlan(p, { monthly_credits: +e.target.value || 0 })}
                           onChange={e => setPlans(ps => ps.map(x => x.id === p.id ? { ...x, monthly_credits: e.target.value } : x))}/>
                  </td>
                  <td className="sup-td-cell">
                    <input className="sup-inline-input" value={p.description || ""}
                           placeholder="Description"
                           onBlur={e => patchPlan(p, { description: e.target.value })}
                           onChange={e => setPlans(ps => ps.map(x => x.id === p.id ? { ...x, description: e.target.value } : x))}/>
                  </td>
                  <td className="sup-td-cell" style={{ textAlign: "right" }}>
                    <button className="btn sup-cust-del" onClick={() => removePlan(p)}>Delete</button>
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      </div>

      <div className="sup-group" style={{ "--sup-group-color": "#fdab3d" }}>
        <div className="sup-group-head">
          <span className="sup-group-title">Ticket types &amp; credit cost</span>
          <span className="sup-group-count">{types.length}</span>
          <button className="btn" style={{ marginLeft: "auto" }} onClick={addType}>+ Add type</button>
        </div>
        <div className="sup-group-table-wrap">
          <table className="sup-t sup-t-settings">
            <thead>
              <tr>
                <th className="sup-th-name">Label</th>
                <th className="sup-th-center" style={{ width: 120 }}>Credit cost</th>
                <th className="sup-th-cell">Description</th>
                <th className="sup-th-center" style={{ width: 80 }}>Active</th>
                <th className="sup-th-cell sup-th-actions" style={{ width: 100 }}></th>
              </tr>
            </thead>
            <tbody>
              {types.map(t => (
                <tr key={t.id} className="sup-tr">
                  <td className="sup-td-name">
                    <input className="sup-inline-input" value={t.label}
                           onBlur={e => patchType(t, { label: e.target.value })}
                           onChange={e => setTypes(ts => ts.map(x => x.id === t.id ? { ...x, label: e.target.value } : x))}/>
                  </td>
                  <td className="sup-td-center">
                    <input type="number" className="sup-inline-input sup-inline-num" value={t.credit_cost} min={0}
                           onBlur={e => patchType(t, { credit_cost: +e.target.value || 0 })}
                           onChange={e => setTypes(ts => ts.map(x => x.id === t.id ? { ...x, credit_cost: e.target.value } : x))}/>
                  </td>
                  <td className="sup-td-cell">
                    <input className="sup-inline-input" value={t.description || ""}
                           placeholder="Description"
                           onBlur={e => patchType(t, { description: e.target.value })}
                           onChange={e => setTypes(ts => ts.map(x => x.id === t.id ? { ...x, description: e.target.value } : x))}/>
                  </td>
                  <td className="sup-td-center">
                    <input type="checkbox" checked={!!t.active}
                           onChange={e => patchType(t, { active: e.target.checked })}/>
                  </td>
                  <td className="sup-td-cell" style={{ textAlign: "right" }}>
                    <button className="btn sup-cust-del" onClick={() => removeType(t)}>Delete</button>
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      </div>
    </div>
  );
}

Object.assign(window, { SupportView });
