"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CdpTarget = void 0;
const chromium_bidi_js_1 = require("../../../protocol/chromium-bidi.js");
const Deferred_js_1 = require("../../../utils/Deferred.js");
const LogManager_js_1 = require("../log/LogManager.js");
class CdpTarget {
    #id;
    #cdpClient;
    #browserCdpClient;
    #eventManager;
    #preloadScriptStorage;
    #unblocked = new Deferred_js_1.Deferred();
    #acceptInsecureCerts;
    #networkDomainEnabled = false;
    #fetchDomainEnabled = false;
    static create(targetId, cdpClient, browserCdpClient, realmStorage, eventManager, preloadScriptStorage, networkStorage, acceptInsecureCerts, logger) {
        const cdpTarget = new CdpTarget(targetId, cdpClient, browserCdpClient, eventManager, preloadScriptStorage, acceptInsecureCerts);
        LogManager_js_1.LogManager.create(cdpTarget, realmStorage, eventManager, logger);
        cdpTarget.#setEventListeners();
        // No need to await.
        // Deferred will be resolved when the target is unblocked.
        void cdpTarget.#unblock();
        return cdpTarget;
    }
    constructor(targetId, cdpClient, browserCdpClient, eventManager, preloadScriptStorage, acceptInsecureCerts) {
        this.#id = targetId;
        this.#cdpClient = cdpClient;
        this.#eventManager = eventManager;
        this.#preloadScriptStorage = preloadScriptStorage;
        this.#browserCdpClient = browserCdpClient;
        this.#acceptInsecureCerts = acceptInsecureCerts;
    }
    /** Returns a deferred that resolves when the target is unblocked. */
    get unblocked() {
        return this.#unblocked;
    }
    get id() {
        return this.#id;
    }
    get cdpClient() {
        return this.#cdpClient;
    }
    get browserCdpClient() {
        return this.#browserCdpClient;
    }
    /** Needed for CDP escape path. */
    get cdpSessionId() {
        // SAFETY we got the client by it's id for creating
        return this.#cdpClient.sessionId;
    }
    /**
     * Enables all the required CDP domains and unblocks the target.
     */
    async #unblock() {
        // Check if the network domain is enabled globally.
        const enabledNetwork = this.#eventManager.subscriptionManager.isSubscribedToModule(chromium_bidi_js_1.BiDiModule.Network, this.#id);
        try {
            await Promise.all([
                this.#cdpClient.sendCommand('Runtime.enable'),
                this.#cdpClient.sendCommand('Page.enable'),
                this.#cdpClient.sendCommand('Page.setLifecycleEventsEnabled', {
                    enabled: true,
                }),
                // Set ignore certificate errors for each target.
                this.#cdpClient.sendCommand('Security.setIgnoreCertificateErrors', {
                    ignore: this.#acceptInsecureCerts,
                }),
                // TODO: enable Network domain for OOPiF targets.
                enabledNetwork
                    ? this.#cdpClient.sendCommand('Network.enable')
                    : undefined,
                this.#cdpClient.sendCommand('Target.setAutoAttach', {
                    autoAttach: true,
                    waitForDebuggerOnStart: true,
                    flatten: true,
                }),
                this.#initAndEvaluatePreloadScripts(),
                this.#cdpClient.sendCommand('Runtime.runIfWaitingForDebugger'),
            ]);
        }
        catch (error) {
            // The target might have been closed before the initialization finished.
            if (!this.#cdpClient.isCloseError(error)) {
                this.#unblocked.resolve({
                    kind: 'error',
                    error,
                });
                return;
            }
        }
        this.#unblocked.resolve({
            kind: 'success',
            value: undefined,
        });
    }
    async enableFetchIfNeeded(params) {
        if (!this.#networkDomainEnabled || this.#fetchDomainEnabled) {
            return;
        }
        this.#fetchDomainEnabled = true;
        try {
            await this.#cdpClient.sendCommand('Fetch.enable', params);
        }
        catch (err) {
            this.#fetchDomainEnabled = false;
        }
    }
    async disableFetchIfNeeded() {
        if (!this.#fetchDomainEnabled) {
            return;
        }
        this.#fetchDomainEnabled = false;
        try {
            await this.#cdpClient.sendCommand('Fetch.disable');
        }
        catch (err) {
            this.#fetchDomainEnabled = true;
        }
    }
    async toggleNetworkIfNeeded(enabled) {
        if (enabled === this.#networkDomainEnabled) {
            return;
        }
        this.#networkDomainEnabled = enabled;
        try {
            await this.#cdpClient.sendCommand(this.#networkDomainEnabled ? 'Network.enable' : 'Network.disable');
        }
        catch (err) {
            this.#networkDomainEnabled = !enabled;
        }
    }
    #setEventListeners() {
        this.#cdpClient.on('*', (event, params) => {
            // We may encounter uses for EventEmitter other than CDP events,
            // which we want to skip.
            if (typeof event !== 'string') {
                return;
            }
            this.#eventManager.registerEvent({
                type: 'event',
                method: `cdp.${event}`,
                params: {
                    event,
                    params,
                    session: this.cdpSessionId,
                },
            }, null);
        });
    }
    /**
     * All the ProxyChannels from all the preload scripts of the given
     * BrowsingContext.
     */
    getChannels() {
        return this.#preloadScriptStorage
            .find()
            .flatMap((script) => script.channels);
    }
    /** Loads all top-level preload scripts. */
    async #initAndEvaluatePreloadScripts() {
        for (const script of this.#preloadScriptStorage.find({
            global: true,
        })) {
            await script.initInTarget(this, true);
        }
    }
}
exports.CdpTarget = CdpTarget;
//# sourceMappingURL=CdpTarget.js.map