// Device Pairing — approve or revoke messaging-platform devices that want to talk
// to Hermes Agent. Wired to the dashboard config plane via /dash/api/pairing
// (HERMES.pairing / pairingApprove / pairingRevoke / pairingClearPending). Pending
// requests arrive with a short pairing code (or a user id); approving them lets that
// device through, revoking removes an already-approved one. No offline design data
// exists for pairing, so the empty/offline state simply shows "no requests".
const { useState, useEffect, useCallback, useMemo } = React;

// Platforms we always offer in the manual-approve picker, even when nothing is
// pending for them. Pending-request platforms are merged on top of this list.
const COMMON_PLATFORMS = ["telegram", "discord", "slack", "whatsapp", "signal"];

// Per-platform glyph. Only `discord` and `chat` exist in the icon set, so everything
// else falls back to the generic chat bubble.
function platformIcon(platform) {
  return (platform || "").toLowerCase() === "discord" ? "discord" : "chat";
}

// Relative time for the *_at ISO timestamps the backend returns.
function fmtAgo(iso) {
  if (!iso) return "";
  const t = Date.parse(iso);
  if (isNaN(t)) return "";
  const s = Math.max(0, (Date.now() - t) / 1000);
  if (s < 60) return "just now";
  if (s < 3600) return Math.floor(s / 60) + "m ago";
  if (s < 86400) return Math.floor(s / 3600) + "h ago";
  if (s < 2592000) return Math.floor(s / 86400) + "d ago";
  return new Date(t).toLocaleDateString();
}

