import chokidar from 'chokidar';
import path from 'node:path';
export class PagesWatcher {
    pagesRoot;
    gateway;
    watcher = null;
    suppressUntil = new Map();
    SUPPRESS_WINDOW_MS = 350;
    callbacks = [];
    constructor(pagesRoot, gateway) {
        this.pagesRoot = pagesRoot;
        this.gateway = gateway;
    }
    onChange(cb) {
        this.callbacks.push(cb);
    }
    start() {
        this.watcher = chokidar.watch(this.pagesRoot, {
            ignoreInitial: true,
            ignored: (p) => /(^|\/|\\)\./.test(path.basename(p)),
            awaitWriteFinish: { stabilityThreshold: 80, pollInterval: 20 },
        });
        this.watcher.on('add', (p) => this.emit('add', p));
        this.watcher.on('change', (p) => this.emit('change', p));
        this.watcher.on('unlink', (p) => this.emit('unlink', p));
    }
    /** Call before a programmatic write so the resulting chokidar event is suppressed. */
    suppress(relPath) {
        this.suppressUntil.set(relPath, Date.now() + this.SUPPRESS_WINDOW_MS);
    }
    /**
     * Broadcast a server-origin change event for a programmatic write.
     * Clients receive `page:changed { origin: 'server' }` and should silently reload
     * without showing the "file changed externally" dialog.
     * Does NOT fire the callback chain (callbacks are for external-origin indexing).
     */
    emitServerWrite(relPath) {
        this.gateway.broadcast({ kind: 'page:changed', event: 'change', path: relPath, origin: 'server' });
    }
    emit(kind, absPath) {
        if (!absPath.endsWith('.md'))
            return;
        const relPath = path.relative(this.pagesRoot, absPath).replaceAll(path.sep, '/');
        const suppressedUntil = this.suppressUntil.get(relPath);
        if (suppressedUntil && Date.now() < suppressedUntil) {
            this.suppressUntil.delete(relPath);
            return;
        }
        this.gateway.broadcast({ kind: 'page:changed', event: kind, path: relPath, origin: 'external' });
        for (const cb of this.callbacks) {
            try {
                cb(relPath, kind);
            }
            catch (err) {
                console.error('[watcher] callback error:', err);
            }
        }
    }
    async close() {
        await this.watcher?.close();
        this.watcher = null;
    }
}
//# sourceMappingURL=watcher.js.map