import { createServer } from '@pondwader/socks5-server';
import { logForDebugging } from '../utils/debug.js';
export function createSocksProxyServer(options) {
    const socksServer = createServer();
    socksServer.setRulesetValidator(async (conn) => {
        try {
            const hostname = conn.destAddress;
            const port = conn.destPort;
            logForDebugging(`Connection request to ${hostname}:${port}`);
            const allowed = await options.filter(port, hostname);
            if (!allowed) {
                logForDebugging(`Connection blocked to ${hostname}:${port}`, {
                    level: 'error',
                });
                return false;
            }
            logForDebugging(`Connection allowed to ${hostname}:${port}`);
            return true;
        }
        catch (error) {
            logForDebugging(`Error validating connection: ${error}`, {
                level: 'error',
            });
            return false;
        }
    });
    return {
        server: socksServer,
        getPort() {
            // Access the internal server to get the port
            // We need to use type assertion here as the server property is private
            try {
                const serverInternal = socksServer?.server;
                if (serverInternal && typeof serverInternal?.address === 'function') {
                    const address = serverInternal.address();
                    if (address && typeof address === 'object' && 'port' in address) {
                        return address.port;
                    }
                }
            }
            catch (error) {
                // Server might not be listening yet or property access failed
                logForDebugging(`Error getting port: ${error}`, { level: 'error' });
            }
            return undefined;
        },
        listen(port, hostname) {
            return new Promise((resolve, reject) => {
                const listeningCallback = () => {
                    const actualPort = this.getPort();
                    if (actualPort) {
                        logForDebugging(`SOCKS proxy listening on ${hostname}:${actualPort}`);
                        resolve(actualPort);
                    }
                    else {
                        reject(new Error('Failed to get SOCKS proxy server port'));
                    }
                };
                socksServer.listen(port, hostname, listeningCallback);
            });
        },
        async close() {
            return new Promise((resolve, reject) => {
                socksServer.close(error => {
                    if (error) {
                        // Only reject for actual errors, not for "already closed" states
                        // Check for common "already closed" error patterns
                        const errorMessage = error.message?.toLowerCase() || '';
                        const isAlreadyClosed = errorMessage.includes('not running') ||
                            errorMessage.includes('already closed') ||
                            errorMessage.includes('not listening');
                        if (!isAlreadyClosed) {
                            reject(error);
                            return;
                        }
                    }
                    resolve();
                });
            });
        },
        unref() {
            // Access the internal server to call unref
            try {
                const serverInternal = socksServer?.server;
                if (serverInternal && typeof serverInternal?.unref === 'function') {
                    serverInternal.unref();
                }
            }
            catch (error) {
                logForDebugging(`Error calling unref: ${error}`, { level: 'error' });
            }
        },
    };
}