"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.launchDebugBrowser = launchDebugBrowser;
const child_process_1 = require("child_process");
const fs = __importStar(require("fs"));
const http = __importStar(require("http"));
const path = __importStar(require("path"));
const chromeFinder_1 = require("../browserEngines/chromeFinder");
function fetchJson(url) {
    return new Promise((resolve, reject) => {
        http
            .get(url, (res) => {
            let data = '';
            res.on('data', (chunk) => (data += chunk));
            res.on('end', () => {
                try {
                    resolve(JSON.parse(data));
                }
                catch (e) {
                    reject(e);
                }
            });
        })
            .on('error', reject);
    });
}
function waitForDebuggerPort(port, timeoutMs) {
    return new Promise((resolve, reject) => {
        const start = Date.now();
        function poll() {
            fetchJson(`http://127.0.0.1:${port}/json/version`)
                .then(() => resolve())
                .catch(() => {
                if (Date.now() - start > timeoutMs) {
                    reject(new Error(`Timed out waiting for Chrome remote debugger on port ${port}`));
                }
                else {
                    global.setTimeout(poll, 100);
                }
            });
        }
        poll();
    });
}
function waitForFile(filePath, timeoutMs) {
    return new Promise((resolve, reject) => {
        const start = Date.now();
        function poll() {
            if (fs.existsSync(filePath)) {
                resolve(fs.readFileSync(filePath, 'utf8').trim());
            }
            else if (Date.now() - start > timeoutMs) {
                reject(new Error(`Timed out waiting for Chrome to write ${filePath}`));
            }
            else {
                global.setTimeout(poll, 100);
            }
        }
        poll();
    });
}
function resolveChromePath() {
    const chromePath = (0, chromeFinder_1.searchForChrome)();
    if (!chromePath) {
        throw new Error('No stable Google Chrome installation was found on this system. ' +
            'Install Chrome and try again.');
    }
    return chromePath;
}
async function launchDebugBrowser(userDataDir, options = {}) {
    const timeoutMs = options.timeoutMs ?? 10_000;
    const requestedPort = options.remoteDebuggingPort ?? 0;
    const chromePath = resolveChromePath();
    fs.mkdirSync(userDataDir, { recursive: true });
    const chromeArgs = [
        `--remote-debugging-port=${requestedPort}`,
        `--user-data-dir=${userDataDir}`,
        '--no-first-run',
        '--no-default-browser-check',
        '--disable-extensions',
    ];
    if (options.headless) {
        chromeArgs.push('--headless=new');
    }
    chromeArgs.push('about:blank');
    const child = (0, child_process_1.spawn)(chromePath, chromeArgs, {
        detached: true,
        stdio: 'ignore',
    });
    if (!child.pid) {
        throw new Error('Failed to spawn Chrome process');
    }
    child.unref();
    let browserPort;
    if (requestedPort === 0) {
        const portFile = path.join(userDataDir, 'DevToolsActivePort');
        const portContent = await waitForFile(portFile, timeoutMs);
        const [portStr] = portContent.split('\n');
        browserPort = parseInt(portStr, 10);
    }
    else {
        browserPort = requestedPort;
        await waitForDebuggerPort(browserPort, timeoutMs);
    }
    const versionInfo = await fetchJson(`http://127.0.0.1:${browserPort}/json/version`);
    const wsEndpoint = versionInfo.webSocketDebuggerUrl ??
        `ws://127.0.0.1:${browserPort}/devtools/browser/unknown`;
    try {
        process.kill(child.pid, 0);
    }
    catch {
        throw new Error('Chrome exited immediately after launch — the remote debugging endpoint ' +
            'may have resolved to a stale Chrome on the same port. Try a different ' +
            '--port, kill any lingering Chrome process on that port, and retry.');
    }
    return {
        wsEndpoint,
        browserPort,
        browserPid: child.pid,
        userDataDir,
    };
}
