/**
 * Collaborative Mode
 *
 * Multi-user collaboration features for Code Buddy:
 * - Shared sessions between users
 * - Real-time synchronization
 * - Presence indicators
 * - Conflict resolution
 * - Permission management
 */
import { EventEmitter } from 'events';
import crypto from 'crypto';
/**
 * Maximum number of messages to keep in shared context.
 * Older messages are trimmed to prevent memory leaks in long sessions.
 */
const MAX_SHARED_MESSAGES = 500;
const DEFAULT_CONFIG = {
    serverUrl: 'ws://localhost',
    port: 9876,
    heartbeatInterval: 30000,
    lockTimeout: 300000,
    maxSessionDuration: 86400000,
};
const USER_COLORS = [
    '#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4',
    '#FFEAA7', '#DDA0DD', '#98D8C8', '#F7DC6F',
];
/**
 * Collaborative Session Manager
 */
export class CollaborativeSessionManager extends EventEmitter {
    config;
    sessions = new Map();
    currentSession = null;
    currentUser = null;
    constructor(config = {}) {
        super();
        this.config = { ...DEFAULT_CONFIG, ...config };
    }
    createSession(name, user, permissions = {}) {
        const sessionId = this.generateId('sess');
        const userId = this.generateId('user');
        const owner = {
            ...user,
            id: userId,
            role: 'owner',
            color: this.assignColor(0),
            lastActive: new Date(),
        };
        const session = {
            id: sessionId,
            name,
            ownerId: userId,
            users: new Map([[userId, owner]]),
            sharedContext: {
                messages: [],
                files: new Map(),
                variables: new Map(),
            },
            permissions: {
                allowEditing: true,
                allowExecution: true,
                allowFileOperations: true,
                requireApproval: false,
                maxUsers: 10,
                ...permissions,
            },
            createdAt: new Date(),
            expiresAt: new Date(Date.now() + this.config.maxSessionDuration),
        };
        this.sessions.set(sessionId, session);
        this.currentSession = session;
        this.currentUser = owner;
        this.emit('session-created', session);
        return session;
    }
    async joinSession(sessionId, user) {
        const session = this.sessions.get(sessionId);
        if (!session)
            throw new Error('Session not found: ' + sessionId);
        if (session.users.size >= session.permissions.maxUsers) {
            throw new Error(`Session is full (${session.permissions.maxUsers} users maximum). Wait for someone to leave or ask the owner to increase the limit.`);
        }
        const userId = this.generateId('user');
        const newUser = {
            ...user,
            id: userId,
            role: 'editor',
            color: this.assignColor(session.users.size),
            lastActive: new Date(),
        };
        session.users.set(userId, newUser);
        this.currentSession = session;
        this.currentUser = newUser;
        this.emit('user-joined', { session, user: newUser });
        return session;
    }
    leaveSession() {
        if (!this.currentSession || !this.currentUser)
            return;
        const session = this.currentSession;
        const userId = this.currentUser.id;
        for (const file of session.sharedContext.files.values()) {
            file.locks.delete(userId);
        }
        session.users.delete(userId);
        if (session.ownerId === userId) {
            const nextOwner = Array.from(session.users.values())[0];
            if (nextOwner) {
                session.ownerId = nextOwner.id;
                nextOwner.role = 'owner';
            }
            else {
                this.sessions.delete(session.id);
            }
        }
        this.currentSession = null;
        this.currentUser = null;
        this.emit('user-left', { sessionId: session.id, userId });
    }
    addMessage(content, type = 'user') {
        if (!this.currentSession || !this.currentUser) {
            throw new Error('Not currently in a collaborative session. Join or create a session first.');
        }
        const message = {
            id: this.generateId('msg'),
            userId: this.currentUser.id,
            content,
            timestamp: new Date(),
            type,
        };
        this.currentSession.sharedContext.messages.push(message);
        // Trim old messages to prevent memory leaks
        this.trimMessages();
        return message;
    }
    /**
     * Trim old messages from shared context to prevent memory leaks.
     * Uses a sliding window approach, keeping the most recent messages.
     */
    trimMessages() {
        if (!this.currentSession)
            return;
        const messages = this.currentSession.sharedContext.messages;
        if (messages.length > MAX_SHARED_MESSAGES) {
            const trimCount = messages.length - MAX_SHARED_MESSAGES;
            this.currentSession.sharedContext.messages = messages.slice(trimCount);
        }
    }
    /**
     * Get current message count and limit for monitoring
     */
    getMessageStats() {
        if (!this.currentSession)
            return null;
        return {
            count: this.currentSession.sharedContext.messages.length,
            max: MAX_SHARED_MESSAGES,
        };
    }
    updateCursor(position) {
        if (!this.currentSession || !this.currentUser)
            return;
        this.currentUser.cursor = position;
        this.currentUser.lastActive = new Date();
    }
    lockFile(path, region) {
        if (!this.currentSession || !this.currentUser)
            return false;
        const file = this.currentSession.sharedContext.files.get(path);
        if (!file)
            return false;
        for (const lock of file.locks.values()) {
            if (lock.userId !== this.currentUser.id) {
                if (!region || !lock.region)
                    return false;
                if (region.start <= lock.region.end && region.end >= lock.region.start) {
                    return false;
                }
            }
        }
        file.locks.set(this.currentUser.id, {
            userId: this.currentUser.id,
            region,
            acquiredAt: new Date(),
            expiresAt: new Date(Date.now() + this.config.lockTimeout),
        });
        return true;
    }
    unlockFile(path) {
        if (!this.currentSession || !this.currentUser)
            return false;
        const file = this.currentSession.sharedContext.files.get(path);
        return file ? file.locks.delete(this.currentUser.id) : false;
    }
    updateFile(path, content) {
        if (!this.currentSession || !this.currentUser)
            return false;
        if (!this.currentSession.permissions.allowEditing)
            return false;
        let file = this.currentSession.sharedContext.files.get(path);
        if (!file) {
            file = {
                path,
                content: '',
                version: 0,
                lastModifiedBy: this.currentUser.id,
                lastModifiedAt: new Date(),
                locks: new Map(),
            };
            this.currentSession.sharedContext.files.set(path, file);
        }
        const lock = file.locks.get(this.currentUser.id);
        if (file.locks.size > 0 && !lock)
            return false;
        file.content = content;
        file.version++;
        file.lastModifiedBy = this.currentUser.id;
        file.lastModifiedAt = new Date();
        return true;
    }
    getCurrentSession() {
        return this.currentSession;
    }
    getCurrentUser() {
        return this.currentUser;
    }
    getUsers() {
        return this.currentSession ? Array.from(this.currentSession.users.values()) : [];
    }
    hasPermission(permission) {
        if (!this.currentSession || !this.currentUser)
            return false;
        if (this.currentUser.role === 'owner')
            return true;
        if (this.currentUser.role === 'viewer')
            return false;
        return !!this.currentSession.permissions[permission];
    }
    generateInviteLink() {
        if (!this.currentSession)
            throw new Error('Not currently in a collaborative session. Join or create a session first.');
        const inviteCode = crypto.randomBytes(16).toString('base64url');
        return 'codebuddy://join/' + this.currentSession.id + '?code=' + inviteCode;
    }
    generateId(prefix) {
        return prefix + '_' + crypto.randomBytes(8).toString('hex');
    }
    assignColor(index) {
        return USER_COLORS[index % USER_COLORS.length];
    }
    dispose() {
        this.leaveSession();
        this.sessions.clear();
        this.removeAllListeners();
    }
}
let collaborationInstance = null;
export function getCollaborationManager(config) {
    if (!collaborationInstance) {
        collaborationInstance = new CollaborativeSessionManager(config);
    }
    return collaborationInstance;
}
export function resetCollaborationManager() {
    if (collaborationInstance)
        collaborationInstance.dispose();
    collaborationInstance = null;
}
export default CollaborativeSessionManager;
//# sourceMappingURL=collaborative-mode.js.map