import { createRequire } from 'node:module';
import { Compiler } from '../compiler/index.js';
import { Server } from '../server/index.js';
import { compilerHandler } from '../utils/index.js';
import { existsSync } from 'node:fs';
import { createWatcher } from './create-watcher.js';
export class FileWatcher {
    constructor(serverOrCompiler, options, _logger) {
        this.serverOrCompiler = serverOrCompiler;
        this.options = options;
        this._logger = _logger;
        this._close = false;
        this._watchedFiles = new Set();
        this._root = options.root;
    }
    getInternalWatcher() {
        return this._watcher;
    }
    filterWatchFile(file, root) {
        return (!file.startsWith(root) &&
            !file.includes('node_modules/') &&
            !file.includes('\0') &&
            existsSync(file));
    }
    getExtraWatchedFiles() {
        const compiler = this.getCompilerFromServerOrCompiler(this.serverOrCompiler);
        return [
            ...compiler.resolvedModulePaths(this._root),
            ...compiler.resolvedWatchPaths()
        ].filter((file) => this.filterWatchFile(file, this._root));
    }
    watchExtraFiles() {
        const files = this.getExtraWatchedFiles();
        for (const file of files) {
            if (!this._watchedFiles.has(file)) {
                this._watcher.add(file);
                this._watchedFiles.add(file);
            }
        }
    }
    async watch() {
        // Determine how to compile the project
        const compiler = this.getCompilerFromServerOrCompiler(this.serverOrCompiler);
        const handlePathChange = async (path) => {
            if (this._close) {
                return;
            }
            try {
                if (this.serverOrCompiler instanceof Server) {
                    await this.serverOrCompiler.hmrEngine.hmrUpdate(path);
                }
                if (this.serverOrCompiler instanceof Compiler &&
                    this.serverOrCompiler.hasModule(path)) {
                    compilerHandler(async () => {
                        const result = await compiler.update([path], true);
                        handleUpdateFinish(result);
                        compiler.writeResourcesToDisk();
                    }, this.options, this._logger, { clear: true });
                }
            }
            catch (error) {
                this._logger.error(error);
            }
        };
        const watchedFiles = this.getExtraWatchedFiles();
        const files = [this.options.root, ...watchedFiles];
        this._watchedFiles = new Set(files);
        this._watcher = createWatcher(this.options, files);
        this._watcher.on('change', (path) => {
            if (this._close)
                return;
            handlePathChange(path);
        });
        const handleUpdateFinish = (updateResult) => {
            const added = [
                ...updateResult.added,
                ...updateResult.extraWatchResult.add
            ].map((addedModule) => {
                const resolvedPath = compiler.transformModulePath(this._root, addedModule);
                return resolvedPath;
            });
            const filteredAdded = added.filter((file) => this.filterWatchFile(file, this._root));
            if (filteredAdded.length > 0) {
                this._watcher.add(filteredAdded);
            }
        };
        if (this.serverOrCompiler instanceof Server) {
            this.serverOrCompiler.hmrEngine?.onUpdateFinish(handleUpdateFinish);
        }
    }
    getCompilerFromServerOrCompiler(serverOrCompiler) {
        return serverOrCompiler instanceof Server
            ? serverOrCompiler.getCompiler()
            : serverOrCompiler;
    }
    close() {
        this._close = true;
        this._watcher = null;
        this.serverOrCompiler = null;
    }
}
export function clearModuleCache(modulePath) {
    const _require = createRequire(import.meta.url);
    delete _require.cache[_require.resolve(modulePath)];
}
//# sourceMappingURL=index.js.map