// Solo staff admin area — Router SMS: a read-only audit trail of every
// SMS this platform has sent (or attempted) to a Teltonika router's own
// SIM card (MSISDN) — see routes/admin-router-sms.ts for the backend
// and migrations/0046_router_sms.sql for the schema/instruction trail.
// Mirrors admin-email-log-page.jsx's layout exactly (same summary-stat
// row, table, status coloring) since this is the same kind of
// third-party-delivery audit trail, just for SMS instead of email.
//
// Sending itself happens per-unit, from the router's own device detail
// page inside Unit Management (unit-management-page.jsx's Teltonika
// `controls` branch) — this page is visibility-only, matching Email
// Log's own "any signed-in admin can view" gate (routes/admin-router-
// sms.ts's GET routes use requireAdmin, not requireSuperAdmin; only the
// send endpoint itself is super_admin-gated).
//
// Reached via the sidebar nav in AdminShell (see admin-shell.jsx). Reuses
// MiniField/SectionLabel/EmptyNote/adminInputStyle/adminSelectStyle from
// admin-assets-page.jsx (loaded earlier — see index.html), same pattern
// as admin-email-log-page.jsx.

const ROUTER_SMS_STATUS_LABELS = { pending: "Pending", sent: "Sent", failed: "Failed" };
const ROUTER_SMS_STATUS_COLORS = {
  pending: "rgba(140,140,140,0.95)",
  sent: "rgba(20,140,60,0.95)",
  failed: "rgba(190,40,30,0.95)",
};

