"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Browser = void 0;
const events_1 = require("events");
const node_fetch_1 = __importDefault(require("node-fetch"));
const exception_js_1 = require("../exception.js");
const logger_js_1 = require("../logger.js");
const connection_js_1 = require("./connection.js");
const interceptor_js_1 = require("./interceptor.js");
class Browser extends events_1.EventEmitter {
    constructor(config = {}) {
        super();
        this.interceptors = [];
        this.targetInitFns = [];
        this.config = {
            chromeAddress: '127.0.0.1',
            chromePort: 9222,
            cdpTimeout: 60000,
            navigationTimeout: 30000,
            stableBoxTimeout: 5000,
            suspendTargets: true,
            toolkitBinding: 'Autopilot',
            logger: new logger_js_1.ConsoleLogger(),
            ...config,
        };
        this.connection = new connection_js_1.Connection(this);
    }
    get logger() {
        return this.config.logger;
    }
    applyConfig(config) {
        Object.assign(this.config, config);
    }
    async connect() {
        if (this.connection.isConnected()) {
            return;
        }
        const version = await this.getVersion();
        await this.connection.connect(version.webSocketDebuggerUrl);
        await this.send('Target.setAutoAttach', {
            autoAttach: true,
            waitForDebuggerOnStart: this.config.suspendTargets,
            flatten: true,
        });
        await this.send('Target.setDiscoverTargets', { discover: true });
    }
    async close() {
        await this.send('Browser.close');
    }
    disconnect() {
        this.connection.disconnect();
    }
    isConnected() {
        return this.connection.isConnected();
    }
    async newTab(browserContextId) {
        const { targetId } = await this.send('Target.createTarget', {
            url: 'about:blank',
            browserContextId,
        });
        const page = await this.getPage(targetId);
        if (!page) {
            throw new exception_js_1.Exception({
                name: 'NewTabFailed',
                message: 'Create new tab failed',
            });
        }
        return page;
    }
    closeAllTabs() {
        for (const target of this.attachedTargets()) {
            if (target.type === 'page') {
                target.close();
            }
        }
    }
    getTarget(targetId) {
        return this.connection.findTargetById(targetId);
    }
    async getPage(targetId) {
        const target = this.connection.findTargetById(targetId);
        return target ? await target.getPage() : null;
    }
    attachedTargets() {
        return this.connection.attachedTargets();
    }
    *attachedPages() {
        for (const target of this.attachedTargets()) {
            if (target.attachedPage) {
                yield target.attachedPage;
            }
        }
    }
    async resolveFrameById(frameId) {
        const target = this.connection.findTargetById(frameId);
        if (target) {
            const page = await target.getPage();
            return page.mainFrame();
        }
        for (const page of this.attachedPages()) {
            const frame = page.frameManager.getFrameById(frameId);
            if (frame) {
                return frame;
            }
        }
        return null;
    }
    async send(method, params) {
        return await this.connection.send({ method, params });
    }
    sendAndForget(method, params) {
        this.connection.sendAndForget({
            method,
            params,
        });
    }
    async http(pathname, readJson = true) {
        const port = this.config.chromePort;
        const url = `http://${this.config.chromeAddress}:${port}${pathname}`;
        const res = await (0, node_fetch_1.default)(url);
        return readJson ? await res.json() : await res.text();
    }
    async getVersion() {
        const res = await this.http('/json/version');
        return {
            browserVersion: res['Browser'],
            protocolVersion: res['Protocol-Version'],
            userAgent: res['User-Agent'],
            v8Version: res['V8-Version'],
            webkitVersion: res['WebKit-Version'],
            webSocketDebuggerUrl: res['webSocketDebuggerUrl'],
        };
    }
    async createBrowserContext() {
        const { browserContextId } = await this.send('Target.createBrowserContext');
        return { browserContextId };
    }
    async disposeBrowserContext(browserContextId) {
        await this.send('Target.disposeBrowserContext', { browserContextId });
    }
    interceptRequests(handler, label = '') {
        const interceptor = new interceptor_js_1.Interceptor(this, handler, label);
        this.interceptors.push(interceptor);
        return interceptor;
    }
    clearInterceptors(label = '') {
        this.interceptors = label ? this.interceptors.filter(_ => _.label !== label) : [];
    }
    addTargetInit(fn) {
        this.targetInitFns.push(fn);
    }
}
exports.Browser = Browser;
//# sourceMappingURL=browser.js.map