// Nexa — Policies & Agents pages (live API)

const {
  fmtDate: fmtDate_b, ruleLabel, ruleDetail, normPolicyRule, normAgent,
  useFetch: useFetch_b, fmtMoney: fmtMoney_b, symbolFor: symbolFor_b,
} = window.TC_HELPERS;
const {
  AgentBadge: AgentBadge_b, Toggle: Toggle_b,
  PlusIcon: PlusIcon_b, ChevronIcon: ChevronIcon_b, XIcon: XIcon_b,
  CheckIcon: CheckIcon_b, Spinner: Spinner_b, RefreshIcon: RefreshIcon_b,
  LoadingBlock: LoadingBlock_b, ErrorBlock: ErrorBlock_b,
} = window.TC_UI;

// ── Constants ───────────────────────────────────────────────
const OPS = ["on_ramp", "off_ramp", "issue_card", "card_spend"];
const COMMON_CURRENCIES = ["GBP", "EUR", "USD", "CAD", "CHF", "AUD", "SGD"];

const RULE_TYPE_DEFS = [
  { value: "transaction_limit",      label: "Per-Transaction Limit",   shape: "amount" },
  { value: "daily_limit",            label: "Daily Aggregate Limit",   shape: "amount" },
  { value: "weekly_limit",           label: "Weekly Aggregate Limit",  shape: "amount" },
  { value: "monthly_limit",          label: "Monthly Aggregate Limit", shape: "amount" },
  { value: "approval_threshold",     label: "Approval Threshold",      shape: "amount", alwaysSoft: true },
  { value: "min_balance",            label: "Minimum Balance Floor",   shape: "amount" },
  { value: "counterparty_whitelist", label: "Counterparty Whitelist",  shape: "namelist" },
  { value: "counterparty_blacklist", label: "Counterparty Blacklist",  shape: "namelist" },
  { value: "currency_whitelist",     label: "Currency Whitelist",      shape: "currency" },
  { value: "corridor_blacklist",     label: "Corridor Blacklist",      shape: "codelist" },
  { value: "time_window",            label: "Time Window",             shape: "time" },
  { value: "velocity_limit",         label: "Velocity Limit",          shape: "velocity" },
  { value: "registered_beneficiary", label: "Registered Beneficiary Required", shape: "toggle" },
];

