// Centralized registry for `agent:subscribe` / `agent:unsubscribe` over the
// editor WebSocket. Multiple panes / dialogs / async helpers can request a
// subscription for the same agentId; the server stays subscribed exactly once
// per agent regardless of client count.
//
// Two distinct concepts:
//   - clientCount: per-call refcount. Two visible panes for the same agent
//     means clientCount=2.
//   - serverActive: did the server-side subscribe message actually go out?
//     Always 1 per agent when there are any client subscribers. May be empty
//     even with non-zero clientCount during a socket-down window; the next
//     onSocketReconnect() re-issues.
//
// Wire onSocketReconnect() to the editor's WebSocket reconnect callback
// (next to where socketConnectionVersion is incremented).
import { getEditorRealtime, } from "../client/realtime/realtimeTransport";
const clientCount = new Map();
const serverActive = new Set();
function trySend(message) {
    return getEditorRealtime().send(message);
}
// Sends agent:subscribe. Marks serverActive optimistically so a second subscriber for the same
// agent doesn't issue a duplicate in-flight subscribe, then clears it if delivery fails (WebSocket:
// not open; SSE: POST rejected) so the next onSocketReconnect re-issues it.
function ensureServerSubscribed(agentId) {
    if (serverActive.has(agentId))
        return;
    serverActive.add(agentId);
    void getEditorRealtime()
        .sendWithAck({ type: "agent:subscribe", agentId })
        .then((ok) => {
        if (!ok)
            serverActive.delete(agentId);
    });
}
export function subscribeAgent(agentId) {
    clientCount.set(agentId, (clientCount.get(agentId) ?? 0) + 1);
    ensureServerSubscribed(agentId);
    let released = false;
    return () => {
        if (released)
            return;
        released = true;
        const remaining = (clientCount.get(agentId) ?? 1) - 1;
        if (remaining <= 0) {
            clientCount.delete(agentId);
            if (serverActive.delete(agentId)) {
                trySend({ type: "agent:unsubscribe", agentId });
            }
        }
        else {
            clientCount.set(agentId, remaining);
        }
    };
}
// Re-sends agent:subscribe even when the registry already considers the
// server-side subscription active. The server treats this as idempotent and
// replays buffered run events plus any pending dialog requests for the agent.
export function requestAgentSubscriptionReplay(agentId) {
    return trySend({ type: "agent:subscribe", agentId });
}
// Called by EditorShell on WebSocket (re)connect. Re-issues subscribe for
// every agent with at least one client subscriber. Always iterates clientCount,
// never serverActive — a previous subscriber that mounted while the socket was
// down would not have made it into serverActive.
export function onSocketReconnect() {
    serverActive.clear();
    for (const [agentId, n] of clientCount) {
        if (n > 0)
            ensureServerSubscribed(agentId);
    }
}
// Test-only — not intended for production callers.
export const __agentSubscriptionRegistryTesting__ = {
    clientCount,
    serverActive,
    reset() {
        clientCount.clear();
        serverActive.clear();
    },
};
//# sourceMappingURL=agentSubscriptionRegistry.js.map