function AdminRouterSmsPage({ onNavigate }) {
  const [state, setState] = useState({ status: "loading", admin: null, log: [], inbound: [] });
  const [statusFilter, setStatusFilter] = useState("");
  const [q, setQ] = useState("");

  // Free-form compose (customer instruction, Sept 2026: "we need to be
  // able to type the MSISDN and type in the text to send") -- separate
  // from the per-unit send control on unit-management-page.jsx; this one
  // needs no unit context at all. Backend: POST /api/admin/router-sms/send.
  const [composeTo, setComposeTo] = useState("");
  const [composeMessage, setComposeMessage] = useState("");
  const [composeBusy, setComposeBusy] = useState(false);
  const [composeResult, setComposeResult] = useState(null); // { ok, error } | null

  const load = () => {
    Promise.all([
      fetch("/api/admin/me", { credentials: "same-origin" }).then((r) => (r.ok ? r.json() : Promise.reject())),
      fetch("/api/admin/router-sms/log", { credentials: "same-origin" }).then((r) => (r.ok ? r.json() : Promise.reject())),
      // Replies FROM routers, captured via Twilio's inbound-SMS webhook
      // (routes/router-sms-webhook.ts) -- a separate direction/table
      // from the outbound `log` above. See migrations/0047.
      fetch("/api/admin/router-sms/inbound", { credentials: "same-origin" }).then((r) => (r.ok ? r.json() : Promise.reject())),
    ])
      .then(([me, log, inbound]) => {
        setState({ status: "ready", admin: me.admin, log: log.log || [], inbound: inbound.inbound || [] });
      })
      .catch(() => onNavigate("admin-login"));
  };

  useEffect(load, []); // eslint-disable-line react-hooks/exhaustive-deps

  const handleCompose = async (e) => {
    e.preventDefault();
    const to = composeTo.trim();
    const text = composeMessage.trim();
    if (!to || !text || composeBusy) return;
    setComposeBusy(true);
    setComposeResult(null);
    try {
      const res = await fetch("/api/admin/router-sms/send", {
        method: "POST", credentials: "same-origin",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ to, message: text }),
      });
      const data = await res.json().catch(() => ({}));
      if (res.ok) {
        setComposeResult({ ok: true });
        setComposeMessage("");
        load();
      } else {
        setComposeResult({ ok: false, error: data.error || "Failed to send SMS." });
      }
    } catch {
      setComposeResult({ ok: false, error: "Couldn't reach the server. Check your connection and try again." });
    }
    setComposeBusy(false);
  };

  if (state.status === "loading") {
    return <section style={{ background: "#fff", minHeight: "calc(100vh - 88px)" }} />;
  }

  const filtered = state.log.filter((row) => {
    if (statusFilter && row.status !== statusFilter) return false;
    if (q.trim()) {
      const needle = q.trim().toLowerCase();
      const haystack = `${row.serial_number || ""} ${row.company_name || ""} ${row.to_msisdn || ""} ${row.message || ""}`.toLowerCase();
      if (!haystack.includes(needle)) return false;
    }
    return true;
  });

  // Replies from routers -- only the free-text search applies here
  // (there's no "status" concept for an inbound message), same q as
  // the outbound table above for a consistent single search box.
  const filteredInbound = state.inbound.filter((row) => {
    if (q.trim()) {
      const needle = q.trim().toLowerCase();
      const haystack = `${row.serial_number || ""} ${row.company_name || ""} ${row.from_msisdn || ""} ${row.body || ""}`.toLowerCase();
      if (!haystack.includes(needle)) return false;
    }
    return true;
  });

  const summary = state.log.reduce(
    (acc, row) => {
      acc.total += 1;
      if (row.status === "sent") acc.sent += 1;
      if (row.status === "failed") acc.failed += 1;
      return acc;
    },
    { total: 0, sent: 0, failed: 0 }
  );

  return (
    <AdminShell admin={state.admin} page="admin-router-sms" onNavigate={onNavigate}
      subtitle="Staff only" title="Router SMS.">
      <div style={{ display: "flex", gap: 20, flexWrap: "wrap", marginBottom: 24 }}>
        <RouterSmsSummaryStat label="Total sent" value={summary.total} />
        <RouterSmsSummaryStat label="Delivered" value={summary.sent} color="rgba(20,140,60,0.95)" />
        <RouterSmsSummaryStat label="Failed" value={summary.failed} color="rgba(190,40,30,0.95)" />
      </div>

      <div style={{
        fontFamily: "var(--font-body)", fontSize: 12.5, color: "#8A8474", marginBottom: 20, maxWidth: 640,
      }}>
        Every SMS sent (or attempted) to a router's own SIM card, across every unit. To send to a specific unit's
        stored SIM number, open it in Unit Management → Devices → the Teltonika Router entry — or send to any number
        directly below.
      </div>

      {/* Free-form send: type any MSISDN + any message, no unit context
          needed. super_admin only, matching the backend gate on
          POST /router-sms/send (same rule as the per-unit send control). */}
      {state.admin && state.admin.role === "super_admin" && (
        <div style={{ background: "#FAF7EF", border: "1px solid #E2DCCB", padding: 16, marginBottom: 28, maxWidth: 640 }}>
          <div style={{ fontFamily: "var(--font-body)", fontSize: 12.5, color: "#1A1712", fontWeight: 600, marginBottom: 10 }}>
            Send SMS to any number
          </div>
          <form onSubmit={handleCompose} style={{ display: "flex", gap: 8, flexWrap: "wrap", marginBottom: 10 }}>
            <input
              type="text" value={composeTo} onChange={(e) => setComposeTo(e.target.value)}
              placeholder="MSISDN, e.g. +467191014067875" disabled={composeBusy}
              data-testid="router-sms-compose-to"
              style={{ ...adminInputStyle, flex: "0 0 240px" }}
            />
            <input
              type="text" value={composeMessage} onChange={(e) => setComposeMessage(e.target.value)}
              placeholder="Message text…" disabled={composeBusy}
              data-testid="router-sms-compose-message"
              style={{ ...adminInputStyle, flex: 1, minWidth: 200 }}
            />
            <button
              type="submit" disabled={composeBusy || !composeTo.trim() || !composeMessage.trim()}
              data-testid="router-sms-compose-send"
              style={{
                background: "#1A1712", color: "#fff", border: "none", padding: "8px 16px",
                cursor: (composeBusy || !composeTo.trim() || !composeMessage.trim()) ? "not-allowed" : "pointer",
                opacity: (composeBusy || !composeTo.trim() || !composeMessage.trim()) ? 0.5 : 1,
                fontFamily: "var(--font-body)", fontSize: 11.5, fontWeight: 600,
                letterSpacing: "0.06em", textTransform: "uppercase", whiteSpace: "nowrap",
              }}
            >{composeBusy ? "Sending…" : "Send"}</button>
          </form>
          {composeResult && (
            composeResult.ok ? (
              <div style={{ fontFamily: "var(--font-body)", fontSize: 12, color: "#2C8C4C" }}>Sent.</div>
            ) : (
              <div style={{ fontFamily: "var(--font-body)", fontSize: 12, color: "#B4382C" }}>{composeResult.error}</div>
            )
          )}
        </div>
      )}

      <div style={{ display: "flex", gap: 12, flexWrap: "wrap", marginBottom: 24 }}>
        <MiniField label="Serial, company, number or message">
          <input
            value={q} onChange={(e) => setQ(e.target.value)}
            placeholder="Search…" style={adminInputStyle}
          />
        </MiniField>
        <MiniField label="Status (sent messages only)">
          <select value={statusFilter} onChange={(e) => setStatusFilter(e.target.value)} style={adminSelectStyle}>
            <option value="">All statuses</option>
            {Object.keys(ROUTER_SMS_STATUS_LABELS).map((s) => <option key={s} value={s}>{ROUTER_SMS_STATUS_LABELS[s]}</option>)}
          </select>
        </MiniField>
      </div>

      <SectionLabel>Sent to routers ({filtered.length}{state.log.length === 300 ? "+" : ""})</SectionLabel>
      {filtered.length === 0 ? (
        <EmptyNote>No SMS messages match this filter.</EmptyNote>
      ) : (
        <div style={{ overflowX: "auto", marginBottom: 32 }}>
          <table style={{ width: "100%", borderCollapse: "collapse", fontFamily: "var(--font-body)", fontSize: 13 }}>
            <thead>
              <tr style={{ textAlign: "left", borderBottom: "1px solid rgba(0,0,0,0.14)" }}>
                <RouterSmsTh>When</RouterSmsTh>
                <RouterSmsTh>Unit</RouterSmsTh>
                <RouterSmsTh>Company</RouterSmsTh>
                <RouterSmsTh>To (MSISDN)</RouterSmsTh>
                <RouterSmsTh>Message</RouterSmsTh>
                <RouterSmsTh>Status</RouterSmsTh>
              </tr>
            </thead>
            <tbody>
              {filtered.map((row) => <RouterSmsRow key={row.id} row={row} />)}
            </tbody>
          </table>
        </div>
      )}

      {/* Replies FROM routers, captured via Twilio's inbound-SMS webhook
          (routes/router-sms-webhook.ts) -- a separate direction/table
          from "Sent to routers" above. See migrations/0047. */}
      <SectionLabel>Replies from routers ({filteredInbound.length}{state.inbound.length === 300 ? "+" : ""})</SectionLabel>
      <div style={{
        fontFamily: "var(--font-body)", fontSize: 12.5, color: "#8A8474", marginBottom: 20, maxWidth: 640,
      }}>
        Every inbound SMS received from a router's own SIM card (e.g. a reply to an "rms_status" query). A blank Unit
        means the sending number didn't match any known router SIM on file.
      </div>
      {filteredInbound.length === 0 ? (
        <EmptyNote>No replies from routers match this filter.</EmptyNote>
      ) : (
        <div style={{ overflowX: "auto" }}>
          <table style={{ width: "100%", borderCollapse: "collapse", fontFamily: "var(--font-body)", fontSize: 13 }}>
            <thead>
              <tr style={{ textAlign: "left", borderBottom: "1px solid rgba(0,0,0,0.14)" }}>
                <RouterSmsTh>When</RouterSmsTh>
                <RouterSmsTh>Unit</RouterSmsTh>
                <RouterSmsTh>Company</RouterSmsTh>
                <RouterSmsTh>From (MSISDN)</RouterSmsTh>
                <RouterSmsTh>Message</RouterSmsTh>
              </tr>
            </thead>
            <tbody>
              {filteredInbound.map((row) => <RouterSmsInboundRow key={row.id} row={row} />)}
            </tbody>
          </table>
        </div>
      )}
    </AdminShell>
  );
}