// ── Rule form (create + edit) ────────────────────────────────
function RuleForm({ initial, onCancel, onSubmit, title = "New policy rule" }) {
  // Initialise from existing rule or empty
  const init = initial || {};
  const [type, setType]           = useState(init.type || RULE_TYPE_DEFS[0].value);
  const [mode, setMode]           = useState(init.mode || "block");
  const [amount, setAmount]       = useState(init.amount != null ? String(init.amount) : "");
  const [currency, setCurrency]   = useState(init.currency || "GBP");
  const [nameList, setNameList]   = useState((init.values || []).join("\n"));
  const [codeList, setCodeList]   = useState((init.values || []).join("\n"));
  const [curList, setCurList]     = useState(init.values || []);
  const [customCur, setCustomCur] = useState("");
  const [maxCount, setMaxCount]   = useState(init.maxCount != null ? String(init.maxCount) : "50");
  const [periodHours, setPH]      = useState(init.periodHours != null ? String(init.periodHours) : "24");
  const [startHour, setSH]        = useState(init.startHour != null ? String(init.startHour) : "7");
  const [endHour, setEH]          = useState(init.endHour != null ? String(init.endHour) : "19");
  const [togVal, setTogVal]       = useState(init.enabled !== false);
  const [submitting, setSub]      = useState(false);

  const meta = RULE_TYPE_DEFS.find(r => r.value === type);
  const isAlwaysSoft = meta && meta.alwaysSoft;

  function toggleCur(cur) {
    setCurList(prev => prev.includes(cur) ? prev.filter(c => c !== cur) : [...prev, cur]);
  }
  function addCustomCur() {
    const c = customCur.trim().toUpperCase();
    if (c && !curList.includes(c)) { setCurList(prev => [...prev, c]); setCustomCur(""); }
  }

  const submit = async (e) => {
    e.preventDefault();
    const rule = {
      policy_type: type,
      is_hard_block: isAlwaysSoft ? false : (mode === "block"),
      enabled: true,
    };
    if (meta.shape === "amount") {
      if (!amount) return;
      rule.amount = Number(amount);
      if (currency) rule.currency = currency;
    } else if (meta.shape === "namelist") {
      const values = nameList.split("\n").map(s => s.trim()).filter(Boolean);
      if (!values.length) return;
      rule.values = values;
    } else if (meta.shape === "codelist") {
      const values = codeList.split("\n").map(s => s.trim().toUpperCase()).filter(Boolean);
      if (!values.length) return;
      rule.values = values;
    } else if (meta.shape === "currency") {
      if (!curList.length) return;
      rule.values = curList;
    } else if (meta.shape === "time") {
      rule.start_hour = Number(startHour);
      rule.end_hour   = Number(endHour);
    } else if (meta.shape === "velocity") {
      rule.max_count    = Number(maxCount);
      rule.period_hours = Number(periodHours);
    } else if (meta.shape === "toggle") {
      rule.enabled = togVal;
    }
    setSub(true);
    try { await onSubmit(rule); } finally { setSub(false); }
  };

  const hours = Array.from({length: 24}, (_, i) => i);

  return (
    <form className="tc-rule-form" onSubmit={submit}>
      <div className="tc-rule-form-h">
        <h3>{title}</h3>
        <button type="button" className="tc-btn tc-btn-ghost tc-btn-sm" onClick={onCancel}><XIcon_b /></button>
      </div>

      <div className="tc-rule-form-row row-2">
        <div className="tc-field">
          <span className="tc-field-l">Rule type</span>
          <select className="tc-select" value={type} onChange={e => setType(e.target.value)} disabled={!!initial}>
            {RULE_TYPE_DEFS.map(r => <option key={r.value} value={r.value}>{r.label}</option>)}
          </select>
        </div>
        <div className="tc-field">
          <span className="tc-field-l">Enforcement mode</span>
          {isAlwaysSoft ? (
            <div style={{paddingTop: 10, fontSize: 12.5, color: "var(--warn)"}}>Always "require approval"</div>
          ) : (
            <div className="tc-mode-seg">
              <button type="button" className={`tc-mode-seg-opt ${mode === "block" ? "is-on" : ""}`} onClick={() => setMode("block")}>Hard block</button>
              <button type="button" className={`tc-mode-seg-opt ${mode === "approval" ? "is-on" : ""}`} onClick={() => setMode("approval")}>Require approval</button>
            </div>
          )}
        </div>
      </div>

      {meta.shape === "amount" && (
        <div className="tc-rule-form-row row-2">
          <div className="tc-field">
            <span className="tc-field-l">Amount</span>
            <input type="number" min="0" step="any" placeholder="50000" value={amount} onChange={e => setAmount(e.target.value)} required />
          </div>
          <div className="tc-field">
            <span className="tc-field-l">Currency (optional)</span>
            <select className="tc-select" value={currency} onChange={e => setCurrency(e.target.value)}>
              <option value="">Any</option>
              {COMMON_CURRENCIES.map(c => <option key={c}>{c}</option>)}
            </select>
          </div>
        </div>
      )}

      {meta.shape === "namelist" && (
        <div className="tc-field">
          <span className="tc-field-l">Names · one per line</span>
          <textarea
            rows="4"
            placeholder={"EMEA Logistics GmbH\nArden & Bell LLP"}
            value={nameList}
            onChange={e => setNameList(e.target.value)}
          />
        </div>
      )}

      {meta.shape === "codelist" && (
        <div className="tc-field">
          <span className="tc-field-l">ISO2 country codes · one per line</span>
          <textarea
            rows="4"
            placeholder={"RU\nIR\nKP"}
            value={codeList}
            onChange={e => setCodeList(e.target.value)}
          />
        </div>
      )}

      {meta.shape === "currency" && (
        <div className="tc-field">
          <span className="tc-field-l">Allowed currencies</span>
          <div style={{display:"flex",flexWrap:"wrap",gap:8,paddingTop:4}}>
            {COMMON_CURRENCIES.map(c => (
              <label key={c} style={{display:"inline-flex",alignItems:"center",gap:5,fontSize:13,cursor:"pointer"}}>
                <input type="checkbox" checked={curList.includes(c)} onChange={() => toggleCur(c)} />
                {c}
              </label>
            ))}
          </div>
          <div style={{display:"flex",gap:8,marginTop:8}}>
            <input
              type="text"
              placeholder="Custom (e.g. SGD)"
              value={customCur}
              onChange={e => setCustomCur(e.target.value.toUpperCase())}
              style={{flex:1}}
            />
            <button type="button" className="tc-btn tc-btn-ghost tc-btn-sm" onClick={addCustomCur}>Add</button>
          </div>
          {curList.length > 0 && (
            <div style={{display:"flex",flexWrap:"wrap",gap:6,marginTop:6}}>
              {curList.map(c => (
                <span key={c} style={{display:"inline-flex",alignItems:"center",gap:4,background:"var(--bg-2)",border:"1px solid var(--line-2)",borderRadius:4,padding:"2px 8px",fontSize:12,fontFamily:"var(--font-mono)"}}>
                  {c}
                  <button type="button" style={{border:0,background:"none",cursor:"pointer",padding:0,color:"var(--fg-3)"}} onClick={() => setCurList(prev => prev.filter(x => x !== c))}>×</button>
                </span>
              ))}
            </div>
          )}
        </div>
      )}

      {meta.shape === "time" && (
        <div className="tc-rule-form-row row-2">
          <div className="tc-field">
            <span className="tc-field-l">Start hour · UTC</span>
            <select className="tc-select" value={startHour} onChange={e => setSH(e.target.value)}>
              {hours.map(h => <option key={h} value={h}>{String(h).padStart(2,"0")}:00</option>)}
            </select>
          </div>
          <div className="tc-field">
            <span className="tc-field-l">End hour · UTC</span>
            <select className="tc-select" value={endHour} onChange={e => setEH(e.target.value)}>
              {hours.map(h => <option key={h} value={h}>{String(h).padStart(2,"0")}:00</option>)}
            </select>
          </div>
        </div>
      )}

      {meta.shape === "velocity" && (
        <div className="tc-rule-form-row row-2">
          <div className="tc-field">
            <span className="tc-field-l">Max transactions</span>
            <input type="number" min="1" value={maxCount} onChange={e => setMaxCount(e.target.value)} required />
          </div>
          <div className="tc-field">
            <span className="tc-field-l">Period · hours</span>
            <input type="number" min="1" value={periodHours} onChange={e => setPH(e.target.value)} required />
          </div>
        </div>
      )}

      {meta.shape === "toggle" && (
        <div style={{display:"flex",alignItems:"center",gap:10,padding:"8px 0"}}>
          <Toggle_b on={togVal} onChange={setTogVal} />
          <span style={{fontSize:13,color:"var(--fg-2)"}}>
            {togVal ? "All payments must go to a registered & approved beneficiary" : "Beneficiary check disabled"}
          </span>
        </div>
      )}

      <div className="tc-rule-form-actions">
        <button type="button" className="tc-btn tc-btn-ghost" onClick={onCancel}>Cancel</button>
        <button type="submit" className="tc-btn tc-btn-accent" disabled={submitting}>
          {submitting ? <Spinner_b size={12} /> : <CheckIcon_b />} {initial ? "Save changes" : "Add rule"}
        </button>
      </div>
    </form>
  );
}

