import {
	HttpsProxyAgent,
	type HttpsProxyAgentOptions,
} from "https-proxy-agent";
import {
	SocksProxyAgent,
	type SocksProxyAgentOptions,
} from "socks-proxy-agent";

export type ProxyConfig = {
	host: string;
	port: number;
	auth?: {
		username: string;
		password: string;
	};
	protocol:
		| "http"
		| "https"
		| "socks4"
		| "socks4a"
		| "socks5"
		| "socks5h"
		| "socks";
};

class ProxyProtocolError extends Error {}

const proxyAgent = (
	proxyConfig: ProxyConfig,
): HttpsProxyAgent | SocksProxyAgent => {
	switch (proxyConfig.protocol) {
		case "http": {
			let options: HttpsProxyAgentOptions = {
				host: proxyConfig.host,
				port: proxyConfig.port,
				secureProxy: false,
			};
			if (proxyConfig.auth) {
				options = Object.assign(options, {
					auth: `${proxyConfig.auth.username}:${proxyConfig.auth.password}`,
				});
			}
			const httpsAgent = new HttpsProxyAgent(options);
			return httpsAgent;
		}
		case "https": {
			let options: HttpsProxyAgentOptions = {
				host: proxyConfig.host,
				port: proxyConfig.port,
				secureProxy: true,
			};
			if (proxyConfig.auth) {
				options = Object.assign(options, {
					auth: `${proxyConfig.auth.username}:${proxyConfig.auth.password}`,
				});
			}
			const httpsAgent = new HttpsProxyAgent(options);
			return httpsAgent;
		}
		case "socks4":
		case "socks4a": {
			let options: SocksProxyAgentOptions = {
				type: 4,
				hostname: proxyConfig.host,
				port: proxyConfig.port,
			};
			if (proxyConfig.auth) {
				options = Object.assign(options, {
					userId: proxyConfig.auth.username,
					password: proxyConfig.auth.password,
				});
			}
			const socksAgent = new SocksProxyAgent(options);
			return socksAgent;
		}
		case "socks5":
		case "socks5h":
		case "socks": {
			let options: SocksProxyAgentOptions = {
				type: 5,
				hostname: proxyConfig.host,
				port: proxyConfig.port,
			};
			if (proxyConfig.auth) {
				options = Object.assign(options, {
					userId: proxyConfig.auth.username,
					password: proxyConfig.auth.password,
				});
			}
			const socksAgent = new SocksProxyAgent(options);
			return socksAgent;
		}
		default:
			throw new ProxyProtocolError("protocol is not accepted");
	}
};
export default proxyAgent;