function PagePairing({ toast }) {
  const [pending, setPending] = useState([]);   // [{platform, code?, user_id?, requested_at?}]
  const [approved, setApproved] = useState([]);  // [{platform, user_id, label?, approved_at?}]
  const [live, setLive] = useState(null);        // null=loading, true=backend, false=offline
  const [busy, setBusy] = useState(null);        // key of the row currently mutating
  const [mPlatform, setMPlatform] = useState("telegram"); // manual-approve form
  const [mCode, setMCode] = useState("");

  const load = useCallback(async () => {
    try {
      const r = await HERMES.pairing();
      setPending(Array.isArray(r && r.pending) ? r.pending : []);
      setApproved(Array.isArray(r && r.approved) ? r.approved : []);
      setLive(true);
    } catch {
      // No pairing design data — just present empty cards in preview/offline mode.
      setPending([]); setApproved([]);
      setLive(false);
    }
  }, []);

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

  // Approve a pending request (or a manual code). The backend identifies a request
  // by its code; if a row only carries a user_id we pass that through as the code.
  const approve = useCallback(async (platform, code, key) => {
    if (!platform || !code) { toast("Platform and code are required"); return; }
    setBusy(key);
    try {
      await HERMES.pairingApprove(platform, code);
      toast(`Approved ${platform} · ${code}`);
      await load();
    } catch (e) { toast(e.message || "Approve failed"); }
    setBusy(null);
  }, [load, toast]);

  const revoke = useCallback(async (platform, user_id, key) => {
    if (!window.confirm(`Revoke ${platform} device ${user_id}? It will need to pair again.`)) return;
    setBusy(key);
    try {
      await HERMES.pairingRevoke(platform, user_id);
      toast(`Revoked ${platform} · ${user_id}`);
      await load();
    } catch (e) { toast(e.message || "Revoke failed"); }
    setBusy(null);
  }, [load, toast]);

  const clearPending = useCallback(async () => {
    if (!pending.length) return;
    if (!window.confirm(`Clear all ${pending.length} pending request${pending.length === 1 ? "" : "s"}?`)) return;
    setBusy("__clear__");
    try {
      await HERMES.pairingClearPending();
      toast("Pending requests cleared");
      await load();
    } catch (e) { toast(e.message || "Clear failed"); }
    setBusy(null);
  }, [pending.length, load, toast]);

  const manualApprove = useCallback(async () => {
    await approve(mPlatform, mCode.trim(), "__manual__");
    setMCode("");
  }, [approve, mPlatform, mCode]);

  // Manual-approve platform options = common platforms ∪ platforms seen in pending.
  const platformOptions = useMemo(() => {
    const set = new Set(COMMON_PLATFORMS);
    for (const p of pending) if (p && p.platform) set.add(String(p.platform).toLowerCase());
    return Array.from(set);
  }, [pending]);

  return (
    <div className="page">
      <PageHead eyebrow="Workspace" title="Device Pairing" sub="Approve or revoke messaging devices that want to talk to Hermes Agent.">
        {live === true && <span className="badge ok"><span className="d" />live</span>}
        {live === false && <span className="badge warn"><span className="d" />preview</span>}
        {live === null && <span className="badge"><span className="d" />loading…</span>}
        <button className="btn btn-ghost" onClick={load}><Icon name="refresh" size={16} />Refresh</button>
      </PageHead>

      {/* ---- Pending requests ---- */}
      <div className="card" style={{ marginBottom: "var(--gap)" }}>
        <div className="card-head">
          <div>
            <h2>Pending requests</h2>
            <p>Devices waiting for approval. Approve a request to let that device through.</p>
          </div>
          <div className="flex" style={{ gap: 8, alignItems: "center" }}>
            <span className="faint mono" style={{ fontSize: 12 }}>{pending.length} pending</span>
            <button className="btn btn-ghost btn-sm" disabled={!pending.length || busy === "__clear__"} onClick={clearPending}>
              <Icon name="trash" size={13} />Clear pending
            </button>
          </div>
        </div>
        {!pending.length ? (
          <div className="empty">No pending pairing requests.</div>
        ) : (
          <div className="rows">
            {pending.map((req, i) => {
              const platform = req.platform || "unknown";
              const code = req.code || req.user_id || "";
              const key = "p" + i + platform + code;
              const ago = fmtAgo(req.requested_at);
              return (
                <div className="row" key={key} style={{ cursor: "default" }}>
                  <span className="glyph"><Icon name={platformIcon(platform)} size={15} /></span>
                  <div className="row-main">
                    <div className="flex" style={{ gap: 8, alignItems: "center", flexWrap: "wrap" }}>
                      <span className="tag" style={{ textTransform: "capitalize" }}>{platform}</span>
                      {req.code
                        ? <b className="mono" style={{ fontSize: 18, letterSpacing: ".06em" }}>{req.code}</b>
                        : <b className="mono" style={{ fontSize: 14 }}>{req.user_id || "—"}</b>}
                    </div>
                    <div className="row-sub mono">
                      {req.code && req.user_id ? <span>{req.user_id}</span> : null}
                      {ago ? <span>{(req.code && req.user_id ? " · " : "") + "requested " + ago}</span> : null}
                      {!req.code && !req.user_id && !ago ? <span>pairing request</span> : null}
                    </div>
                  </div>
                  <button className="btn btn-primary btn-sm" disabled={busy === key || !code}
                    onClick={() => approve(platform, code, key)}>
                    <Icon name="check" size={14} />{busy === key ? "Approving…" : "Approve"}
                  </button>
                </div>
              );
            })}
          </div>
        )}
      </div>

      {/* ---- Approved devices ---- */}
      <div className="card" style={{ marginBottom: "var(--gap)" }}>
        <div className="card-head">
          <div>
            <h2>Approved devices</h2>
            <p>Devices currently allowed to talk to the agent. Revoke to remove access.</p>
          </div>
          <span className="faint mono" style={{ fontSize: 12 }}>{approved.length} approved</span>
        </div>
        {!approved.length ? (
          <div className="empty">No approved devices yet.</div>
        ) : (
          <div className="rows">
            {approved.map((dev, i) => {
              const platform = dev.platform || "unknown";
              const userId = dev.user_id || "";
              const key = "a" + i + platform + userId;
              const ago = fmtAgo(dev.approved_at);
              return (
                <div className="row" key={key} style={{ cursor: "default" }}>
                  <span className="glyph" style={{ background: "var(--success-soft)", color: "var(--success)" }}><Icon name="lock" size={15} /></span>
                  <div className="row-main">
                    <div className="flex" style={{ gap: 8, alignItems: "center", flexWrap: "wrap" }}>
                      <span className="tag" style={{ textTransform: "capitalize" }}>{platform}</span>
                      <b className="mono" style={{ fontSize: 13.5 }}>{dev.label || userId || "—"}</b>
                    </div>
                    <div className="row-sub mono">
                      {dev.label && userId ? <span>{userId}</span> : null}
                      {ago ? <span>{(dev.label && userId ? " · " : "") + "approved " + ago}</span> : null}
                      {!userId && !dev.label && !ago ? <span>approved device</span> : null}
                    </div>
                  </div>
                  <button className="btn btn-danger btn-sm" disabled={busy === key || !userId}
                    onClick={() => revoke(platform, userId, key)}>
                    <Icon name="x" size={14} />{busy === key ? "Revoking…" : "Revoke"}
                  </button>
                </div>
              );
            })}
          </div>
        )}
      </div>

      {/* ---- Manual approve ---- */}
      <div className="card">
        <div className="card-head">
          <div>
            <h2>Manual approve</h2>
            <p>Have a pairing code in hand? Pick the platform, paste the code, and approve it directly.</p>
          </div>
        </div>
        <div className="grid cols-3" style={{ alignItems: "end" }}>
          <div className="field">
            <label>Platform</label>
            <select className="select" value={mPlatform} onChange={(e) => setMPlatform(e.target.value)}>
              {platformOptions.map((p) => (
                <option key={p} value={p}>{p.charAt(0).toUpperCase() + p.slice(1)}</option>
              ))}
            </select>
          </div>
          <div className="field">
            <label>Pairing code</label>
            <input className="input mono" value={mCode} placeholder="e.g. 4821-AB"
              onChange={(e) => setMCode(e.target.value)}
              onKeyDown={(e) => { if (e.key === "Enter" && mCode.trim()) manualApprove(); }} />
          </div>
          <div className="field">
            <button className="btn btn-primary" disabled={!mCode.trim() || busy === "__manual__"} onClick={manualApprove}>
              <Icon name="check" size={15} />{busy === "__manual__" ? "Approving…" : "Approve"}
            </button>
          </div>
        </div>
      </div>
    </div>
  );
}
window.PagePairing = PagePairing;