// ── Policy dry-run ───────────────────────────────────────────
function DryRunPanel({ agentId }) {
  const [amount, setAmount]   = useState("");
  const [currency, setCur]    = useState("GBP");
  const [cp, setCp]           = useState("");
  const [op, setOp]           = useState("off_ramp");
  const [result, setResult]   = useState(null);
  const [loading, setLoading] = useState(false);
  const [error, setError]     = useState("");

  const run = async (e) => {
    e.preventDefault();
    if (!amount || !agentId) return;
    setLoading(true); setResult(null); setError("");
    try {
      const r = await TC_API.policyDryRun(agentId, {
        amount: Number(amount),
        currency,
        counterparty_name: cp,
        operation: op,
      });
      setResult(r);
    } catch (err) {
      setError(err.message || String(err));
    } finally {
      setLoading(false);
    }
  };

  const decisionColor = {
    approved:          "var(--good)",
    rejected:          "#963c2c",
    requires_approval: "var(--warn)",
  };

  return (
    <div className="tc-card">
      <div className="tc-card-pad">
        <div className="tc-block-h" style={{marginBottom:16}}>
          <h2>Test a payment</h2>
          <span className="tc-block-h-meta">dry-run · no side effects</span>
        </div>

        <form onSubmit={run} style={{display:"flex",flexWrap:"wrap",gap:12,alignItems:"flex-end"}}>
          <div className="tc-field" style={{flex:"1 1 120px"}}>
            <span className="tc-field-l">Amount</span>
            <input type="number" min="0" step="any" placeholder="10000" value={amount} onChange={e => setAmount(e.target.value)} required />
          </div>
          <div className="tc-field" style={{flex:"0 0 100px"}}>
            <span className="tc-field-l">Currency</span>
            <select className="tc-select" value={currency} onChange={e => setCur(e.target.value)}>
              {COMMON_CURRENCIES.map(c => <option key={c}>{c}</option>)}
            </select>
          </div>
          <div className="tc-field" style={{flex:"2 1 180px"}}>
            <span className="tc-field-l">Counterparty name</span>
            <input type="text" placeholder="EMEA Logistics GmbH" value={cp} onChange={e => setCp(e.target.value)} />
          </div>
          <div className="tc-field" style={{flex:"1 1 130px"}}>
            <span className="tc-field-l">Operation</span>
            <select className="tc-select" value={op} onChange={e => setOp(e.target.value)}>
              {OPS.map(o => <option key={o}>{o}</option>)}
            </select>
          </div>
          <button type="submit" className="tc-btn tc-btn-ghost" disabled={loading || !agentId} style={{height:36,flexShrink:0}}>
            {loading ? <Spinner_b size={12} /> : "Run test"}
          </button>
        </form>

        {error && <div className="tc-error" style={{marginTop:14}}><div className="tc-error-h">Test failed</div><div className="tc-error-b">{error}</div></div>}

        {result && (
          <div style={{marginTop:16,padding:"16px 18px",background:"var(--bg-2)",border:"1px solid var(--line-2)",borderRadius:"var(--r-md)"}}>
            <div style={{display:"flex",alignItems:"center",gap:10,marginBottom:result.reasons.length ? 10 : 0}}>
              <span style={{
                display:"inline-flex",alignItems:"center",gap:6,
                fontSize:13,fontWeight:500,color:decisionColor[result.decision]||"var(--fg)",
                fontFamily:"var(--font-mono)",letterSpacing:"0.04em",textTransform:"uppercase"
              }}>
                <span style={{width:8,height:8,borderRadius:"50%",background:decisionColor[result.decision]||"var(--fg-3)",display:"inline-block"}} />
                {result.decision.replace(/_/g," ")}
              </span>
              {result.triggered_rules.length > 0 && (
                <span style={{fontSize:11.5,color:"var(--fg-3)",fontFamily:"var(--font-mono)"}}>
                  {result.triggered_rules.length} rule{result.triggered_rules.length > 1 ? "s" : ""} triggered
                </span>
              )}
            </div>
            {result.reasons.map((r, i) => (
              <div key={i} style={{fontSize:12.5,color:"var(--fg-2)",marginTop:6,paddingLeft:16,borderLeft:"2px solid var(--line)"}}>
                {r}
              </div>
            ))}
          </div>
        )}
      </div>
    </div>
  );
}

