/* ===============================================================
   AGENTICS.CREDIT — CAMPAIGN · MYAGENT MODULE
   Split out of campaign.jsx on 2026-07-03. Contains:
     - StrategyJournalPanel + JournalEntry (per-agent daily narrative)
     - MyAgent page (agent detail + personality + strategy tuning)
     - CampaignAPI panel + code snippets + starter key
   Load AFTER campaign.jsx in index.html so shared globals (apiPost,
   acGet, acSend, useToast, Card, AddAgentModal, StrategyCoachModal,
   RiskBanner, KyaBadge) are already defined.
   =============================================================== */

function StrategyJournalPanel({ agentId, agentName }) {
  const [entries, setEntries] = useState([]);
  const [loaded, setLoaded]   = useState(false);
  const [error, setError]     = useState(null);
  const [expandedId, setExpandedId] = useState(null);

  useEffect(() => {
    if (!agentId) return;
    let cancelled = false;
    async function fetchEntries() {
      try {
        const data = await acGet(`/agents/${agentId}/journal?limit=50`);
        if (cancelled) return;
        setEntries((data && data.entries) || []);
        setError(null);
      } catch (e) {
        if (cancelled) return;
        setError((e && e.message) || "load_failed");
      } finally {
        if (!cancelled) setLoaded(true);
      }
    }
    fetchEntries();
    // Refresh once every 5 min — journal updates are daily so no need
    // to poll aggressively.
    const id = setInterval(fetchEntries, 5 * 60 * 1000);
    return () => { cancelled = true; clearInterval(id); };
  }, [agentId]);

  return (
    <Card title={`STRATEGY_JOURNAL — ${agentName || ""}`}>
      {!loaded && (
        <div style={{ padding: 20, color: "var(--cg-muted)", fontFamily: "'DM Mono', monospace", fontSize: 12 }}>
          Loading journal…
        </div>
      )}
      {loaded && error && (
        <div style={{ padding: 20, color: "#e97", fontFamily: "'DM Mono', monospace", fontSize: 12 }}>
          Couldn't load journal — {error}
        </div>
      )}
      {loaded && !error && entries.length === 0 && (
        <div style={{ padding: 24, color: "var(--cg-muted)", fontStyle: "italic", textAlign: "center", fontSize: 13 }}>
          No journal entries yet. Your agent's first nightly review runs at UTC 00:15.
        </div>
      )}
      {loaded && entries.length > 0 && (
        <div style={{ display: "flex", flexDirection: "column", gap: 12, padding: 4 }}>
          {entries.map(e => (
            <JournalEntry
              key={e.id}
              entry={e}
              expanded={expandedId === e.id}
              onToggle={() => setExpandedId(id => id === e.id ? null : e.id)}
            />
          ))}
        </div>
      )}
    </Card>
  );
}

