import { EventEmitter } from 'events';
import { watch } from 'fs';
import { stat } from 'fs/promises';
import * as path from 'path';
export class FileWatchManager extends EventEmitter {
    constructor(logger) {
        super();
        this.watchedFiles = new Map();
        this.socketIoInstance = null;
        this.logger = logger;
    }
    async watchFile(socket, filePath) {
        try {
            const normalizedPath = path.normalize(filePath);
            const stats = await stat(normalizedPath);
            if (!stats.isFile()) {
                this.logger.warn(`路径不是文件: ${normalizedPath}`);
                return false;
            }
            const currentModified = stats.mtimeMs;
            if (this.watchedFiles.has(normalizedPath)) {
                const watchedFile = this.watchedFiles.get(normalizedPath);
                watchedFile.socketIds.add(socket.id);
                this.logger.info(`Socket ${socket.id} 加入监视文件: ${normalizedPath}`);
                return true;
            }
            const watcher = watch(normalizedPath, { persistent: false }, async (eventType, filename) => {
                if (eventType === 'change') {
                    try {
                        const newStats = await stat(normalizedPath);
                        const watchedFile = this.watchedFiles.get(normalizedPath);
                        if (watchedFile && newStats.mtimeMs > watchedFile.lastModified) {
                            if (watchedFile.ignoreNextChange) {
                                this.logger.info(`忽略文件变化（保存操作）: ${normalizedPath}`);
                                watchedFile.lastModified = newStats.mtimeMs;
                                watchedFile.ignoreNextChange = false;
                                return;
                            }
                            watchedFile.lastModified = newStats.mtimeMs;
                            this.logger.info(`检测到文件变化: ${normalizedPath}`);
                            watchedFile.socketIds.forEach(socketId => {
                                const targetSocket = this.findSocket(socketId);
                                if (targetSocket) {
                                    targetSocket.emit('file-changed', {
                                        filePath: normalizedPath,
                                        modifiedTime: newStats.mtimeMs
                                    });
                                }
                            });
                        }
                    }
                    catch (error) {
                        this.logger.error(`检查文件状态失败: ${normalizedPath}`, error);
                    }
                }
            });
            watcher.on('error', (error) => {
                this.logger.error(`文件监视器错误: ${normalizedPath}`, error);
                this.unwatchFile(socket, normalizedPath);
            });
            this.watchedFiles.set(normalizedPath, {
                filePath: normalizedPath,
                watcher,
                lastModified: currentModified,
                socketIds: new Set([socket.id]),
                ignoreNextChange: false
            });
            this.logger.info(`开始监视文件: ${normalizedPath}`);
            return true;
        }
        catch (error) {
            this.logger.error(`监视文件失败: ${filePath}`, error);
            return false;
        }
    }
    unwatchFile(socket, filePath) {
        const normalizedPath = path.normalize(filePath);
        const watchedFile = this.watchedFiles.get(normalizedPath);
        if (!watchedFile) {
            return;
        }
        watchedFile.socketIds.delete(socket.id);
        if (watchedFile.socketIds.size === 0) {
            watchedFile.watcher.close();
            this.watchedFiles.delete(normalizedPath);
            this.logger.info(`停止监视文件: ${normalizedPath}`);
        }
        else {
            this.logger.info(`Socket ${socket.id} 取消监视文件: ${normalizedPath}`);
        }
    }
    unwatchAllFilesForSocket(socket) {
        const filesToUnwatch = [];
        this.watchedFiles.forEach((watchedFile, filePath) => {
            if (watchedFile.socketIds.has(socket.id)) {
                filesToUnwatch.push(filePath);
            }
        });
        filesToUnwatch.forEach(filePath => {
            this.unwatchFile(socket, filePath);
        });
        if (filesToUnwatch.length > 0) {
            this.logger.info(`Socket ${socket.id} 断开连接，取消监视 ${filesToUnwatch.length} 个文件`);
        }
    }
    getWatchStats() {
        const files = Array.from(this.watchedFiles.entries()).map(([path, info]) => ({
            path,
            watcherCount: info.socketIds.size
        }));
        return {
            totalFiles: this.watchedFiles.size,
            files
        };
    }
    ignoreNextChange(filePath) {
        const normalizedPath = path.normalize(filePath);
        const watchedFile = this.watchedFiles.get(normalizedPath);
        if (watchedFile) {
            watchedFile.ignoreNextChange = true;
            this.logger.info(`设置忽略下一次变化: ${normalizedPath}`);
        }
    }
    setSocketIO(io) {
        this.socketIoInstance = io;
    }
    findSocket(socketId) {
        if (!this.socketIoInstance) {
            return null;
        }
        return this.socketIoInstance.sockets.sockets.get(socketId) || null;
    }
    cleanup() {
        this.watchedFiles.forEach(watchedFile => {
            watchedFile.watcher.close();
        });
        this.watchedFiles.clear();
        this.logger.info('所有文件监视器已清理');
    }
}
