/**
 * Agent Workspace
 *
 * Provides isolated workspaces for agents with separate
 * file access, environment, and state management.
 */
import { EventEmitter } from 'events';
import * as path from 'path';
import * as os from 'os';
import fs from 'fs-extra';
import * as crypto from 'crypto';
import { generateSessionKey } from './agent-config.js';
import { logger } from '../../utils/logger.js';
/**
 * Default workspace configuration
 */
export const DEFAULT_WORKSPACE_CONFIG = {
    baseDir: path.join(os.homedir(), '.codebuddy', 'workspaces'),
    isolateTempDir: true,
    trackFileAccess: true,
    maxActiveFiles: 100,
};
// ============================================================================
// Agent Workspace
// ============================================================================
/**
 * Isolated workspace for an agent
 */
export class AgentWorkspace extends EventEmitter {
    config;
    workspaceConfig;
    session;
    state;
    workspaceDir;
    initialized = false;
    constructor(agentConfig, sessionId, workspaceConfig = {}) {
        super();
        this.config = agentConfig;
        this.workspaceConfig = { ...DEFAULT_WORKSPACE_CONFIG, ...workspaceConfig };
        const now = Date.now();
        this.session = {
            key: generateSessionKey(agentConfig.id, sessionId),
            agentId: agentConfig.id,
            sessionId,
            createdAt: now,
            lastActivityAt: now,
        };
        this.workspaceDir = path.join(this.workspaceConfig.baseDir, agentConfig.id, sessionId);
        this.state = {
            workingDirectory: process.cwd(),
            environment: {},
            activeFiles: new Set(),
            state: {},
        };
    }
    /**
     * Initialize workspace
     */
    async initialize() {
        if (this.initialized)
            return;
        // Create workspace directory
        await fs.ensureDir(this.workspaceDir);
        // Create isolated temp directory if enabled
        if (this.workspaceConfig.isolateTempDir) {
            const tempDir = path.join(this.workspaceDir, 'tmp');
            await fs.ensureDir(tempDir);
            this.state.environment.TMPDIR = tempDir;
            this.state.environment.TEMP = tempDir;
            this.state.environment.TMP = tempDir;
        }
        // Create state file
        await this.saveState();
        this.initialized = true;
        this.emit('workspace:initialized', { session: this.session });
        logger.debug('Agent workspace initialized', {
            agentId: this.config.id,
            sessionId: this.session.sessionId,
            workspaceDir: this.workspaceDir,
        });
    }
    /**
     * Get session info
     */
    getSession() {
        return { ...this.session };
    }
    /**
     * Get agent config
     */
    getAgentConfig() {
        return { ...this.config };
    }
    /**
     * Get workspace directory
     */
    getWorkspaceDir() {
        return this.workspaceDir;
    }
    /**
     * Get working directory
     */
    getWorkingDirectory() {
        return this.state.workingDirectory;
    }
    /**
     * Set working directory
     */
    setWorkingDirectory(dir) {
        this.state.workingDirectory = dir;
        this.updateActivity();
    }
    /**
     * Get environment
     */
    getEnvironment() {
        return { ...this.state.environment };
    }
    /**
     * Set environment variable
     */
    setEnvironmentVariable(key, value) {
        this.state.environment[key] = value;
        this.updateActivity();
    }
    /**
     * Track file access
     */
    trackFile(filePath) {
        if (!this.workspaceConfig.trackFileAccess)
            return;
        this.state.activeFiles.add(filePath);
        // Trim if too many files
        if (this.state.activeFiles.size > this.workspaceConfig.maxActiveFiles) {
            const files = Array.from(this.state.activeFiles);
            this.state.activeFiles = new Set(files.slice(-this.workspaceConfig.maxActiveFiles));
        }
        this.updateActivity();
        this.emit('file:accessed', { filePath, agentId: this.config.id });
    }
    /**
     * Get active files
     */
    getActiveFiles() {
        return Array.from(this.state.activeFiles);
    }
    /**
     * Get/set custom state
     */
    getState(key) {
        return this.state.state[key];
    }
    setState(key, value) {
        this.state.state[key] = value;
        this.updateActivity();
    }
    /**
     * Update last activity timestamp
     */
    updateActivity() {
        this.session.lastActivityAt = Date.now();
    }
    /**
     * Check if session is expired
     */
    isExpired() {
        const elapsed = Date.now() - this.session.lastActivityAt;
        return elapsed > this.config.sessionTimeoutMs;
    }
    /**
     * Save workspace state to disk
     */
    async saveState() {
        const stateFile = path.join(this.workspaceDir, 'state.json');
        const data = {
            session: this.session,
            state: {
                workingDirectory: this.state.workingDirectory,
                environment: this.state.environment,
                activeFiles: Array.from(this.state.activeFiles),
                state: this.state.state,
            },
        };
        await fs.writeJSON(stateFile, data, { spaces: 2 });
    }
    /**
     * Load workspace state from disk
     */
    async loadState() {
        const stateFile = path.join(this.workspaceDir, 'state.json');
        if (!await fs.pathExists(stateFile)) {
            return false;
        }
        try {
            const data = await fs.readJSON(stateFile);
            this.session = data.session;
            this.state = {
                workingDirectory: data.state.workingDirectory || process.cwd(),
                environment: data.state.environment || {},
                activeFiles: new Set(data.state.activeFiles || []),
                state: data.state.state || {},
            };
            return true;
        }
        catch (error) {
            logger.warn('Failed to load workspace state', {
                error: error instanceof Error ? error.message : String(error),
            });
            return false;
        }
    }
    /**
     * Clean up workspace
     */
    async cleanup() {
        await this.saveState();
        this.emit('workspace:cleanup', { session: this.session });
    }
    /**
     * Destroy workspace (remove all data)
     */
    async destroy() {
        try {
            await fs.remove(this.workspaceDir);
            this.emit('workspace:destroyed', { session: this.session });
        }
        catch (error) {
            logger.warn('Failed to destroy workspace', {
                error: error instanceof Error ? error.message : String(error),
            });
        }
    }
}
// ============================================================================
// Workspace Manager
// ============================================================================
/**
 * Manages multiple agent workspaces
 */