function JournalEntry({ entry, expanded, onToggle }) {
  const kind = entry.kind || "review";
  const created = entry.created_at ? new Date(entry.created_at) : null;
  const rationale = (entry.rationale || "").trim();
  const payload = entry.payload || {};

  // Kind-specific styling
  const kindStyle = {
    design:    { color: "var(--accent)",           bg: "rgba(29,158,117,0.10)",  border: "rgba(29,158,117,0.35)" },
    review:    { color: "var(--fg)",               bg: "var(--bg-2)",            border: "var(--border)"        },
    mutation:  { color: "var(--amber, #d29022)",   bg: "rgba(210,144,34,0.08)",  border: "rgba(210,144,34,0.35)" },
    user_note: { color: "#8dbfff",                 bg: "rgba(80,131,250,0.08)",  border: "rgba(80,131,250,0.35)" },
  }[kind] || { color: "var(--fg)", bg: "var(--bg-2)", border: "var(--border)" };

  const kindLabel = kind.toUpperCase().replace("_", " ");

  const assessment = payload.assessment;
  const assessmentStyle = {
    ahead:      { color: "var(--accent)",         bg: "rgba(29,158,117,0.14)"  },
    "on-track": { color: "var(--fg)",             bg: "var(--cg-tint-2)" },
    behind:     { color: "var(--amber, #d29022)", bg: "rgba(210,144,34,0.14)"  },
  }[assessment] || null;

  const short = rationale.length > 260 ? rationale.slice(0, 260).trim() + "…" : rationale;

  return (
    <div style={{
      border: "1px solid " + kindStyle.border,
      background: kindStyle.bg,
      borderRadius: 6,
      padding: "12px 14px",
      fontFamily: "'DM Mono', monospace",
    }}>
      <div style={{ display: "flex", alignItems: "center", gap: 10, marginBottom: 6, flexWrap: "wrap" }}>
        <span style={{
          fontSize: 10, letterSpacing: 1, padding: "2px 8px",
          color: kindStyle.color, background: "rgba(0,0,0,0.15)",
          border: "1px solid " + kindStyle.border, borderRadius: 3,
        }}>{kindLabel}</span>
        {assessment && assessmentStyle && (
          <span style={{
            fontSize: 10, letterSpacing: 1, padding: "2px 8px",
            color: assessmentStyle.color, background: assessmentStyle.bg,
            borderRadius: 3,
          }}>{assessment.toUpperCase()}</span>
        )}
        {payload.model && (
          <span style={{ fontSize: 10, color: "var(--cg-muted)", letterSpacing: 0.5 }}>
            {payload.model.replace("claude-", "")}
          </span>
        )}
        <span style={{ fontSize: 10, color: "var(--cg-muted)", marginLeft: "auto" }}>
          {created ? created.toLocaleString(undefined, { month: "short", day: "numeric", hour: "2-digit", minute: "2-digit" }) : ""}
        </span>
      </div>

      <div style={{
        fontSize: 13, color: "var(--fg)", lineHeight: 1.65,
        whiteSpace: "pre-wrap", fontFamily: "'DM Mono', monospace",
      }}>
        {expanded ? rationale : short}
      </div>

      {rationale.length > 260 && (
        <button
          onClick={onToggle}
          style={{
            marginTop: 6, background: "none", border: "none",
            color: "var(--accent)", fontFamily: "'DM Mono', monospace",
            fontSize: 11, cursor: "pointer", padding: 0, letterSpacing: 0.5,
          }}
        >
          {expanded ? "← COLLAPSE" : "READ MORE →"}
        </button>
      )}

      {/* Details block on expand — strategy delta + lesson updates */}
      {expanded && (
        <div style={{ marginTop: 10, paddingTop: 10, borderTop: "1px dashed " + kindStyle.border, fontSize: 11, lineHeight: 1.7 }}>
          {payload.delta && Object.keys(payload.delta).length > 0 && (
            <div style={{ marginBottom: 6 }}>
              <div style={{ color: "var(--cg-muted)", marginBottom: 4 }}>// STRATEGY_DELTA</div>
              {Object.entries(payload.delta).map(([k, v]) => (
                <div key={k} style={{ display: "flex", justifyContent: "space-between", color: "var(--fg)" }}>
                  <span style={{ color: "var(--cg-muted)" }}>{k}</span>
                  <span>{typeof v === "object" ? JSON.stringify(v) : String(v)}</span>
                </div>
              ))}
            </div>
          )}
          {payload.lessons_updated && (
            <div style={{ color: "var(--cg-muted)", fontStyle: "italic" }}>
              // playbook_lessons refreshed
            </div>
          )}
          {typeof payload.cost_usd === "number" && (
            <div style={{ color: "var(--cg-muted)", marginTop: 4, fontSize: 10 }}>
              // review cost: ${payload.cost_usd.toFixed(4)} · {payload.input_tokens || 0}→{payload.output_tokens || 0} tokens
            </div>
          )}
        </div>
      )}
    </div>
  );
}


