// cli/commands/watch.ts — planu watch command (SPEC-130)
import { parseArgs } from 'node:util';
import { resolve } from 'node:path';
import { green, cyan, dim, yellow, red } from '../colors.js';
export const watchCommand = {
    name: 'watch',
    description: 'Watch for file changes and run hook handlers',
    usage: 'planu watch [path] [--hooks on-save,on-create] [--verbose] [--dry-run]',
    async run(args) {
        const { values, positionals } = parseArgs({
            args,
            options: {
                hooks: { type: 'string', short: 'H' },
                verbose: { type: 'boolean', short: 'V' },
                'dry-run': { type: 'boolean' },
                help: { type: 'boolean', short: 'h' },
            },
            strict: false,
            allowPositionals: true,
        });
        if (values.help) {
            printWatchHelp();
            return;
        }
        const projectPath = resolve(positionals[0] ?? process.cwd());
        const hookTypes = values.hooks?.split(',').map((h) => h.trim()) ?? [
            'on-save',
            'on-create',
            'on-delete',
        ];
        const verbose = values.verbose ?? false;
        const dryRun = values['dry-run'] ?? false;
        process.stdout.write(`${green('Planu Watch')} — watching ${cyan(projectPath)}\n`);
        process.stdout.write(`${dim('Hooks:')} ${hookTypes.join(', ')}${dryRun ? ` ${yellow('[dry-run]')}` : ''}\n`);
        process.stdout.write(`${dim('Press Ctrl+C to stop.')}\n\n`);
        // Lazy-load engine components
        const { HookEngine } = await import('../../engine/hooks/hook-engine.js');
        const { EventBus } = await import('../../engine/hooks/event-bus.js');
        const { FileWatcher } = await import('../../engine/hooks/file-watcher.js');
        const { ConfigLoader } = await import('../../engine/hooks/config-loader.js');
        const { Debouncer } = await import('../../engine/hooks/debouncer.js');
        // Load config
        const configLoader = new ConfigLoader(projectPath);
        const config = await configLoader.load();
        // Create engine
        const eventBus = new EventBus();
        const engine = new HookEngine(eventBus);
        // Verbose logging via event bus
        if (verbose) {
            eventBus.onEvent('hook:start', (evt) => {
                const handler = evt.data.handler;
                const path = evt.data.path;
                process.stdout.write(`${dim(`[hook:start]`)} ${handler} → ${path}\n`);
            });
            eventBus.onEvent('hook:complete', (evt) => {
                const handler = evt.data.handler;
                const latency = evt.data.latencyMs;
                process.stdout.write(`${green('[hook:complete]')} ${handler} (${String(latency)}ms)\n`);
            });
            eventBus.onEvent('hook:error', (evt) => {
                const handler = evt.data.handler;
                const error = evt.data.error;
                process.stderr.write(`${red('[hook:error]')} ${handler}: ${error}\n`);
            });
        }
        // Create watcher and debouncer
        const watcher = new FileWatcher({
            rootDir: projectPath,
            include: config.hooks['on-save']?.include,
            exclude: config.hooks['on-save']?.exclude,
        });
        const debouncer = new Debouncer((event) => {
            const hookType = mapEventType(event.type);
            if (!hookType || !hookTypes.includes(hookType)) {
                return;
            }
            if (dryRun) {
                process.stdout.write(`${yellow('[dry-run]')} Would dispatch ${hookType} for ${event.path}\n`);
                return;
            }
            if (verbose) {
                process.stdout.write(`${dim('[dispatch]')} ${hookType} → ${event.path}\n`);
            }
            void engine.dispatch(event, hookType);
        }, {
            debounceMs: config.debounceMs,
            rateLimitPerFileMs: config.rateLimitPerFileMs,
        });
        // Wire watcher -> debouncer
        watcher.on('change', (event) => {
            eventBus.emitEvent('file:change', {
                path: event.path,
                type: event.type,
                timestamp: event.timestamp,
            });
            debouncer.push(event);
        });
        // Start
        engine.start();
        watcher.start();
        configLoader.startWatching();
        // SIGINT/SIGTERM graceful shutdown
        const cleanup = () => {
            process.stdout.write(`\n${dim('Stopping watch...')}\n`);
            engine.stop();
            watcher.close();
            debouncer.dispose();
            configLoader.close();
            process.stdout.write(`${green('Watch stopped.')}\n`);
            process.exit(0);
        };
        process.on('SIGINT', cleanup);
        process.on('SIGTERM', cleanup);
        // Keep process alive
        await new Promise(() => {
            // Never resolves — process runs until signal
        });
    },
};
// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------
function mapEventType(type) {
    switch (type) {
        case 'modify':
            return 'on-save';
        case 'create':
            return 'on-create';
        case 'delete':
            return 'on-delete';
        default:
            return null;
    }
}
function printWatchHelp() {
    const lines = [
        `${green('planu watch')} — Watch for file changes and run hook handlers`,
        '',
        `${cyan('Usage:')} planu watch [path] [options]`,
        '',
        cyan('Options:'),
        '  --hooks, -H    Comma-separated hook types (default: on-save,on-create,on-delete)',
        '  --verbose, -V  Show detailed hook execution logs',
        '  --dry-run      Preview which hooks would fire without executing',
        '  --help, -h     Show this help message',
        '',
        cyan('Examples:'),
        '  planu watch                    Watch current directory',
        '  planu watch /path/to/project   Watch specific directory',
        '  planu watch --hooks on-save    Only watch for file saves',
        '  planu watch --verbose          Show detailed execution logs',
        '  planu watch --dry-run          Preview without executing hooks',
    ];
    process.stdout.write(lines.join('\n') + '\n');
}
//# sourceMappingURL=watch.js.map