"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.ContentJsWatcher = void 0;
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const child_process_1 = require("child_process");
const chalk = require('chalk');
class ContentJsWatcher {
    constructor(options) {
        this.isRebuilding = false;
        this.pendingRebuild = false;
        this.onRebuilt = options.onRebuilt;
        this.log = options.log;
    }
    start() {
        const runtimeDir = this.getRuntimeDir();
        const watchDir = path.join(runtimeDir, ContentJsWatcher.contentJsSrc);
        this.log(chalk.cyan('📁 Watching contentJs source files for changes...'));
        this.log(chalk.gray(`   ${watchDir}`));
        try {
            this.watcher = fs.watch(watchDir, { recursive: true }, (_eventType, filename) => {
                if (filename && this.shouldTriggerRebuild(filename)) {
                    this.scheduleRebuild(filename);
                }
            });
            this.watcher.on('error', (error) => {
                this.log(chalk.red('Watch error:'), error.message);
            });
        }
        catch (error) {
            this.log(chalk.red('Failed to start watcher:'), error);
        }
    }
    stop() {
        if (this.watcher) {
            this.watcher.close();
            this.watcher = undefined;
        }
        if (this.debounceTimer) {
            global.clearTimeout(this.debounceTimer);
            this.debounceTimer = undefined;
        }
    }
    shouldTriggerRebuild(filename) {
        return (filename.endsWith('.ts') &&
            !filename.includes('.spec.') &&
            !filename.includes('.test.'));
    }
    scheduleRebuild(filename) {
        if (this.debounceTimer) {
            global.clearTimeout(this.debounceTimer);
        }
        this.debounceTimer = global.setTimeout(() => {
            this.log(chalk.yellow(`\n🔄 Change detected: ${filename}`));
            void this.triggerRebuild();
        }, 300);
    }
    async triggerRebuild() {
        if (this.isRebuilding) {
            this.pendingRebuild = true;
            return;
        }
        this.isRebuilding = true;
        try {
            this.log(chalk.cyan('   Rebuilding contentJs...'));
            const success = await this.runWebpackBuild();
            if (success) {
                this.log(chalk.green('   ✓ Content script rebuilt'));
                this.clearContentScriptCache();
                this.log(chalk.cyan('   Reinjecting into browser...'));
                await this.onRebuilt();
                this.log(chalk.green('   ✓ Content script reinjected\n'));
            }
            else {
                this.log(chalk.red('   ✗ Build failed\n'));
            }
        }
        catch (error) {
            this.log(chalk.red('   ✗ Rebuild error:'), error);
        }
        finally {
            this.isRebuilding = false;
            if (this.pendingRebuild) {
                this.pendingRebuild = false;
                void this.triggerRebuild();
            }
        }
    }
    runWebpackBuild() {
        return new Promise((resolve) => {
            const runtimeDir = this.getRuntimeDir();
            const webpackBin = path.join(runtimeDir, '../node_modules/webpack/bin/webpack.js');
            const webpackConfig = path.join(runtimeDir, ContentJsWatcher.webpackConfig);
            const outputPath = path.join(runtimeDir, ContentJsWatcher.contentJsOutput);
            try {
                fs.unlinkSync(outputPath);
            }
            catch {
            }
            this.log(chalk.gray(`   Running: node ${webpackBin}`));
            this.log(chalk.gray(`   Config: ${webpackConfig}`));
            this.log(chalk.gray(`   CWD: ${runtimeDir}`));
            const child = (0, child_process_1.spawn)('node', [webpackBin, '--config', webpackConfig, '--mode', 'development'], {
                cwd: runtimeDir,
                stdio: ['ignore', 'pipe', 'pipe'],
            });
            let stdout = '';
            let stderr = '';
            child.stdout?.on('data', (data) => {
                stdout += data.toString();
            });
            child.stderr?.on('data', (data) => {
                stderr += data.toString();
            });
            child.on('close', (code) => {
                const outputExists = fs.existsSync(outputPath);
                const success = outputExists || code === 0;
                if (!success) {
                    this.log(chalk.red(`   Webpack exited with code ${code}`));
                    if (stdout.trim()) {
                        this.log(chalk.yellow('   Stdout:'));
                        stdout
                            .split('\n')
                            .slice(0, 20)
                            .forEach((line) => {
                            if (line.trim()) {
                                this.log(chalk.yellow(`     ${line}`));
                            }
                        });
                    }
                    if (stderr.trim()) {
                        this.log(chalk.red('   Stderr:'));
                        stderr
                            .split('\n')
                            .slice(0, 20)
                            .forEach((line) => {
                            if (line.trim()) {
                                this.log(chalk.red(`     ${line}`));
                            }
                        });
                    }
                }
                resolve(success);
            });
            child.on('error', (error) => {
                this.log(chalk.red('   Failed to run webpack:'), error.message);
                resolve(false);
            });
        });
    }
    clearContentScriptCache() {
        const { CliTrainingContext } = require('./CliTrainingContext');
        CliTrainingContext.clearContentScriptCache();
    }
    getRuntimeDir() {
        const currentDir = path.resolve(__dirname, '../..');
        if (currentDir.includes('mabl-cli-build')) {
            const workspaceRoot = path.resolve(currentDir, '../..');
            const runtimeSrcDir = path.join(workspaceRoot, 'runtime');
            this.log(chalk.gray(`   Build dir: ${currentDir}`));
            this.log(chalk.gray(`   Workspace root: ${workspaceRoot}`));
            this.log(chalk.gray(`   Runtime dir: ${runtimeSrcDir}`));
            if (fs.existsSync(path.join(runtimeSrcDir, 'src/trainer/contentJs'))) {
                return runtimeSrcDir;
            }
            this.log(chalk.red(`   Warning: Source directory not found at ${runtimeSrcDir}`));
        }
        return currentDir;
    }
}
exports.ContentJsWatcher = ContentJsWatcher;
ContentJsWatcher.contentJsSrc = 'src/trainer/contentJs';
ContentJsWatcher.contentJsOutput = 'src/resources/contentJs/content.js';
ContentJsWatcher.webpackConfig = 'webpack.contentJs.config.js';