function MyAgent({ user, onUpdate }) {
  // Full agent rows fetched directly from GET /agents so we have
  // personality / markets / max_leverage / target_tier / status per agent.
  // (user.agents only carries the lightweight card shape used by the
  //  dashboard's AgentsGridPanel.)
  const [agents, setAgents] = useState([]);
  const [selectedAgentId, setSelectedAgentId] = useState(null);
  const [loadedAgents, setLoadedAgents] = useState(false);

  // Per-agent form state. Resets whenever the user picks a different
  // agent so each agent's settings are edited in isolation.
  const [desc, setDesc] = useState("");
  const [target, setTarget] = useState("qualified");
  const [markets, setMarkets] = useState([]);
  const [maxLev, setMaxLev] = useState(2);

  // Strategy-tuning form state — direct edit of strategy_state. When the
  // user saves, the agent gets pinned (claude_executor stops auto-tuning).
  // Reset to AI un-pins so Claude resumes hourly drift.
  const [stratEdits, setStratEdits] = useState({});
  const [stratSaving, setStratSaving] = useState(false);

  const [saving, setSaving] = useState(false);
  const [showApi, setShowApi] = useState(false);
  const [keyVisible, setKeyVisible] = useState(false);
  const [coachOpen, setCoachOpen] = useState(false);
  const [pauseBusy, setPauseBusy] = useState(false);

  async function togglePause() {
    if (!selected || pauseBusy) return;
    const nextAction = selected.status === "active" ? "pause" : "resume";
    setPauseBusy(true);
    try {
      const res = await acSend(`/agents/${selected.id}/${nextAction}`, {});
      // Merge the returned agent back into local state so the button + badge
      // reflect the new status immediately without waiting on refresh.
      const updated = (res && res.agent) || null;
      if (updated) {
        setAgents(prev => prev.map(a => a.id === selected.id ? { ...a, ...updated } : a));
      }
      toast && toast.push({
        title: nextAction === "pause" ? "Agent paused" : "Agent resumed",
        meta:  (res && res.message) || "",
        duration: 4500,
      });
    } catch (e) {
      const msg = (e && (e.detail || e.message)) || "Try again";
      toast && toast.push({ title: `${nextAction === "pause" ? "Pause" : "Resume"} failed`, meta: msg.replace(/^\d+:\s*/, ""), duration: 4000 });
    } finally {
      setPauseBusy(false);
    }
  }
  const [addOpen, setAddOpen] = useState(false);
  const toast = useToast && useToast();

  // Fetch agents on mount + on tab-visibility regain (same pattern as
  // the dashboard's refreshAgents). Auto-selects the primary if no
  // selection yet, falling back to the first agent.
  useEffect(() => {
    let cancelled = false;
    async function refresh() {
      try {
        const data = await acGet("/agents");
        if (cancelled) return;
        const list = (data && (data.agents || data)) || [];
        setAgents(list);
        setLoadedAgents(true);
        setSelectedAgentId(prev => {
          if (prev && list.some(a => a.id === prev)) return prev;
          const primary = list.find(a => a.is_primary) || list[0];
          return primary ? primary.id : null;
        });
      } catch (_) { setLoadedAgents(true); }
    }
    refresh();
    function onVis() { if (!document.hidden) refresh(); }
    document.addEventListener("visibilitychange", onVis);
    return () => { cancelled = true; document.removeEventListener("visibilitychange", onVis); };
  }, []);

  const selected = agents.find(a => a.id === selectedAgentId) || null;

  // When the user picks a different agent, reset the form to that
  // agent's persisted values. Strip the "-PERP" suffix from markets
  // for display (chips render bare symbols); we re-append on save.
  useEffect(() => {
    if (!selected) return;
    setDesc(selected.personality || "");
    setTarget((selected.target_tier || "qualified").toLowerCase());
    setMarkets((selected.markets || []).map(m => m.replace(/-PERP$/, "")));
    setMaxLev(Math.max(2, Math.min(20, Number(selected.max_leverage || 2))));
    setStratEdits({});   // clear any in-flight tuning edits
  }, [selectedAgentId]);   // intentionally only on id change

  const dirty = selected && (
    desc !== (selected.personality || "") ||
    target !== (selected.target_tier || "qualified").toLowerCase() ||
    JSON.stringify(markets.slice().sort()) !==
      JSON.stringify((selected.markets || []).map(m => m.replace(/-PERP$/, "")).slice().sort()) ||
    Number(maxLev) !== Math.max(2, Math.min(20, Number(selected.max_leverage || 2)))
  );

  async function saveChanges() {
    if (!selected || saving) return;
    setSaving(true);
    try {
      const updated = await acSend(`/agents/${selected.id}`, {
        personality:  desc,
        markets:      (markets || []).map(m => m.endsWith("-PERP") ? m : `${m}-PERP`),
        max_leverage: Number(maxLev),
      }, "PUT");
      // Merge the returned agent back into our local list so the picker
      // labels + form baseline reflect the new state without a refetch.
      const newAgent = (updated && updated.agent) || updated;
      if (newAgent && newAgent.id) {
        setAgents(prev => prev.map(a => a.id === newAgent.id ? { ...a, ...newAgent } : a));
      }
      // Mirror onto the dashboard's user object so other panels see the
      // change without waiting for /me's 30s poll.
      onUpdate && onUpdate({});
      toast && toast.push({ title: `${selected.name} updated`, meta: "Agent picks it up on its next hourly review", duration: 3500 });
    } catch (e) {
      const msg = (e && (e.detail || e.message)) || "Try again";
      toast && toast.push({ title: "Save failed", meta: msg.replace(/^\d+:\s*/, ""), duration: 4000 });
    } finally {
      setSaving(false);
    }
  }

  // ---------------------------------------------------------------------
  //  Strategy tuning — PATCH /agents/:id/strategy + POST .../strategy/unpin
  //
  //  stratEdits holds only the fields the user has touched. We merge them
  //  on top of the agent's current strategy_state for display, but only
  //  the edits are sent up. The backend merges onto the persisted
  //  strategy_state and (by default) pins the agent.
  // ---------------------------------------------------------------------
  function stratGet(field, fallback) {
    if (stratEdits[field] !== undefined) return stratEdits[field];
    const ss = (selected && selected.strategy_state) || {};
    return ss[field] !== undefined ? ss[field] : fallback;
  }
  function stratSet(field, value) {
    setStratEdits(e => ({ ...e, [field]: value }));
  }

  const stratDirty = Object.keys(stratEdits).length > 0;
  const isPinned   = !!(selected && selected.strategy_pinned);

  async function saveStrategy() {
    if (!selected || stratSaving || !stratDirty) return;
    setStratSaving(true);
    try {
      // Coerce numeric fields back from strings (range/number inputs return
      // strings depending on the browser). Only send fields the user edited.
      const payload = { pin: true };
      const numericFields = [
        "target_position_size_pct", "max_positions", "leverage",
        "stop_loss_pct", "take_profit_pct",
        "trailing_trigger_pct", "trailing_lock_pct", "max_hold_hours",
        "cooldown_minutes",
      ];
      for (const [k, v] of Object.entries(stratEdits)) {
        if (numericFields.includes(k)) {
          const n = Number(v);
          if (Number.isFinite(n)) payload[k] = n;
        } else {
          payload[k] = v;
        }
      }
      const res = await acSend(`/agents/${selected.id}/strategy`, payload, "PATCH");
      const newAgent = (res && res.agent) || null;
      if (newAgent && newAgent.id) {
        setAgents(prev => prev.map(a => a.id === newAgent.id ? { ...a, ...newAgent } : a));
      }
      setStratEdits({});
      toast && toast.push({
        title:    `${selected.name} now self-managed`,
        meta:     `Your tuning is live — AI will not auto-adjust until you reset.`,
        duration: 4500,
      });
    } catch (e) {
      const msg = (e && (e.detail || e.message)) || "Try again";
      toast && toast.push({ title: "Save failed", meta: msg.replace(/^\d+:\s*/, ""), duration: 4500 });
    } finally {
      setStratSaving(false);
    }
  }

  async function resetToAI() {
    if (!selected || stratSaving) return;
    if (!window.confirm(`Hand ${selected.name} back to the AI? Current strategy stays as a starting point; the AI will tune it on its next hourly review.`)) {
      return;
    }
    setStratSaving(true);
    try {
      const res = await acSend(`/agents/${selected.id}/strategy/unpin`, null, "POST");
      const newAgent = (res && res.agent) || null;
      if (newAgent && newAgent.id) {
        setAgents(prev => prev.map(a => a.id === newAgent.id ? { ...a, ...newAgent } : a));
      }
      setStratEdits({});
      toast && toast.push({
        title:    `${selected.name} is AI-managed again`,
        meta:     `Claude will retune within the hour.`,
        duration: 4000,
      });
    } catch (e) {
      const msg = (e && (e.detail || e.message)) || "Try again";
      toast && toast.push({ title: "Reset failed", meta: msg.replace(/^\d+:\s*/, ""), duration: 4500 });
    } finally {
      setStratSaving(false);
    }
  }

  function statusPill(a) {
    if (!a) return null;
    // Risk state takes precedence over LIVE/PAUSED. Halted is the loudest
    // because it's the only state that needs user action to clear.
    const rs = a.risk_state;
    if (rs === "halted") {
      return (
        <span style={{
          fontSize: 10, letterSpacing: 1, padding: "2px 6px", marginLeft: 8,
          color: "#fff", background: "var(--red, #b13b3b)", borderRadius: 3,
          fontFamily: "JetBrains Mono, monospace",
        }} title="Trailing drawdown breached 12% — this agent can no longer qualify for a credit line. It keeps trading with tighter risk controls (soft/hard cut still apply) until the balance runs out. Data still flows for model training.">⚠ NO CREDIT</span>
      );
    }
    if (rs === "hard_cut") {
      return (
        <span style={{
          fontSize: 10, letterSpacing: 1, padding: "2px 6px", marginLeft: 8,
          color: "var(--red, #b13b3b)", background: "rgba(177,59,59,0.12)",
          border: "1px solid rgba(177,59,59,0.45)", borderRadius: 3,
          fontFamily: "JetBrains Mono, monospace",
        }} title="Daily drawdown breached 7.5%. Trading resumes at UTC midnight.">🛑 HARD CUT</span>
      );
    }
    if (rs === "soft_cut") {
      return (
        <span style={{
          fontSize: 10, letterSpacing: 1, padding: "2px 6px", marginLeft: 8,
          color: "var(--amber, #d29022)", background: "rgba(210,144,34,0.12)",
          border: "1px solid rgba(210,144,34,0.45)", borderRadius: 3,
          fontFamily: "JetBrains Mono, monospace",
        }} title="Daily drawdown above 5%. New positions sized at 50% until recovery.">⚠ SOFT CUT</span>
      );
    }
    const isLive = a.status === "active";
    return (
      <span style={{
        fontSize: 10, letterSpacing: 1, padding: "2px 6px",
        color: isLive ? "var(--accent)" : "var(--cg-muted)",
        background: isLive ? "rgba(29,158,117,0.10)" : "var(--cg-tint)",
        borderRadius: 3, marginLeft: 8,
      }}>{isLive ? "● LIVE" : "⏸ PAUSED"}</span>
    );
  }

  return (
    <div className="cg-myagent">
      <div className="cg-myagent-tabs">
        <button className={!showApi ? "active" : ""} onClick={() => setShowApi(false)}>[STRATEGY]</button>
        <button className={showApi ? "active" : ""} onClick={() => setShowApi(true)}>[API_ACCESS]</button>
      </div>

      {/* Agent picker — shows one tab per owned agent. Hidden when there's
          only one (no need to pick) and replaced with a passive label.
          When multiple agents exist this is how the user switches between
          them; every form action below targets `selected`. */}
      {!showApi && (
        <div className="cg-agent-picker">
          {!loadedAgents && (
            <span className="cg-agent-picker-empty">Loading agents…</span>
          )}
          {loadedAgents && agents.length === 0 && (
            <span className="cg-agent-picker-empty">No agents yet — create your first one.</span>
          )}
          {loadedAgents && agents.length > 0 && agents.map(a => (
            <button
              key={a.id}
              className={"cg-agent-tab" + (a.id === selectedAgentId ? " active" : "") + (a.status !== "active" ? " paused" : "")}
              onClick={() => setSelectedAgentId(a.id)}
            >
              {a.name}{statusPill(a)}
            </button>
          ))}
          {loadedAgents && (
            <button
              className="cg-agent-tab"
              onClick={() => setAddOpen(true)}
              style={{ color: "var(--accent)", borderStyle: "dashed" }}
              title="Design and launch a new agent"
            >
              + NEW AGENT
            </button>
          )}
        </div>
      )}

      {!showApi && selected && selected.kya_id && (
        <div style={{ marginBottom: 12, padding: "10px 14px", border: "1px solid var(--border)", background: "var(--cg-tint-3)", display: "flex", justifyContent: "space-between", alignItems: "center", flexWrap: "wrap", gap: 8 }}>
          <div>
            <div style={{ fontSize: 10, color: "var(--cg-muted)", letterSpacing: 1.5, marginBottom: 4, fontFamily: "JetBrains Mono, monospace" }}>// KYA_IDENTITY · BILLIONS_NETWORK</div>
            <KyaBadge id={selected.kya_id} status={selected.kya_status || "assigned"} />
          </div>
          <div style={{ fontSize: 11, color: "var(--cg-muted)", lineHeight: 1.5, maxWidth: 320, textAlign: "right" }}>
            {selected.kya_status === "verified"
              ? "Verified by Billions Network — this agent's human owner has been linked on-chain."
              : "Identity assigned. Face-scan ownership verification via the Billions app is coming soon."}
          </div>
        </div>
      )}

      {!showApi && selected && selected.risk_state && (
        <RiskBanner agent={selected} />
      )}

      {!showApi && selected ? (
        <div className="cg-myagent-grid">
          <Card
            title={`AGENT_PERSONALITY — ${selected.name}`}
            right={
              <div style={{ display: "flex", gap: 8, alignItems: "center" }}>
                <button
                  className="cg-cta-ghost"
                  onClick={togglePause}
                  disabled={pauseBusy}
                  title={selected.status === "active"
                    ? "Stop the agent from opening new trades. Open positions stay open."
                    : "Resume trading on the next 30s tick."}
                  style={{
                    padding: "4px 12px",
                    fontSize: 11,
                    background: selected.status === "active"
                      ? "rgba(210,144,34,0.14)"
                      : "rgba(29,158,117,0.10)",
                    color: selected.status === "active" ? "var(--amber, #d29022)" : "var(--accent)",
                  }}
                >
                  {pauseBusy ? "…" : selected.status === "active" ? "⏸ PAUSE" : "▶ RESUME"}
                </button>
                <button
                  className="cg-cta-ghost"
                  onClick={() => setCoachOpen(true)}
                  style={{ padding: "4px 12px", fontSize: 11, background: "rgba(29,158,117,0.10)", color: "var(--accent)" }}
                >
                  ✨ COACH {selected.name}
                </button>
              </div>
            }
          >
            <textarea
              className="cg-textarea"
              rows={10}
              value={desc}
              onChange={e => setDesc(e.target.value)}
            />
            <div className="cg-myagent-actions">
              <button
                className="cg-cta-primary"
                disabled={!dirty || saving}
                onClick={saveChanges}
              >{saving ? "SAVING…" : "SAVE CHANGES"}</button>
              <span className="cg-help">Changes take effect on {selected.name}'s next strategy review (~1 hour)</span>
            </div>
          </Card>
          <Card title={`AGENT_SETTINGS — ${selected.name}`}>
            <div className="cg-field">
              <label>TARGET_TIER</label>
              <select value={target} onChange={e => setTarget(e.target.value)}>
                <option value="speculative">Speculative</option>
                <option value="emerging">Emerging</option>
                <option value="qualified">Qualified</option>
                <option value="elite">Elite</option>
              </select>
            </div>
            <div className="cg-field">
              <label>MARKETS</label>
              <div className="cg-chips">
                {["BTC", "ETH", "SOL", "HYPE", "AVAX", "ARB"].map(m => {
                  const on = markets.includes(m);
                  return (
                    <button key={m} className={"cg-chip" + (on ? " active" : "")} onClick={() => setMarkets(on ? markets.filter(x => x !== m) : [...markets, m])}>
                      {m}{on ? " ×" : " +"}
                    </button>
                  );
                })}
              </div>
            </div>
            <div className="cg-field">
              <label>
                MAX_LEVERAGE
                <span style={{ marginLeft: 8, color: "var(--accent)", fontFamily: "JetBrains Mono, monospace", fontSize: 16, fontWeight: 600 }}>
                  {maxLev}x
                </span>
              </label>
              <input
                type="range"
                min={2}
                max={20}
                step={1}
                value={maxLev}
                onChange={e => setMaxLev(Number(e.target.value))}
                style={{ width: "100%", marginTop: 6 }}
              />
              <div style={{ display: "flex", justifyContent: "space-between", fontSize: 10, color: "var(--muted)", marginTop: 4, fontFamily: "JetBrains Mono, monospace" }}>
                <span>2x</span><span>5x</span><span>10x</span><span>15x</span><span>20x</span>
              </div>
              <div style={{ fontSize: 11, color: "var(--muted)", marginTop: 8, lineHeight: 1.55 }}>
                Liquidation at <span className="mono accent">{(100 / maxLev).toFixed(1)}%</span> adverse move on notional.
                Higher leverage → bigger PnL, faster liquidation, deeper drawdowns.
                Drawdown is the most-weighted negative signal in your credit score.
              </div>
            </div>
          </Card>

          {/* STRATEGY TUNING — direct edit of strategy_state. Saving auto-pins
              so the AI stops touching the values the user just set. */}
          <Card
            title={`STRATEGY_TUNING — ${selected.name}`}
            right={
              <span style={{
                fontSize: 10, letterSpacing: 1, padding: "3px 8px",
                color:      isPinned ? "var(--accent)" : "var(--cg-muted)",
                background: isPinned ? "rgba(29,158,117,0.12)" : "var(--cg-tint)",
                border:     "1px solid " + (isPinned ? "rgba(29,158,117,0.30)" : "var(--border)"),
                borderRadius: 3,
                fontFamily: "JetBrains Mono, monospace",
              }}>
                {isPinned ? "● SELF-MANAGED" : "◎ AI-MANAGED"}
              </span>
            }
          >
            <div style={{ fontSize: 11, color: "var(--muted)", lineHeight: 1.6, marginBottom: 14 }}>
              {isPinned
                ? `You've taken the wheel on ${selected.name}. The AI will not auto-adjust these values until you reset.`
                : `${selected.name} is currently AI-managed — values update every hour. Edit any field and save to take control yourself.`}
            </div>

            <div className="cg-field">
              <label>STOP_LOSS % <span style={{ color: "var(--accent)", marginLeft: 8 }}>{Number(stratGet("stop_loss_pct", 1.0)).toFixed(2)}%</span></label>
              <input type="range" min={0.1} max={5} step={0.1}
                value={stratGet("stop_loss_pct", 1.0)}
                onChange={e => stratSet("stop_loss_pct", e.target.value)}
                style={{ width: "100%" }} />
            </div>

            <div className="cg-field">
              <label>TAKE_PROFIT % <span style={{ color: "var(--accent)", marginLeft: 8 }}>{Number(stratGet("take_profit_pct", 2.0)).toFixed(2)}%</span></label>
              <input type="range" min={0.3} max={15} step={0.1}
                value={stratGet("take_profit_pct", 2.0)}
                onChange={e => stratSet("take_profit_pct", e.target.value)}
                style={{ width: "100%" }} />
            </div>

            <div className="cg-field">
              <label>LEVERAGE <span style={{ color: "var(--accent)", marginLeft: 8 }}>{stratGet("leverage", 4)}x</span></label>
              <input type="range" min={1} max={20} step={1}
                value={stratGet("leverage", 4)}
                onChange={e => stratSet("leverage", e.target.value)}
                style={{ width: "100%" }} />
              <div style={{ fontSize: 10, color: "var(--muted)", marginTop: 4 }}>
                Capped at MAX_LEVERAGE ({maxLev}x) by your agent settings above.
              </div>
            </div>

            <div className="cg-field">
              <label>POSITION_SIZE % <span style={{ color: "var(--accent)", marginLeft: 8 }}>{Number(stratGet("target_position_size_pct", 3)).toFixed(1)}%</span></label>
              <input type="range" min={0.5} max={20} step={0.5}
                value={stratGet("target_position_size_pct", 3)}
                onChange={e => stratSet("target_position_size_pct", e.target.value)}
                style={{ width: "100%" }} />
              <div style={{ fontSize: 10, color: "var(--muted)", marginTop: 4 }}>
                Margin allocated per trade, before leverage. Notional = position_size × leverage.
              </div>
            </div>

            <div className="cg-field">
              <label>MAX_POSITIONS <span style={{ color: "var(--accent)", marginLeft: 8 }}>{stratGet("max_positions", 3)}</span></label>
              <input type="range" min={1} max={10} step={1}
                value={stratGet("max_positions", 3)}
                onChange={e => stratSet("max_positions", e.target.value)}
                style={{ width: "100%" }} />
            </div>

            <div className="cg-field">
              <label>
                <input type="checkbox"
                  checked={!!stratGet("trailing_stop", true)}
                  onChange={e => stratSet("trailing_stop", e.target.checked)}
                  style={{ marginRight: 8 }} />
                TRAILING_STOP enabled
              </label>
              {!!stratGet("trailing_stop", true) && (
                <div style={{ paddingLeft: 24, marginTop: 6 }}>
                  <div style={{ fontSize: 11, color: "var(--muted)", marginBottom: 4 }}>
                    Trail arms at <span className="mono accent">{Number(stratGet("trailing_trigger_pct", 1.5)).toFixed(2)}%</span> profit,
                    then stop sits <span className="mono accent">{Number(stratGet("trailing_lock_pct", 0.5)).toFixed(2)}%</span> below the high.
                  </div>
                  <div style={{ display: "flex", gap: 12, marginTop: 8 }}>
                    <div style={{ flex: 1 }}>
                      <div style={{ fontSize: 10, color: "var(--muted)", marginBottom: 2 }}>ARM AT %</div>
                      <input type="range" min={0.3} max={5} step={0.1}
                        value={stratGet("trailing_trigger_pct", 1.5)}
                        onChange={e => stratSet("trailing_trigger_pct", e.target.value)}
                        style={{ width: "100%" }} />
                    </div>
                    <div style={{ flex: 1 }}>
                      <div style={{ fontSize: 10, color: "var(--muted)", marginBottom: 2 }}>LOCK %</div>
                      <input type="range" min={0} max={3} step={0.1}
                        value={stratGet("trailing_lock_pct", 0.5)}
                        onChange={e => stratSet("trailing_lock_pct", e.target.value)}
                        style={{ width: "100%" }} />
                    </div>
                  </div>
                </div>
              )}
            </div>

            <div className="cg-field">
              <label>MAX_HOLD_HOURS <span style={{ color: "var(--accent)", marginLeft: 8 }}>{Number(stratGet("max_hold_hours", 12)).toFixed(0)}h</span></label>
              <input type="range" min={1} max={48} step={1}
                value={stratGet("max_hold_hours", 12)}
                onChange={e => stratSet("max_hold_hours", e.target.value)}
                style={{ width: "100%" }} />
              <div style={{ fontSize: 10, color: "var(--muted)", marginTop: 4 }}>
                Hard exit if a trade is older than this, regardless of PnL.
              </div>
            </div>

            <div className="cg-myagent-actions" style={{ flexWrap: "wrap" }}>
              <button
                className="cg-cta-primary"
                disabled={!stratDirty || stratSaving}
                onClick={saveStrategy}
              >{stratSaving ? "SAVING…" : (isPinned ? "SAVE CHANGES" : "SAVE & TAKE CONTROL")}</button>
              {isPinned && (
                <button
                  className="cg-cta-ghost"
                  disabled={stratSaving}
                  onClick={resetToAI}
                  style={{ color: "var(--cg-muted)" }}
                >RESET TO AI →</button>
              )}
              <span className="cg-help">
                {isPinned
                  ? "Changes go live on the next 15s execution tick."
                  : "Saving pins the agent — AI stops adjusting until you hit reset."}
              </span>
            </div>
          </Card>
        </div>
      ) : !showApi && loadedAgents ? (
        // No agent selected (likely 0 agents). The empty-state copy in
        // the picker above tells the user what to do; render nothing else.
        null
      ) : showApi ? (
        <CampaignAPI keyVisible={keyVisible} onToggleKey={() => setKeyVisible(v => !v)} />
      ) : null}

      {!showApi && selected && (
        <div style={{ marginTop: 20 }}>
          <StrategyJournalPanel agentId={selected.id} agentName={selected.name} />
        </div>
      )}

      {coachOpen && selected && (
        <StrategyCoachModal
          user={user}
          agentId={selected.id}
          onClose={() => setCoachOpen(false)}
          onApplyPersonality={(p) => {
            // Update both the textarea and the cached agent row so the
            // picker label + diff detection stay consistent.
            setDesc(p);
            setAgents(prev => prev.map(a => a.id === selected.id ? { ...a, personality: p } : a));
            onUpdate && onUpdate({});
          }}
        />
      )}

      {addOpen && (
        <AddAgentModal
          onClose={() => setAddOpen(false)}
          onCreated={(created) => {
            // AddAgentModal returns the freshly-created agent. Append it
            // to the list, focus it, close the modal, and nudge /me so
            // the dashboard's other panels pick up the new count.
            setAddOpen(false);
            if (created && created.id) {
              setAgents(prev => [...prev, created]);
              setSelectedAgentId(created.id);
              toast && toast.push({
                title:    `${created.name || "Agent"} launched`,
                meta:     "First strategy review runs within the hour.",
                duration: 4000,
              });
            }
            onUpdate && onUpdate({});
          }}
        />
      )}
    </div>
  );
}