// ────────────────────────────────────────────────────────────
// POLICIES PAGE
// ────────────────────────────────────────────────────────────
function PoliciesPage({ agents }) {
  const [selectedAgentId, setSelectedAgentId] = useState(agents[0]?.id || "");
  const [showForm, setShowForm]     = useState(false);
  const [editingRule, setEditingRule] = useState(null); // null | normPolicyRule object
  const [resetting, setResetting]   = useState(false);

  useEffect(() => {
    if (!selectedAgentId && agents[0]) setSelectedAgentId(agents[0].id);
  }, [agents, selectedAgentId]);

  const policyQ = useFetch_b(
    () => selectedAgentId ? TC_API.getAgentPolicy(selectedAgentId) : Promise.resolve(null),
    [selectedAgentId]
  );

  const agent = agents.find(a => a.id === selectedAgentId);
  const rules = useMemo(
    () => ((policyQ.data && policyQ.data.rules) || []).map(normPolicyRule),
    [policyQ.data]
  );

  const closeForm = () => { setShowForm(false); setEditingRule(null); };

  const onToggleRule = async (ruleId, enabled) => {
    try { await TC_API.togglePolicyRule(selectedAgentId, ruleId, enabled); policyQ.refetch(); }
    catch (e) { alert(`Update failed: ${e.message}`); }
  };
  const onDeleteRule = async (ruleId) => {
    if (!confirm("Delete this rule?")) return;
    try { await TC_API.deletePolicyRule(selectedAgentId, ruleId); policyQ.refetch(); }
    catch (e) { alert(`Delete failed: ${e.message}`); }
  };
  const onAddRule = async (rule) => {
    await TC_API.addPolicyRule(selectedAgentId, rule);
    closeForm();
    policyQ.refetch();
  };
  const onEditRule = async (updates) => {
    const { policy_type, is_hard_block, enabled, amount, currency, values, period_hours, max_count, start_hour, end_hour } = updates;
    const patch = { is_hard_block, enabled };
    if (amount   != null) patch.amount   = amount;
    if (currency != null) patch.currency = currency;
    if (values   != null) patch.values   = values;
    if (period_hours != null) patch.period_hours = period_hours;
    if (max_count    != null) patch.max_count    = max_count;
    if (start_hour   != null) patch.start_hour   = start_hour;
    if (end_hour     != null) patch.end_hour     = end_hour;
    await TC_API.updatePolicyRule(selectedAgentId, editingRule.id, patch);
    closeForm();
    policyQ.refetch();
  };
  const onResetToDefault = async () => {
    if (!confirm("Replace all rules with the default policy template? This cannot be undone.")) return;
    setResetting(true);
    try { await TC_API.resetPolicyToDefault(selectedAgentId); policyQ.refetch(); }
    catch (e) { alert(`Reset failed: ${e.message}`); }
    finally { setResetting(false); }
  };

  if (agents.length === 0) {
    return <div className="tc-page"><div className="tc-card tc-empty">No agents registered yet. Register an agent to configure policy.</div></div>;
  }

  return (
    <div className="tc-page">
      <div className="tc-policy-head">
        <div className="tc-policy-head-l">
          <div className="tc-agent-select">
            <span className="tc-field-l">Agent</span>
            <select className="tc-select" value={selectedAgentId}
              onChange={e => { setSelectedAgentId(e.target.value); closeForm(); }}>
              {agents.map(a => <option key={a.id} value={a.id}>{a.name}</option>)}
            </select>
            {agent && <AgentBadge_b status={agent.status} />}
          </div>
          {agent && agent.allowedOperations.length > 0 && (
            <div className="tc-policy-ops">allowed operations · {agent.allowedOperations.join(" · ")}</div>
          )}
        </div>
        <div style={{display:"flex",alignItems:"center",gap:8}}>
          <span className="tc-badge">
            <span className="tc-badge-dot" />
            {rules.filter(r => r.enabled).length}/{rules.length} active
          </span>
          <button
            className="tc-btn tc-btn-ghost tc-btn-sm"
            disabled={resetting || !selectedAgentId}
            onClick={onResetToDefault}
            title="Apply default policy template"
          >
            {resetting ? <Spinner_b size={10} /> : <RefreshIcon_b />} Default template
          </button>
        </div>
      </div>

      <section>
        <div className="tc-block-h">
          <h2>Policy rules</h2>
          <span className="tc-block-h-meta">evaluated on every instruction</span>
        </div>

        <div>
          {!showForm && !editingRule && (
            <button className="tc-btn tc-btn-ghost tc-rule-add-btn" onClick={() => setShowForm(true)}>
              <PlusIcon_b /> Add rule
            </button>
          )}
          {showForm && !editingRule && (
            <RuleForm onCancel={closeForm} onSubmit={onAddRule} />
          )}
          {editingRule && (
            <RuleForm
              initial={editingRule}
              title="Edit rule"
              onCancel={closeForm}
              onSubmit={onEditRule}
            />
          )}
        </div>

        {policyQ.loading && !rules.length
          ? <LoadingBlock_b label="Loading policy…" />
          : policyQ.error
          ? <ErrorBlock_b error={policyQ.error} onRetry={policyQ.refetch} label="Couldn't load policy" />
          : <div style={{marginTop: 10}}>
              {rules.map(r => (
                <div
                  key={r.id}
                  className={`tc-rule ${r.enabled ? "" : "is-disabled"}`}
                  style={{cursor:"pointer"}}
                  onClick={() => { if (!showForm) { setEditingRule(editingRule?.id === r.id ? null : r); } }}
                >
                  <Toggle_b on={r.enabled} onChange={(v) => { onToggleRule(r.id, v); }} />
                  <div className="tc-rule-body">
                    <span className="tc-rule-label">{ruleLabel(r)}</span>
                    <span className="tc-rule-detail">{ruleDetail(r)}</span>
                  </div>
                  <span className={`tc-mode ${r.mode === "block" ? "is-block" : "is-approval"}`}>
                    {r.mode === "block" ? "Block" : "Approval"}
                  </span>
                  <button
                    className="tc-btn tc-btn-ghost tc-btn-sm"
                    onClick={e => { e.stopPropagation(); onDeleteRule(r.id); }}
                  >
                    <XIcon_b /> Delete
                  </button>
                  <span style={{width: 8}} />
                </div>
              ))}
              {rules.length === 0 && (
                <div className="tc-empty">No rules configured. The agent operates without policy guardrails.</div>
              )}
            </div>
        }
      </section>

      {selectedAgentId && <DryRunPanel agentId={selectedAgentId} />}
    </div>
  );
}

