"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.TmuxControlRegistry = void 0;
exports.getTmuxControlRegistry = getTmuxControlRegistry;
const logger_1 = require("../../lib/logger");
const tmux_control_mode_metrics_1 = require("./tmux-control-mode-metrics");
const tmux_control_client_1 = require("./tmux-control-client");
const logger = (0, logger_1.createLogger)('tmux-control-registry');
const DEFAULT_REGISTRY_IDLE_TIMEOUT_MS = 15_000;
class TmuxControlRegistry {
    entries = new Map();
    handlers = new Map();
    idleTimeoutMs;
    createClient;
    constructor(options = {}) {
        this.idleTimeoutMs = options.idleTimeoutMs ?? DEFAULT_REGISTRY_IDLE_TIMEOUT_MS;
        this.createClient = options.createClient ?? (() => new tmux_control_client_1.TmuxControlClient(options));
    }
    subscribe(sessionName, subscriberId, handler) {
        const entry = this.ensureEntry(sessionName);
        entry.subscribers.add(subscriberId);
        this.cancelIdleCleanup(entry);
        this.updateMetrics();
        let handlerSet = this.handlers.get(sessionName);
        if (!handlerSet) {
            handlerSet = new Set();
            this.handlers.set(sessionName, handlerSet);
        }
        handlerSet.add(handler);
        return () => {
            handlerSet?.delete(handler);
            this.unsubscribe(sessionName, subscriberId);
        };
    }
    sendInput(sessionName, input) {
        const entry = this.entries.get(sessionName);
        if (!entry) {
            throw new Error(`No control client registered for ${sessionName}`);
        }
        entry.client.sendInput(input);
    }
    resize(sessionName, cols, rows) {
        const entry = this.entries.get(sessionName);
        if (!entry) {
            throw new Error(`No control client registered for ${sessionName}`);
        }
        entry.client.resize(cols, rows);
    }
    hasSession(sessionName) {
        return this.entries.has(sessionName);
    }
    getSubscriberCount(sessionName) {
        return this.entries.get(sessionName)?.subscribers.size ?? 0;
    }
    getTotalSubscriberCount() {
        let count = 0;
        for (const entry of this.entries.values()) {
            count += entry.subscribers.size;
        }
        return count;
    }
    getSessionCount() {
        return this.entries.size;
    }
    shutdown() {
        for (const [sessionName, entry] of this.entries) {
            this.teardownEntry(sessionName, entry);
        }
        this.entries.clear();
        this.handlers.clear();
        this.updateMetrics();
    }
    ensureEntry(sessionName) {
        const existing = this.entries.get(sessionName);
        if (existing) {
            return existing;
        }
        const client = this.createClient(sessionName);
        client.start(sessionName);
        const unsubscribeClientEvent = client.onEvent((event) => {
            const handlers = this.handlers.get(sessionName);
            if (handlers) {
                for (const handler of handlers) {
                    handler(event);
                }
            }
            if (event.type === 'exit' || event.type === 'error') {
                this.deleteEntry(sessionName);
            }
        });
        const entry = {
            client,
            subscribers: new Set(),
            unsubscribeClientEvent,
            idleTimer: null,
        };
        this.entries.set(sessionName, entry);
        this.updateMetrics();
        return entry;
    }
    unsubscribe(sessionName, subscriberId) {
        const entry = this.entries.get(sessionName);
        if (!entry) {
            return;
        }
        entry.subscribers.delete(subscriberId);
        this.updateMetrics();
        if (entry.subscribers.size === 0) {
            this.scheduleIdleCleanup(sessionName, entry);
        }
    }
    scheduleIdleCleanup(sessionName, entry) {
        if (this.idleTimeoutMs <= 0) {
            this.deleteEntry(sessionName);
            return;
        }
        this.cancelIdleCleanup(entry);
        entry.idleTimer = setTimeout(() => {
            logger.debug('idle-cleanup', { sessionName });
            this.deleteEntry(sessionName);
        }, this.idleTimeoutMs);
    }
    cancelIdleCleanup(entry) {
        if (entry.idleTimer) {
            clearTimeout(entry.idleTimer);
            entry.idleTimer = null;
        }
    }
    deleteEntry(sessionName) {
        const entry = this.entries.get(sessionName);
        if (!entry) {
            return;
        }
        this.teardownEntry(sessionName, entry);
        this.entries.delete(sessionName);
        this.handlers.delete(sessionName);
        this.updateMetrics();
    }
    teardownEntry(_sessionName, entry) {
        this.cancelIdleCleanup(entry);
        entry.unsubscribeClientEvent();
        entry.client.stop();
        (0, tmux_control_mode_metrics_1.incrementTmuxControlCleanupCount)();
    }
    updateMetrics() {
        (0, tmux_control_mode_metrics_1.setTmuxControlActiveSessions)(this.getSessionCount());
        (0, tmux_control_mode_metrics_1.setTmuxControlSubscriberCount)(this.getTotalSubscriberCount());
    }
}
exports.TmuxControlRegistry = TmuxControlRegistry;
let tmuxControlRegistrySingleton = null;
function getTmuxControlRegistry() {
    if (!tmuxControlRegistrySingleton) {
        tmuxControlRegistrySingleton = new TmuxControlRegistry();
    }
    return tmuxControlRegistrySingleton;
}
