"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createProxyAwareFetch = createProxyAwareFetch;
exports.installProxyFetch = installProxyFetch;
const node_module_1 = require("node:module");
let cachedProxyAgent;
let installed = false;
const localRequire = (0, node_module_1.createRequire)(__filename);
function attemptRequire(moduleId) {
    try {
        return localRequire(moduleId);
    }
    catch {
        return null;
    }
}
function resolveProxyAgent() {
    if (cachedProxyAgent !== undefined) {
        return cachedProxyAgent;
    }
    const candidates = [
        () => attemptRequire('undici')?.ProxyAgent ?? null,
        () => attemptRequire('node:undici')?.ProxyAgent ?? null,
        () => attemptRequire('internal/deps/undici/undici')?.ProxyAgent ?? null,
    ];
    for (const load of candidates) {
        const ctor = load();
        if (ctor) {
            cachedProxyAgent = ctor;
            return ctor;
        }
    }
    cachedProxyAgent = null;
    return null;
}
function firstDefined(keys) {
    for (const key of keys) {
        const value = process.env[key];
        if (typeof value === 'string' && value.trim().length > 0) {
            return value.trim();
        }
    }
    return undefined;
}
function normalizeHost(value) {
    let normalized = value.trim().toLowerCase();
    if (normalized.startsWith('[') && normalized.endsWith(']')) {
        normalized = normalized.slice(1, -1);
    }
    return normalized;
}
function splitHostPort(rule) {
    if (rule.startsWith('[')) {
        const closing = rule.indexOf(']');
        if (closing !== -1) {
            const host = rule.slice(1, closing);
            const remainder = rule.slice(closing + 1);
            if (remainder.startsWith(':')) {
                return { host, port: remainder.slice(1) };
            }
            return { host };
        }
    }
    const firstColon = rule.indexOf(':');
    const lastColon = rule.lastIndexOf(':');
    if (firstColon !== -1 && firstColon === lastColon) {
        return { host: rule.slice(0, firstColon), port: rule.slice(firstColon + 1) };
    }
    return { host: rule };
}
function matchesNoProxyRule(host, port, rule) {
    if (!rule) {
        return false;
    }
    if (rule === '*') {
        return true;
    }
    const { host: ruleHostRaw, port: rulePortRaw } = splitHostPort(rule);
    const rulePort = rulePortRaw?.trim();
    const ruleHost = ruleHostRaw.trim();
    if (rulePort && rulePort !== port) {
        return false;
    }
    if (!ruleHost) {
        return true;
    }
    const normalizedRuleHost = normalizeHost(ruleHost);
    if (!normalizedRuleHost) {
        return true;
    }
    if (normalizedRuleHost === host) {
        return true;
    }
    if (normalizedRuleHost.startsWith('.')) {
        const suffix = normalizedRuleHost.slice(1);
        return host === suffix || host.endsWith(`.${suffix}`);
    }
    if (normalizedRuleHost.startsWith('*')) {
        const suffix = normalizedRuleHost.replace(/^\*+/, '');
        if (!suffix) {
            return true;
        }
        const normalizedSuffix = suffix.startsWith('.') ? suffix.slice(1) : suffix;
        return host === normalizedSuffix || host.endsWith(`.${normalizedSuffix}`);
    }
    return host === normalizedRuleHost || host.endsWith(`.${normalizedRuleHost}`);
}
function isNoProxyMatch(target) {
    const raw = firstDefined(['NO_PROXY', 'no_proxy']);
    if (!raw) {
        return false;
    }
    const host = normalizeHost(target.hostname);
    const port = target.port || (target.protocol === 'https:' ? '443' : target.protocol === 'http:' ? '80' : '');
    const rules = raw.split(',').map((entry) => entry.trim().toLowerCase()).filter(Boolean);
    return rules.some((rule) => matchesNoProxyRule(host, port, rule));
}
function resolveProxyUrl(target) {
    const protocol = target.protocol;
    let proxy;
    if (protocol === 'http:') {
        proxy = firstDefined(['HTTP_PROXY', 'http_proxy', 'ALL_PROXY', 'all_proxy']);
    }
    else if (protocol === 'https:') {
        proxy = firstDefined(['HTTPS_PROXY', 'https_proxy', 'HTTP_PROXY', 'http_proxy', 'ALL_PROXY', 'all_proxy']);
    }
    else {
        proxy = firstDefined(['ALL_PROXY', 'all_proxy']);
    }
    if (!proxy) {
        return null;
    }
    if (isNoProxyMatch(target)) {
        return null;
    }
    return proxy;
}
function determineProxyForRequest(input) {
    if (typeof input === 'string') {
        if (!/^https?:/i.test(input)) {
            return null;
        }
        try {
            const absolute = new URL(input);
            return resolveProxyUrl(absolute);
        }
        catch {
            return null;
        }
    }
    if (input instanceof URL) {
        return resolveProxyUrl(input);
    }
    if (typeof Request !== 'undefined' && input instanceof Request) {
        try {
            const absolute = new URL(input.url);
            return resolveProxyUrl(absolute);
        }
        catch {
            return null;
        }
    }
    return null;
}
function createProxyAwareFetch(fetchImpl, ProxyAgent) {
    if (typeof fetchImpl !== 'function') {
        return fetchImpl;
    }
    const agentCache = new Map();
    return async (input, init = {}) => {
        const existingDispatcher = init?.dispatcher;
        if (existingDispatcher) {
            return fetchImpl(input, init);
        }
        const proxyUrl = determineProxyForRequest(input);
        if (!proxyUrl) {
            return fetchImpl(input, init);
        }
        let dispatcher = agentCache.get(proxyUrl);
        if (!dispatcher) {
            dispatcher = new ProxyAgent(proxyUrl);
            agentCache.set(proxyUrl, dispatcher);
        }
        const nextInit = {
            ...(init || {}),
            dispatcher,
        };
        return fetchImpl(input, nextInit);
    };
}
function installProxyFetch() {
    if (installed) {
        return;
    }
    installed = true;
    if (typeof globalThis.fetch !== 'function') {
        return;
    }
    const ProxyAgent = resolveProxyAgent();
    if (!ProxyAgent) {
        return;
    }
    globalThis.fetch = createProxyAwareFetch(globalThis.fetch, ProxyAgent);
}