// ────────────────────────────────────────────────────────────
// AGENT CREATION FORM
// ────────────────────────────────────────────────────────────
function CreateAgentForm({ accounts, onCancel, onCreated }) {
  const [name, setName]         = useState("");
  const [desc, setDesc]         = useState("");
  const [ops, setOps]           = useState(["on_ramp", "off_ramp"]);
  const [walletAll, setWallAll] = useState(true);
  const [walletIds, setWIds]    = useState([]);
  const [submitting, setSub]    = useState(false);
  const [error, setError]       = useState("");

  function toggleOp(op) { setOps(prev => prev.includes(op) ? prev.filter(x => x !== op) : [...prev, op]); }
  function toggleWallet(id) { setWIds(prev => prev.includes(id) ? prev.filter(x => x !== id) : [...prev, id]); }

  const submit = async (e) => {
    e.preventDefault();
    if (!name.trim()) { setError("Agent name is required."); return; }
    if (ops.length === 0) { setError("Select at least one allowed operation."); return; }
    setSub(true); setError("");
    try {
      const r = await TC_API.registerAgent({
        name: name.trim(),
        description: desc.trim(),
        allowed_operations: ops,
        allowed_wallet_ids: walletAll ? [] : walletIds,
      });
      onCreated(r);
    } catch (err) {
      setError(err.message || String(err));
      setSub(false);
    }
  };

  const OP_LABELS = { on_ramp: "On-ramp", off_ramp: "Off-ramp", issue_card: "Issue card", card_spend: "Card spend" };

  return (
    <form className="tc-rule-form" onSubmit={submit}>
      <div className="tc-rule-form-h">
        <h3>Create agent</h3>
        <button type="button" className="tc-btn tc-btn-ghost tc-btn-sm" onClick={onCancel}><XIcon_b /></button>
      </div>

      <div className="tc-field">
        <span className="tc-field-l">Agent name</span>
        <input
          type="text"
          placeholder="AP Automation, Treasury FX, Intercompany…"
          value={name}
          onChange={e => { setName(e.target.value); setError(""); }}
          required
          autoFocus
        />
      </div>

      <div className="tc-field">
        <span className="tc-field-l">Description</span>
        <textarea
          rows="2"
          placeholder="What will this agent do? (optional)"
          value={desc}
          onChange={e => setDesc(e.target.value)}
        />
      </div>

      <div className="tc-field">
        <span className="tc-field-l">Allowed operations</span>
        <div style={{display:"flex",flexWrap:"wrap",gap:10,paddingTop:4}}>
          {OPS.map(op => (
            <label key={op} style={{display:"inline-flex",alignItems:"center",gap:5,fontSize:13,cursor:"pointer"}}>
              <input type="checkbox" checked={ops.includes(op)} onChange={() => toggleOp(op)} />
              {OP_LABELS[op] || op}
            </label>
          ))}
        </div>
      </div>

      <div className="tc-field">
        <span className="tc-field-l">Wallet scope</span>
        <div style={{display:"flex",flexDirection:"column",gap:8,paddingTop:4}}>
          <label style={{display:"inline-flex",alignItems:"center",gap:6,fontSize:13,cursor:"pointer"}}>
            <input type="radio" checked={walletAll} onChange={() => setWallAll(true)} />
            All wallets
          </label>
          <label style={{display:"inline-flex",alignItems:"center",gap:6,fontSize:13,cursor:"pointer"}}>
            <input type="radio" checked={!walletAll} onChange={() => setWallAll(false)} />
            Specific wallets
          </label>
          {!walletAll && (
            <div style={{paddingLeft:22,display:"flex",flexDirection:"column",gap:6}}>
              {accounts.length === 0
                ? <span style={{fontSize:12,color:"var(--fg-3)"}}>No accounts found</span>
                : accounts.map(a => (
                    <label key={a.id} style={{display:"inline-flex",alignItems:"center",gap:6,fontSize:12.5,cursor:"pointer",fontFamily:"var(--font-mono)"}}>
                      <input type="checkbox" checked={walletIds.includes(a.id)} onChange={() => toggleWallet(a.id)} />
                      {a.currency} · {a.id}
                    </label>
                  ))
              }
            </div>
          )}
        </div>
      </div>

      {error && <p style={{margin:0,fontSize:12.5,color:"#963c2c"}}>{error}</p>}

      <div className="tc-rule-form-actions">
        <button type="button" className="tc-btn tc-btn-ghost" onClick={onCancel}>Cancel</button>
        <button type="submit" className="tc-btn tc-btn-accent" disabled={submitting}>
          {submitting ? <Spinner_b size={12} /> : <CheckIcon_b />} Create agent
        </button>
      </div>
    </form>
  );
}