function RouterSmsSummaryStat({ label, value, color }) {
  return (
    <div style={{ minWidth: 120 }}>
      <div style={{ fontFamily: "var(--font-display)", fontWeight: 700, fontSize: 28, color: color || "#000" }}>{value}</div>
      <div style={{ fontFamily: "var(--font-body)", fontSize: 11, letterSpacing: "0.08em", textTransform: "uppercase", color: "rgba(0,0,0,0.55)" }}>
        {label}
      </div>
    </div>
  );
}

function RouterSmsTh({ children }) {
  return (
    <th style={{
      padding: "10px 14px", fontFamily: "var(--font-body)", fontSize: 11,
      letterSpacing: "0.08em", textTransform: "uppercase", color: "rgba(0,0,0,0.55)", fontWeight: 600,
    }}>
      {children}
    </th>
  );
}

function RouterSmsTd({ children, wrap }) {
  return (
    <td style={{
      padding: "10px 14px", borderBottom: "1px solid rgba(0,0,0,0.08)", verticalAlign: "top",
      ...(wrap ? { wordBreak: "break-all" } : {}),
    }}>
      {children}
    </td>
  );
}

function RouterSmsRow({ row }) {
  return (
    <tr data-testid={`router-sms-log-row-${row.id}`}>
      <RouterSmsTd>
        <span style={{ whiteSpace: "nowrap", color: "rgba(0,0,0,0.7)" }}>
          {new Date(row.created_at.replace(" ", "T") + "Z").toLocaleString()}
        </span>
      </RouterSmsTd>
      <RouterSmsTd>{row.serial_number || "\u2014"}</RouterSmsTd>
      <RouterSmsTd>{row.company_name || "\u2014"}</RouterSmsTd>
      <RouterSmsTd wrap>{row.to_msisdn}</RouterSmsTd>
      <RouterSmsTd wrap>{row.message}</RouterSmsTd>
      <RouterSmsTd>
        <span style={{
          color: ROUTER_SMS_STATUS_COLORS[row.status] || "rgba(0,0,0,0.55)",
          textTransform: "uppercase", letterSpacing: "0.08em", fontSize: 11, fontWeight: 600,
        }}>
          {ROUTER_SMS_STATUS_LABELS[row.status] || row.status}
        </span>
        {row.error && (
          <div style={{ fontSize: 11, color: "rgba(190,40,30,0.85)", marginTop: 4, maxWidth: 260 }}>
            {row.error}
          </div>
        )}
      </RouterSmsTd>
    </tr>
  );
}

function RouterSmsInboundRow({ row }) {
  return (
    <tr data-testid={`router-sms-inbound-row-${row.id}`}>
      <RouterSmsTd>
        <span style={{ whiteSpace: "nowrap", color: "rgba(0,0,0,0.7)" }}>
          {new Date(row.received_at.replace(" ", "T") + "Z").toLocaleString()}
        </span>
      </RouterSmsTd>
      <RouterSmsTd>{row.serial_number || "\u2014"}</RouterSmsTd>
      <RouterSmsTd>{row.company_name || "\u2014"}</RouterSmsTd>
      <RouterSmsTd wrap>{row.from_msisdn}</RouterSmsTd>
      <RouterSmsTd wrap>{row.body}</RouterSmsTd>
    </tr>
  );
}

Object.assign(window, { AdminRouterSmsPage });