/* ===============================================================
   CAMPAIGN API SECTION
   =============================================================== */

const CAMPAIGN_API_KEY = "ac_campaign_4f8e2a9b1c3d7e6f8a9b2c3d4e5f6a7b";
const CAMPAIGN_SNIPPETS = {
  python: `from agentics_campaign import CampaignClient

client = CampaignClient(api_key="${CAMPAIGN_API_KEY}")

# Get current BTC price
price = client.get_price("BTC-PERP")

# Open a long position
trade = client.open_trade(market="BTC-PERP", side="long", size_usd=500)
print(f"Opened at \${trade.entry_price:,.0f}")

# Close when done
result = client.close_trade(trade.id)
print(f"PnL: \${result.pnl:.2f} | Credit: {result.credit_earned:.0f} $CREDIT")`,

  javascript: `import { CampaignClient } from '@agentics/campaign';

const client = new CampaignClient({ apiKey: '${CAMPAIGN_API_KEY}' });

const price = await client.getPrice('BTC-PERP');
const trade = await client.openTrade({ market: 'ETH-PERP', side: 'long', sizeUsd: 300 });
const result = await client.closeTrade(trade.id);
console.log(\`PnL: $\${result.pnl.toFixed(2)} | Credit: \${result.creditEarned}\`);`,

  typescript: `import { CampaignClient, type Trade } from '@agentics/campaign';

const client = new CampaignClient({ apiKey: '${CAMPAIGN_API_KEY}' });

const trade: Trade = await client.openTrade({
  market: 'BTC-PERP',
  side: 'long',
  sizeUsd: 500,
});

const result = await client.closeTrade(trade.id);
console.log(\`PnL: $\${result.pnl} | Credit: \${result.creditEarned}\`);`,
};