// ── API key reveal modal ─────────────────────────────────────
function ApiKeyModal({ agent, onClose, title = "Agent created" }) {
  const [copied, setCopied] = useState(false);
  const copy = () => {
    navigator.clipboard.writeText(agent.api_key).then(() => { setCopied(true); setTimeout(() => setCopied(false), 2000); });
  };
  return (
    <div style={{
      position:"fixed",inset:0,zIndex:100,
      background:"rgba(0,0,0,0.45)",
      display:"flex",alignItems:"center",justifyContent:"center",padding:24,
    }}>
      <div style={{
        background:"var(--bg)",border:"1px solid var(--line-2)",borderRadius:"var(--r-md)",
        padding:"32px 36px",maxWidth:560,width:"100%",display:"flex",flexDirection:"column",gap:18,
      }}>
        <div style={{display:"flex",justifyContent:"space-between",alignItems:"flex-start"}}>
          <div>
            <div style={{fontSize:18,fontFamily:"var(--font-display)",fontWeight:500,letterSpacing:"-0.01em",color:"var(--fg)"}}>
              {title}
            </div>
            <div style={{fontSize:13,color:"var(--fg-3)",marginTop:4}}>{agent.name} · {agent.agent_id}</div>
          </div>
          <button className="tc-btn tc-btn-ghost tc-btn-sm" onClick={onClose}><XIcon_b /></button>
        </div>

        <div style={{background:"rgba(182,138,63,0.08)",border:"1px solid rgba(182,138,63,0.35)",borderRadius:"var(--r)",padding:"12px 14px"}}>
          <div style={{fontSize:11.5,fontWeight:500,color:"var(--warn)",fontFamily:"var(--font-mono)",letterSpacing:"0.06em",textTransform:"uppercase",marginBottom:4}}>
            Save this key now — it won't be shown again
          </div>
          <div style={{fontSize:12,color:"var(--fg-2)",lineHeight:1.5}}>
            This is the only time the full API key is returned. Copy it to a secure secrets manager.
          </div>
        </div>

        <div>
          <div style={{fontSize:10.5,fontFamily:"var(--font-mono)",letterSpacing:"0.08em",color:"var(--fg-4)",textTransform:"uppercase",marginBottom:6}}>API key</div>
          <div style={{
            fontFamily:"var(--font-mono)",fontSize:12.5,background:"var(--bg-2)",
            border:"1px solid var(--line-2)",borderRadius:"var(--r)",padding:"10px 12px",
            wordBreak:"break-all",color:"var(--accent)",letterSpacing:"0.02em",lineHeight:1.6,
          }}>
            {agent.api_key}
          </div>
          <button className="tc-btn tc-btn-ghost tc-btn-sm" style={{marginTop:8}} onClick={copy}>
            {copied ? <><CheckIcon_b /> Copied</> : "Copy key"}
          </button>
        </div>

        <div>
          <div style={{fontSize:10.5,fontFamily:"var(--font-mono)",letterSpacing:"0.08em",color:"var(--fg-4)",textTransform:"uppercase",marginBottom:6}}>Connect snippet</div>
          <pre style={{
            fontFamily:"var(--font-mono)",fontSize:11.5,background:"var(--bg-2)",
            border:"1px solid var(--line-2)",borderRadius:"var(--r)",padding:"10px 12px",
            margin:0,overflowX:"auto",color:"var(--fg-2)",lineHeight:1.65,whiteSpace:"pre",
          }}>{`fetch("${TC_API.BASE}/wallets/off-ramp", {
  method: "POST",
  headers: {
    "X-Agent-Key": "${agent.api_key}",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({ ... })
})`}</pre>
        </div>

        <div style={{display:"flex",gap:8,justifyContent:"flex-end",borderTop:"1px solid var(--line-2)",paddingTop:14}}>
          <button className="tc-btn tc-btn-primary" onClick={onClose}>Done</button>
        </div>
      </div>
    </div>
  );
}

