/**
 * Nexus Prime — Machine Efficiency Governor
 *
 * First-class subsystem that tracks machine resource usage and
 * enforces hard limits on worktrees, caches, dashboard state,
 * and process count. Can degrade operation under pressure.
 *
 * Principle: agentically strong and laptop-safe.
 */
import { DEFAULT_LIMITS } from './types.js';
import { detectMemoryPressure, estimateProcessCount } from './pressure-detector.js';
export class MachineEfficiencyGovernor {
    limits;
    activeWorktrees = 0;
    activeDashboardListeners = 0;
    cacheStats = {
        proofCacheSizeMB: 0,
        graphCacheSizeMB: 0,
        embeddingCacheSizeMB: 0,
        totalCacheSizeMB: 0,
        maxCacheSizeMB: DEFAULT_LIMITS.maxCacheSizeMB,
    };
    pressureLevel = 'nominal';
    idleMode = false;
    lastCheckedAt = 0;
    checkInterval = null;
    constructor(limits) {
        this.limits = { ...DEFAULT_LIMITS, ...limits };
    }
    /** Start periodic pressure checks. */
    start(intervalMs = 30_000) {
        this.refresh();
        if (this.checkInterval)
            return;
        this.checkInterval = setInterval(() => this.refresh(), intervalMs);
        this.checkInterval.unref(); // Don't keep process alive
    }
    /** Stop periodic checks. */
    stop() {
        if (this.checkInterval) {
            clearInterval(this.checkInterval);
            this.checkInterval = null;
        }
    }
    /** Refresh all tracked metrics. */
    refresh() {
        this.pressureLevel = detectMemoryPressure();
        this.lastCheckedAt = Date.now();
        this.cacheStats.totalCacheSizeMB =
            this.cacheStats.proofCacheSizeMB +
                this.cacheStats.graphCacheSizeMB +
                this.cacheStats.embeddingCacheSizeMB;
    }
    /** Get current governor state (for dashboard Trust surface). */
    getState() {
        return {
            activeWorktrees: this.activeWorktrees,
            maxWorktrees: this.limits.maxWorktreesPerWorkspace,
            activeDashboardListeners: this.activeDashboardListeners,
            maxDashboardListeners: this.limits.maxDashboardListeners,
            estimatedProcessCount: estimateProcessCount(),
            cacheStats: { ...this.cacheStats },
            pressureLevel: this.pressureLevel,
            parallelismBudget: this.getParallelismBudget(),
            idleMode: this.idleMode,
            lastCheckedAt: this.lastCheckedAt,
        };
    }
    // ─── Worktree limits ──────────────────────────────────────────────────
    /** Check if a new worktree can be allocated. */
    canAllocateWorktree() {
        return this.activeWorktrees < this.limits.maxWorktreesPerWorkspace;
    }
    /** Register a worktree allocation. Returns false if cap exceeded. */
    registerWorktree() {
        if (!this.canAllocateWorktree())
            return false;
        this.activeWorktrees++;
        return true;
    }
    /** Release a worktree. */
    releaseWorktree() {
        this.activeWorktrees = Math.max(0, this.activeWorktrees - 1);
    }
    /** Get active worktree count. */
    getActiveWorktreeCount() {
        return this.activeWorktrees;
    }
    // ─── Dashboard listener limits ────────────────────────────────────────
    /** Check if a new dashboard listener can be added. */
    canAddDashboardListener() {
        return this.activeDashboardListeners < this.limits.maxDashboardListeners;
    }
    /** Register a dashboard listener. Returns false if cap exceeded. */
    registerDashboardListener() {
        if (!this.canAddDashboardListener())
            return false;
        this.activeDashboardListeners++;
        return true;
    }
    /** Release a dashboard listener. */
    releaseDashboardListener() {
        this.activeDashboardListeners = Math.max(0, this.activeDashboardListeners - 1);
    }
    // ─── Cache limits ─────────────────────────────────────────────────────
    /** Update cache size for a given cache type. */
    updateCacheSize(type, sizeMB) {
        if (type === 'proof')
            this.cacheStats.proofCacheSizeMB = sizeMB;
        else if (type === 'graph')
            this.cacheStats.graphCacheSizeMB = sizeMB;
        else if (type === 'embedding')
            this.cacheStats.embeddingCacheSizeMB = sizeMB;
        this.cacheStats.totalCacheSizeMB =
            this.cacheStats.proofCacheSizeMB +
                this.cacheStats.graphCacheSizeMB +
                this.cacheStats.embeddingCacheSizeMB;
    }
    /** Check if cache is within bounds. */
    isCacheWithinBounds() {
        return this.cacheStats.totalCacheSizeMB <= this.limits.maxCacheSizeMB;
    }
    // ─── Idle mode ────────────────────────────────────────────────────────
    /** Enter idle mode (longer polling intervals, reduced background work). */
    enterIdleMode() {
        this.idleMode = true;
    }
    /** Exit idle mode. */
    exitIdleMode() {
        this.idleMode = false;
    }
    /** Get recommended polling interval based on idle mode. */
    getPollingInterval() {
        return this.idleMode ? this.limits.idlePollingIntervalMs : 5000;
    }
    // ─── Pressure-aware degradation ───────────────────────────────────────
    /** Get current pressure level. */
    getPressureLevel() {
        return this.pressureLevel;
    }
    /**
     * Get the parallelism budget based on pressure level.
     * nominal:  full parallelism (up to maxWorktrees)
     * elevated: 50% reduction
     * critical: single-worker mode
     */
    getParallelismBudget() {
        switch (this.pressureLevel) {
            case 'critical': return 1;
            case 'elevated': return Math.max(1, Math.floor(this.limits.maxWorktreesPerWorkspace / 2));
            default: return this.limits.maxWorktreesPerWorkspace;
        }
    }
    /** Check if simulation should be paused (elevated or critical). */
    shouldPauseSimulation() {
        return this.pressureLevel !== 'nominal';
    }
    /** Check if non-critical background work should be paused. */
    shouldPauseBackgroundWork() {
        return this.pressureLevel === 'critical';
    }
    /** Get recommended dashboard refresh interval based on pressure. */
    getDashboardRefreshInterval() {
        switch (this.pressureLevel) {
            case 'critical': return 30_000; // 30s
            case 'elevated': return 15_000; // 15s
            default: return 5_000; // 5s
        }
    }
}
// ─── Singleton ──────────────────────────────────────────────────────────────
let sharedGovernor;
export function getSharedGovernor() {
    if (!sharedGovernor) {
        sharedGovernor = new MachineEfficiencyGovernor();
        sharedGovernor.start();
    }
    return sharedGovernor;
}