function CampaignAPI({ keyVisible, onToggleKey }) {
  const [lang, setLang] = useState("python");
  return (
    <div className="cg-api">
      <Card title="CAMPAIGN_API_KEY">
        <div className="cg-apikey-row">
          <code className="cg-apikey">{keyVisible ? CAMPAIGN_API_KEY : "ac_campaign_" + "•".repeat(24)}</code>
          <button className="cg-cta-ghost" onClick={onToggleKey}>{keyVisible ? "[HIDE]" : "[REVEAL]"}</button>
          <button className="cg-cta-ghost" onClick={() => navigator.clipboard && navigator.clipboard.writeText(CAMPAIGN_API_KEY)}>[COPY]</button>
        </div>
        <div className="cg-apikey-warn">⚠ Save this — shown once. Cannot be retrieved later.</div>
      </Card>

      <Card title="QUICKSTART">
        <div className="cg-lang-tabs">
          {["python", "javascript", "typescript"].map(l => (
            <button key={l} className={lang === l ? "active" : ""} onClick={() => setLang(l)}>[{l.toUpperCase()}]</button>
          ))}
        </div>
        <pre className="cg-code">{CAMPAIGN_SNIPPETS[lang]}</pre>
        <div className="cg-install">
          <code>pip install agentics-campaign</code>
          <code>npm install @agentics/campaign</code>
        </div>
      </Card>

      <Card title="RECENT_API_CALLS">
        <div className="cg-table">
          <div className="cg-tr head"><span>TIME</span><span>METHOD</span><span>STATUS</span><span>LATENCY</span></div>
          {[
            ["14:23:14", "POST /trade/open", "200_OK", "84ms"],
            ["14:18:08", "POST /trade/close", "200_OK", "62ms"],
            ["14:12:55", "GET /price/BTC-PERP", "200_OK", "21ms"],
            ["14:05:33", "POST /trade/open", "200_OK", "91ms"],
            ["13:55:01", "GET /score", "200_OK", "44ms"],
          ].map(([t, m, s, l], i) => (
            <div key={i} className="cg-tr">
              <span>{t}</span><span>{m}</span><span className="accent">{s}</span><span>{l}</span>
            </div>
          ))}
        </div>
      </Card>
    </div>
  );
}

/* ===============================================================
   CAMPAIGN LEADERBOARD
   =============================================================== */

/* ===============================================================
   EXPORTS
   =============================================================== */
Object.assign(window, {
  MyAgent, CampaignAPI, StrategyJournalPanel, JournalEntry,
});