// ────────────────────────────────────────────────────────────
// AGENTS PAGE
// ────────────────────────────────────────────────────────────
function AgentsPage({ agents, agentsQ }) {
  const [openId, setOpenId]             = useState(agents[0]?.id || null);
  const [busyId, setBusyId]             = useState(null);
  const [showCreate, setCreate]         = useState(false);
  const [newAgent, setNewAgent]         = useState(null);   // newly created/rotated agent with api_key
  const [newAgentTitle, setNewAgentTitle] = useState("Agent created");
  const [rotateConfirmId, setRotateConfirmId] = useState(null); // agent id pending rotation confirm

  // Load accounts for wallet scope picker
  const accountsQ = useFetch_b(() => TC_API.getAccounts(), []);
  const accounts  = useMemo(() => (accountsQ.data || []).map(a => ({
    id: a.account_id || a.id,
    currency: a.currency,
  })), [accountsQ.data]);

  useEffect(() => {
    if (!openId && agents[0]) setOpenId(agents[0].id);
  }, [agents, openId]);

  const doAction = async (id, action) => {
    setBusyId(id);
    try {
      if (action === "activate")   await TC_API.activateAgent(id);
      if (action === "suspend")    await TC_API.suspendAgent(id);
      if (action === "reactivate") await TC_API.activateAgent(id);
      if (action === "revoke")     await TC_API.revokeAgent(id);
      agentsQ && agentsQ.refetch && agentsQ.refetch();
    } catch (e) {
      alert(`${action} failed: ${e.message}`);
    } finally { setBusyId(null); }
  };

  const doRotate = async (id) => {
    const agent = agents.find(a => a.id === id);
    setBusyId(id);
    setRotateConfirmId(null);
    try {
      const result = await TC_API.rotateAgentKey(id);
      // Show the new key exactly like creation — result has {agent_id, api_key, rotated_at}
      setNewAgent({ api_key: result.api_key, agent_id: result.agent_id, name: agent?.name || result.agent_id });
      setNewAgentTitle("Key rotated");
      agentsQ && agentsQ.refetch && agentsQ.refetch();
    } catch (e) {
      alert(`Key rotation failed: ${e.message}`);
    } finally { setBusyId(null); }
  };

  const onCreated = (agent) => {
    setCreate(false);
    setNewAgentTitle("Agent created");
    setNewAgent(agent);
    agentsQ && agentsQ.refetch && agentsQ.refetch();
  };

  if (agentsQ && agentsQ.loading && !agents.length) {
    return <div className="tc-page"><LoadingBlock_b label="Loading agents…" /></div>;
  }
  if (agentsQ && agentsQ.error) {
    return <div className="tc-page"><ErrorBlock_b error={agentsQ.error} onRetry={agentsQ.refetch} /></div>;
  }

  return (
    <div className="tc-page">
      {newAgent && <ApiKeyModal agent={newAgent} title={newAgentTitle} onClose={() => setNewAgent(null)} />}

      {/* Rotate key confirmation modal */}
      {rotateConfirmId && (() => {
        const a = agents.find(x => x.id === rotateConfirmId);
        return (
          <div style={{position:"fixed",inset:0,zIndex:100,background:"rgba(0,0,0,0.45)",display:"flex",alignItems:"center",justifyContent:"center",padding:24}}>
            <div style={{background:"var(--bg)",border:"1px solid var(--line-2)",borderRadius:"var(--r-md)",padding:"28px 32px",maxWidth:460,width:"100%",display:"flex",flexDirection:"column",gap:16}}>
              <div style={{fontSize:17,fontFamily:"var(--font-display)",fontWeight:500,color:"var(--fg)"}}>Rotate API key?</div>
              <div style={{fontSize:13,color:"var(--fg-2)",lineHeight:1.6}}>
                <strong>{a?.name || rotateConfirmId}</strong> will stop working immediately with the old key.
                The new key will be shown once — save it to your secrets manager before closing.
              </div>
              <div style={{display:"flex",gap:8,justifyContent:"flex-end",paddingTop:4}}>
                <button className="tc-btn tc-btn-ghost" onClick={() => setRotateConfirmId(null)}>Cancel</button>
                <button className="tc-btn tc-btn-danger" disabled={busyId === rotateConfirmId} onClick={() => doRotate(rotateConfirmId)}>
                  {busyId === rotateConfirmId ? <Spinner_b size={12} /> : "Rotate key"}
                </button>
              </div>
            </div>
          </div>
        );
      })()}

      <section>
        <div className="tc-block-h">
          <h2>Registered agents</h2>
          <span className="tc-block-h-meta">{agents.length} registered · {agents.filter(a => a.status === "active").length} active</span>
        </div>

        {!showCreate && (
          <button className="tc-btn tc-btn-ghost tc-rule-add-btn" style={{marginBottom:14}} onClick={() => setCreate(true)}>
            <PlusIcon_b /> Create agent
          </button>
        )}
        {showCreate && (
          <CreateAgentForm
            accounts={accounts}
            onCancel={() => setCreate(false)}
            onCreated={onCreated}
          />
        )}

        {agents.length === 0 && !showCreate ? (
          <div className="tc-card tc-empty">No agents registered yet.</div>
        ) : (
          <div>
            {agents.map(a => {
              const isOpen = openId === a.id;
              const walletLabel = !a.allowedWalletIds || a.allowedWalletIds.length === 0
                ? "all wallets"
                : a.allowedWalletIds.join(" · ");
              const maskedKey = a.apiKeyMasked || (a.apiKey
                ? `${a.apiKey.slice(0, 3)}${"•".repeat(20)}${a.apiKey.slice(-4)}`
                : "—");
              return (
                <article key={a.id} className={`tc-agent-card ${isOpen ? "is-open" : ""} ${a.status === "suspended" ? "is-suspended" : ""}`}>
                  <button className="tc-agent-collapsed" onClick={() => setOpenId(isOpen ? null : a.id)}>
                    <span className={`tc-status-dot is-${a.status}`} />
                    <div className="tc-agent-name">
                      <span className="tc-agent-name-t">{a.name || a.id}</span>
                      <span className="tc-agent-name-h">{a.id}</span>
                    </div>
                    <div style={{flex: 1}} />
                    {a.lastUsedAt && (
                      <span style={{fontSize:11,color:"var(--fg-4)",fontFamily:"var(--font-mono)",marginRight:8}}>
                        last used {fmtDate_b(a.lastUsedAt)}
                      </span>
                    )}
                    <AgentBadge_b status={a.status} />
                    <span style={{width: 8}} />
                    <span className="tc-chevron"><ChevronIcon_b /></span>
                  </button>

                  {isOpen && (
                    <div className="tc-agent-expanded">
                      {a.description && (
                        <div className="tc-agent-detail" style={{gridColumn: "1 / -1"}}>
                          <span className="tc-agent-detail-k">Description</span>
                          <span className="tc-agent-detail-v is-prose">{a.description}</span>
                        </div>
                      )}

                      <div className="tc-agent-detail">
                        <span className="tc-agent-detail-k">API key</span>
                        <span className="tc-agent-detail-v" style={{fontFamily:"var(--font-mono)",fontSize:12,letterSpacing:"0.02em"}}>{maskedKey}</span>
                      </div>
                      <div className="tc-agent-detail">
                        <span className="tc-agent-detail-k">Created</span>
                        <span className="tc-agent-detail-v">{a.createdAt ? fmtDate_b(a.createdAt) : "—"}</span>
                      </div>
                      <div className="tc-agent-detail">
                        <span className="tc-agent-detail-k">Last used</span>
                        <span className="tc-agent-detail-v">{a.lastUsedAt ? fmtDate_b(a.lastUsedAt) : "Never"}</span>
                      </div>
                      <div className="tc-agent-detail">
                        <span className="tc-agent-detail-k">Allowed operations</span>
                        <span className="tc-agent-detail-v">{(a.allowedOperations||[]).length ? a.allowedOperations.join(" · ") : "—"}</span>
                      </div>
                      <div className="tc-agent-detail">
                        <span className="tc-agent-detail-k">Wallet scope</span>
                        <span className="tc-agent-detail-v">{walletLabel}</span>
                      </div>

                      {a.status === "suspended" && a.suspensionReason && (
                        <div className="tc-agent-suspension">
                          <strong>Suspension reason</strong>
                          {a.suspensionReason}
                        </div>
                      )}

                      <div className="tc-agent-actions">
                        {(a.status === "created") && (
                          <>
                            <button className="tc-btn tc-btn-ghost" disabled={busyId === a.id}
                              onClick={() => doAction(a.id, "activate")}
                              title="Move to test mode first">
                              Test mode
                            </button>
                            <button className="tc-btn tc-btn-accent" disabled={busyId === a.id}
                              onClick={() => doAction(a.id, "activate")}>
                              <CheckIcon_b /> Activate
                            </button>
                          </>
                        )}
                        {a.status === "test" && (
                          <button className="tc-btn tc-btn-accent" disabled={busyId === a.id}
                            onClick={() => doAction(a.id, "activate")}>
                            <CheckIcon_b /> Go live
                          </button>
                        )}
                        {a.status === "active" && (
                          <button className="tc-btn tc-btn-ghost" disabled={busyId === a.id}
                            onClick={() => doAction(a.id, "suspend")}>
                            Suspend
                          </button>
                        )}
                        {a.status === "suspended" && (
                          <button className="tc-btn tc-btn-accent" disabled={busyId === a.id}
                            onClick={() => doAction(a.id, "reactivate")}>
                            Reactivate
                          </button>
                        )}
                        {a.status !== "revoked" && (
                          <>
                            <button className="tc-btn tc-btn-ghost" disabled={busyId === a.id}
                              onClick={() => setRotateConfirmId(a.id)}
                              title="Invalidate current key and issue a new one">
                              <RefreshIcon_b /> Rotate key
                            </button>
                            <button className="tc-btn tc-btn-danger" disabled={busyId === a.id}
                              onClick={() => doAction(a.id, "revoke")}>
                              Revoke (permanent)
                            </button>
                          </>
                        )}
                      </div>
                    </div>
                  )}
                </article>
              );
            })}
          </div>
        )}
      </section>
    </div>
  );
}

window.TC_PAGES_B = { PoliciesPage, AgentsPage };