export class WorkspaceManager extends EventEmitter {
    workspaces = new Map();
    config;
    constructor(config = {}) {
        super();
        this.config = { ...DEFAULT_WORKSPACE_CONFIG, ...config };
    }
    /**
     * Create workspace for an agent
     */
    async createWorkspace(agentConfig, sessionId) {
        const sid = sessionId || crypto.randomBytes(8).toString('hex');
        const workspace = new AgentWorkspace(agentConfig, sid, this.config);
        await workspace.initialize();
        this.workspaces.set(workspace.getSession().key, workspace);
        this.emit('workspace:created', { key: workspace.getSession().key, agentId: agentConfig.id });
        return workspace;
    }
    /**
     * Get workspace by session key
     */
    getWorkspace(sessionKey) {
        return this.workspaces.get(sessionKey);
    }
    /**
     * Get workspace by agent ID (returns first active)
     */
    getWorkspaceByAgent(agentId) {
        for (const workspace of this.workspaces.values()) {
            if (workspace.getAgentConfig().id === agentId && !workspace.isExpired()) {
                return workspace;
            }
        }
        return undefined;
    }
    /**
     * Get all workspaces for an agent
     */
    getWorkspacesForAgent(agentId) {
        return Array.from(this.workspaces.values()).filter(ws => ws.getAgentConfig().id === agentId);
    }
    /**
     * Remove workspace
     */
    async removeWorkspace(sessionKey, destroy = false) {
        const workspace = this.workspaces.get(sessionKey);
        if (!workspace)
            return false;
        if (destroy) {
            await workspace.destroy();
        }
        else {
            await workspace.cleanup();
        }
        this.workspaces.delete(sessionKey);
        this.emit('workspace:removed', { key: sessionKey });
        return true;
    }
    /**
     * Clean up expired workspaces
     */
    async cleanupExpired() {
        const expired = [];
        for (const [key, workspace] of this.workspaces) {
            if (workspace.isExpired()) {
                expired.push(key);
            }
        }
        for (const key of expired) {
            await this.removeWorkspace(key, true);
        }
        return expired.length;
    }
    /**
     * Get all active workspaces
     */
    getActiveWorkspaces() {
        return Array.from(this.workspaces.values()).filter(ws => !ws.isExpired());
    }
    /**
     * Load existing workspace from disk
     */
    async loadWorkspace(agentConfig, sessionId) {
        const workspace = new AgentWorkspace(agentConfig, sessionId, this.config);
        const loaded = await workspace.loadState();
        if (!loaded) {
            return null;
        }
        this.workspaces.set(workspace.getSession().key, workspace);
        return workspace;
    }
    /**
     * Clear all workspaces
     */
    async clearAll(destroy = false) {
        const keys = Array.from(this.workspaces.keys());
        for (const key of keys) {
            await this.removeWorkspace(key, destroy);
        }
    }
    /**
     * Dispose manager
     */
    async dispose() {
        await this.clearAll();
        this.removeAllListeners();
    }
}
// ============================================================================
// Singleton
// ============================================================================
let workspaceManagerInstance = null;
/**
 * Get or create WorkspaceManager singleton
 */
export function getWorkspaceManager(config) {
    if (!workspaceManagerInstance) {
        workspaceManagerInstance = new WorkspaceManager(config);
    }
    return workspaceManagerInstance;
}
/**
 * Reset WorkspaceManager singleton
 */
export async function resetWorkspaceManager() {
    if (workspaceManagerInstance) {
        await workspaceManagerInstance.dispose();
    }
    workspaceManagerInstance = null;
}
//# sourceMappingURL=agent-workspace.js.map