"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createAgent = createAgent;
exports.useOrCreateAgent = useOrCreateAgent;
exports.isExistingAgentInstance = isExistingAgentInstance;
const proxy_agent_1 = require("./proxy-agent");
const proxy_options_1 = require("./proxy-options");
const http_1 = require("http");
const ssh_1 = require("./ssh");
const events_1 = require("events");
const agent_base_1 = require("agent-base");
const system_ca_1 = require("./system-ca");
class DevtoolsProxyAgent extends proxy_agent_1.ProxyAgent {
    proxyOptions;
    logger;
    sshAgent;
    _req;
    _reqLock;
    _reqLockResolve;
    constructor(proxyOptions, logger) {
        super({
            ...proxyOptions,
            getProxyForUrl: (url) => this._getProxyForUrl(url),
        });
        this.logger = logger;
        this.proxyOptions = proxyOptions;
        if (proxyOptions.proxy && new URL(proxyOptions.proxy).protocol === 'ssh:') {
            this.sshAgent = new ssh_1.SSHAgent(proxyOptions, logger);
        }
    }
    _getProxyForUrl = (url) => {
        if (!this._reqLockResolve || !this._req) {
            throw new Error('getProxyForUrl() called without pending request');
        }
        this._reqLockResolve();
        const req = this._req;
        this._req = undefined;
        this._reqLock = undefined;
        this._reqLockResolve = undefined;
        return (0, proxy_options_1.proxyForUrl)(this.proxyOptions, url, req);
    };
    async initialize() {
        await this.sshAgent?.initialize();
    }
    async connect(req, opts) {
        opts.ca = (0, system_ca_1.mergeCA)(this.proxyOptions.ca, opts.ca);
        if (this.sshAgent)
            return this.sshAgent;
        while (this._reqLock) {
            await this._reqLock;
        }
        this._req = req;
        this._reqLock = new Promise((resolve) => (this._reqLockResolve = resolve));
        this.logger.emit('proxy:connect', { agent: this, req, opts });
        const agent = await super.connect(req, opts);
        if ('addRequest' in agent && typeof agent.addRequest === 'function') {
            const dummyHttpAgent = Object.assign(new http_1.Agent(), {
                addRequest() {
                },
            });
            agent.addRequest(req, opts);
            return dummyHttpAgent;
        }
        return agent;
    }
    destroy() {
        this.sshAgent?.destroy();
        super.destroy();
    }
}
class DevtoolsProxyAgentWithSystemCA extends agent_base_1.Agent {
    proxyOptions;
    logger = new events_1.EventEmitter();
    agent;
    constructor(proxyOptions) {
        super();
        this.proxyOptions = proxyOptions;
        this.agent = (async () => {
            const { ca } = await (0, system_ca_1.systemCA)({
                ca: proxyOptions.ca,
                excludeSystemCerts: proxyOptions.caExcludeSystemCerts,
            });
            return new DevtoolsProxyAgent({ ...proxyOptions, ca, allowPartialTrustChain: true }, this.logger);
        })();
        this.agent.catch(() => {
        });
    }
    async initialize() {
        const agent = await this.agent;
        await agent.initialize?.();
    }
    async connect() {
        return await this.agent;
    }
    async destroy() {
        (await this.agent).destroy();
    }
}
function createAgent(proxyOptions) {
    return new DevtoolsProxyAgentWithSystemCA(proxyOptions);
}
function useOrCreateAgent(proxyOptions, target, useTargetRegardlessOfExistingAgent = false) {
    if (isExistingAgentInstance(proxyOptions)) {
        const agent = proxyOptions;
        if (useTargetRegardlessOfExistingAgent &&
            target !== undefined &&
            agent.proxyOptions &&
            !(0, proxy_options_1.proxyForUrl)(agent.proxyOptions, target)) {
            return undefined;
        }
        return agent;
    }
    else {
        if (target !== undefined && !(0, proxy_options_1.proxyForUrl)(proxyOptions, target)) {
            return undefined;
        }
        return createAgent(proxyOptions);
    }
}
function isExistingAgentInstance(options) {
    return 'createConnection' in options;
}
//# sourceMappingURL=agent.js.map