import * as plugins from './plugins.js';
import { ProxyRouter } from './classes.router.js';
import * as fs from 'fs';
import * as path from 'path';
import { fileURLToPath } from 'url';

export interface INetworkProxyOptions {
  port: number;
  maxConnections?: number;
  keepAliveTimeout?: number;
  headersTimeout?: number;
  logLevel?: 'error' | 'warn' | 'info' | 'debug';
  cors?: {
    allowOrigin?: string;
    allowMethods?: string;
    allowHeaders?: string;
    maxAge?: number;
  };
}

interface IWebSocketWithHeartbeat extends plugins.wsDefault {
  lastPong: number;
  isAlive: boolean;
}

export class NetworkProxy {
  // Configuration
  public options: INetworkProxyOptions;
  public proxyConfigs: plugins.tsclass.network.IReverseProxyConfig[] = [];
  public defaultHeaders: { [key: string]: string } = {};
  
  // Server instances
  public httpsServer: plugins.https.Server;
  public wsServer: plugins.ws.WebSocketServer;
  
  // State tracking
  public router = new ProxyRouter();
  public socketMap = new plugins.lik.ObjectMap<plugins.net.Socket>();
  public activeContexts: Set<string> = new Set();
  public connectedClients: number = 0;
  public startTime: number = 0;
  public requestsServed: number = 0;
  public failedRequests: number = 0;
  
  // Timers and intervals
  private heartbeatInterval: NodeJS.Timeout;
  private metricsInterval: NodeJS.Timeout;
  
  // Certificates
  private defaultCertificates: { key: string; cert: string };
  private certificateCache: Map<string, { key: string; cert: string; expires?: Date }> = new Map();

  /**
   * Creates a new NetworkProxy instance
   */
  constructor(optionsArg: INetworkProxyOptions) {
    // Set default options
    this.options = {
      port: optionsArg.port,
      maxConnections: optionsArg.maxConnections || 10000,
      keepAliveTimeout: optionsArg.keepAliveTimeout || 120000, // 2 minutes 
      headersTimeout: optionsArg.headersTimeout || 60000, // 1 minute
      logLevel: optionsArg.logLevel || 'info',
      cors: optionsArg.cors || {
        allowOrigin: '*',
        allowMethods: 'GET, POST, PUT, DELETE, OPTIONS',
        allowHeaders: 'Content-Type, Authorization',
        maxAge: 86400
      }
    };
    
    this.loadDefaultCertificates();
  }

  /**
   * Loads default certificates from the filesystem
   */
  private loadDefaultCertificates(): void {
    const __dirname = path.dirname(fileURLToPath(import.meta.url));
    const certPath = path.join(__dirname, '..', 'assets', 'certs');
    
    try {
      this.defaultCertificates = {
        key: fs.readFileSync(path.join(certPath, 'key.pem'), 'utf8'),
        cert: fs.readFileSync(path.join(certPath, 'cert.pem'), 'utf8')
      };
      this.log('info', 'Default certificates loaded successfully');
    } catch (error) {
      this.log('error', 'Error loading default certificates', error);
      
      // Generate self-signed fallback certificates
      try {
        // This is a placeholder for actual certificate generation code
        // In a real implementation, you would use a library like selfsigned to generate certs
        this.defaultCertificates = {
          key: "FALLBACK_KEY_CONTENT",
          cert: "FALLBACK_CERT_CONTENT"
        };
        this.log('warn', 'Using fallback self-signed certificates');
      } catch (fallbackError) {
        this.log('error', 'Failed to generate fallback certificates', fallbackError);
        throw new Error('Could not load or generate SSL certificates');
      }
    }
  }

  /**
   * Starts the proxy server
   */
  public async start(): Promise<void> {
    this.startTime = Date.now();
    
    // Create the HTTPS server
    this.httpsServer = plugins.https.createServer(
      {
        key: this.defaultCertificates.key,
        cert: this.defaultCertificates.cert
      },
      (req, res) => this.handleRequest(req, res)
    );

    // Configure server timeouts
    this.httpsServer.keepAliveTimeout = this.options.keepAliveTimeout;
    this.httpsServer.headersTimeout = this.options.headersTimeout;
    
    // Setup connection tracking
    this.setupConnectionTracking();
    
    // Setup WebSocket support
    this.setupWebsocketSupport();
    
    // Start metrics collection
    this.setupMetricsCollection();

    // Start the server
    return new Promise((resolve) => {
      this.httpsServer.listen(this.options.port, () => {
        this.log('info', `NetworkProxy started on port ${this.options.port}`);
        resolve();
      });
    });
  }

  /**
   * Sets up tracking of TCP connections
   */
  private setupConnectionTracking(): void {
    this.httpsServer.on('connection', (connection: plugins.net.Socket) => {
      // Check if max connections reached
      if (this.socketMap.getArray().length >= this.options.maxConnections) {
        this.log('warn', `Max connections (${this.options.maxConnections}) reached, rejecting new connection`);
        connection.destroy();
        return;
      }

      // Add connection to tracking
      this.socketMap.add(connection);
      this.connectedClients = this.socketMap.getArray().length;
      this.log('debug', `New connection. Currently ${this.connectedClients} active connections`);
      
      // Setup connection cleanup handlers
      const cleanupConnection = () => {
        if (this.socketMap.checkForObject(connection)) {
          this.socketMap.remove(connection);
          this.connectedClients = this.socketMap.getArray().length;
          this.log('debug', `Connection closed. ${this.connectedClients} connections remaining`);
        }
      };
      
      connection.on('close', cleanupConnection);
      connection.on('error', (err) => {
        this.log('debug', 'Connection error', err);
        cleanupConnection();
      });
      connection.on('end', cleanupConnection);
      connection.on('timeout', () => {
        this.log('debug', 'Connection timeout');
        cleanupConnection();
      });
    });
  }

  /**
   * Sets up WebSocket support
   */
  private setupWebsocketSupport(): void {
    // Create WebSocket server
    this.wsServer = new plugins.ws.WebSocketServer({ 
      server: this.httpsServer,
      // Add WebSocket specific timeout
      clientTracking: true
    });

    // Handle WebSocket connections
    this.wsServer.on('connection', (wsIncoming: IWebSocketWithHeartbeat, reqArg: plugins.http.IncomingMessage) => {
      this.handleWebSocketConnection(wsIncoming, reqArg);
    });

    // Set up the heartbeat interval (check every 30 seconds, terminate after 2 minutes of inactivity)
    this.heartbeatInterval = setInterval(() => {
      if (this.wsServer.clients.size === 0) {
        return; // Skip if no active connections
      }
      
      this.log('debug', `WebSocket heartbeat check for ${this.wsServer.clients.size} clients`);
      this.wsServer.clients.forEach((ws: plugins.wsDefault) => {
        const wsWithHeartbeat = ws as IWebSocketWithHeartbeat;
        
        if (wsWithHeartbeat.isAlive === false) {
          this.log('debug', 'Terminating inactive WebSocket connection');
          return wsWithHeartbeat.terminate();
        }
        
        wsWithHeartbeat.isAlive = false;
        wsWithHeartbeat.ping();
      });
    }, 30000);
  }

  /**
   * Sets up metrics collection 
   */
  private setupMetricsCollection(): void {
    this.metricsInterval = setInterval(() => {
      const uptime = Math.floor((Date.now() - this.startTime) / 1000);
      const metrics = {
        uptime,
        activeConnections: this.connectedClients,
        totalRequests: this.requestsServed,
        failedRequests: this.failedRequests,
        activeWebSockets: this.wsServer?.clients.size || 0,
        memoryUsage: process.memoryUsage(),
        activeContexts: Array.from(this.activeContexts)
      };
      
      this.log('debug', 'Proxy metrics', metrics);
    }, 60000); // Log metrics every minute
  }

  /**
   * Handles an incoming WebSocket connection
   */
  private handleWebSocketConnection(wsIncoming: IWebSocketWithHeartbeat, reqArg: plugins.http.IncomingMessage): void {
    const wsPath = reqArg.url;
    const wsHost = reqArg.headers.host;
    
    this.log('info', `WebSocket connection for ${wsHost}${wsPath}`);
    
    // Setup heartbeat tracking
    wsIncoming.isAlive = true;
    wsIncoming.lastPong = Date.now();
    wsIncoming.on('pong', () => {
      wsIncoming.isAlive = true;
      wsIncoming.lastPong = Date.now();
    });

    // Get the destination configuration
    const wsDestinationConfig = this.router.routeReq(reqArg);
    if (!wsDestinationConfig) {
      this.log('warn', `No route found for WebSocket ${wsHost}${wsPath}`);
      wsIncoming.terminate();
      return;
    }

    // Check authentication if required
    if (wsDestinationConfig.authentication) {
      try {
        if (!this.authenticateRequest(reqArg, wsDestinationConfig)) {
          this.log('warn', `WebSocket authentication failed for ${wsHost}${wsPath}`);
          wsIncoming.terminate();
          return;
        }
      } catch (error) {
        this.log('error', 'WebSocket authentication error', error);
        wsIncoming.terminate();
        return;
      }
    }

    // Setup outgoing WebSocket connection
    let wsOutgoing: plugins.wsDefault;
    const outGoingDeferred = plugins.smartpromise.defer();

    try {
      const wsTarget = `ws://${wsDestinationConfig.destinationIp}:${wsDestinationConfig.destinationPort}${reqArg.url}`;
      this.log('debug', `Proxying WebSocket to ${wsTarget}`);
      
      wsOutgoing = new plugins.wsDefault(wsTarget);
      
      wsOutgoing.on('open', () => {
        this.log('debug', 'Outgoing WebSocket connection established');
        outGoingDeferred.resolve();
      });
      
      wsOutgoing.on('error', (error) => {
        this.log('error', 'Outgoing WebSocket error', error);
        outGoingDeferred.reject(error);
        if (wsIncoming.readyState === wsIncoming.OPEN) {
          wsIncoming.terminate();
        }
      });
    } catch (err) {
      this.log('error', 'Failed to create outgoing WebSocket connection', err);
      wsIncoming.terminate();
      return;
    }

    // Handle message forwarding from client to backend
    wsIncoming.on('message', async (message, isBinary) => {
      try {
        // Wait for outgoing connection to be ready
        await outGoingDeferred.promise;
        
        // Only forward if both connections are still open
        if (wsOutgoing.readyState === wsOutgoing.OPEN) {
          wsOutgoing.send(message, { binary: isBinary });
        }
      } catch (error) {
        this.log('error', 'Error forwarding WebSocket message to backend', error);
      }
    });

    // Handle message forwarding from backend to client
    wsOutgoing.on('message', (message, isBinary) => {
      try {
        // Only forward if the incoming connection is still open
        if (wsIncoming.readyState === wsIncoming.OPEN) {
          wsIncoming.send(message, { binary: isBinary });
        }
      } catch (error) {
        this.log('error', 'Error forwarding WebSocket message to client', error);
      }
    });

    // Clean up connections when either side closes
    wsIncoming.on('close', (code, reason) => {
      this.log('debug', `Incoming WebSocket closed: ${code} - ${reason}`);
      if (wsOutgoing && wsOutgoing.readyState !== wsOutgoing.CLOSED) {
        try {
          // Validate close code (must be 1000-4999) or use 1000 as default
          const validCode = (code >= 1000 && code <= 4999) ? code : 1000;
          wsOutgoing.close(validCode, reason.toString() || '');
        } catch (error) {
          this.log('error', 'Error closing outgoing WebSocket', error);
          wsOutgoing.terminate();
        }
      }
    });

    wsOutgoing.on('close', (code, reason) => {
      this.log('debug', `Outgoing WebSocket closed: ${code} - ${reason}`);
      if (wsIncoming && wsIncoming.readyState !== wsIncoming.CLOSED) {
        try {
          // Validate close code (must be 1000-4999) or use 1000 as default
          const validCode = (code >= 1000 && code <= 4999) ? code : 1000;
          wsIncoming.close(validCode, reason.toString() || '');
        } catch (error) {
          this.log('error', 'Error closing incoming WebSocket', error);
          wsIncoming.terminate();
        }
      }
    });
  }

  /**
   * Handles an HTTP/HTTPS request
   */
  private async handleRequest(
    originRequest: plugins.http.IncomingMessage,
    originResponse: plugins.http.ServerResponse
  ): Promise<void> {
    this.requestsServed++;
    const startTime = Date.now();
    const reqId = `req_${Date.now()}_${Math.random().toString(36).substring(2, 7)}`;
    
    try {
      const reqPath = plugins.url.parse(originRequest.url).path;
      this.log('info', `[${reqId}] ${originRequest.method} ${originRequest.headers.host}${reqPath}`);
      
      // Handle preflight OPTIONS requests for CORS
      if (originRequest.method === 'OPTIONS' && this.options.cors) {
        this.handleCorsRequest(originRequest, originResponse);
        return;
      }
      
      // Get destination configuration
      const destinationConfig = this.router.routeReq(originRequest);
      if (!destinationConfig) {
        this.log('warn', `[${reqId}] No route found for ${originRequest.headers.host}`);
        this.sendErrorResponse(originResponse, 404, 'Not Found: No matching route');
        this.failedRequests++;
        return;
      }
      
      // Handle authentication if configured
      if (destinationConfig.authentication) {
        try {
          if (!this.authenticateRequest(originRequest, destinationConfig)) {
            this.sendErrorResponse(originResponse, 401, 'Unauthorized', {
              'WWW-Authenticate': 'Basic realm="Access to the proxy site", charset="UTF-8"'
            });
            this.failedRequests++;
            return;
          }
        } catch (error) {
          this.log('error', `[${reqId}] Authentication error`, error);
          this.sendErrorResponse(originResponse, 500, 'Internal Server Error: Authentication failed');
          this.failedRequests++;
          return;
        }
      }
      
      // Construct destination URL
      const destinationUrl = `http://${destinationConfig.destinationIp}:${destinationConfig.destinationPort}${originRequest.url}`;
      this.log('debug', `[${reqId}] Proxying to ${destinationUrl}`);
      
      // Forward the request
      await this.forwardRequest(reqId, originRequest, originResponse, destinationUrl);
      
      const processingTime = Date.now() - startTime;
      this.log('debug', `[${reqId}] Request completed in ${processingTime}ms`);
    } catch (error) {
      this.log('error', `[${reqId}] Unhandled error in request handler`, error);
      try {
        this.sendErrorResponse(originResponse, 502, 'Bad Gateway: Server error');
      } catch (responseError) {
        this.log('error', `[${reqId}] Failed to send error response`, responseError);
      }
      this.failedRequests++;
    }
  }

  /**
   * Handles a CORS preflight request
   */
  private handleCorsRequest(
    req: plugins.http.IncomingMessage,
    res: plugins.http.ServerResponse
  ): void {
    const cors = this.options.cors;
    
    // Set CORS headers
    res.setHeader('Access-Control-Allow-Origin', cors.allowOrigin);
    res.setHeader('Access-Control-Allow-Methods', cors.allowMethods);
    res.setHeader('Access-Control-Allow-Headers', cors.allowHeaders);
    res.setHeader('Access-Control-Max-Age', String(cors.maxAge));
    
    // Handle preflight request
    res.statusCode = 204;
    res.end();
    
    // Count this as a request served
    this.requestsServed++;
  }

  /**
   * Authenticates a request against the destination config
   */
  private authenticateRequest(
    req: plugins.http.IncomingMessage,
    config: plugins.tsclass.network.IReverseProxyConfig
  ): boolean {
    const authInfo = config.authentication;
    if (!authInfo) {
      return true; // No authentication required
    }
    
    switch (authInfo.type) {
      case 'Basic': {
        const authHeader = req.headers.authorization;
        if (!authHeader || !authHeader.includes('Basic ')) {
          return false;
        }
        
        const authStringBase64 = authHeader.replace('Basic ', '');
        const authString: string = plugins.smartstring.base64.decode(authStringBase64);
        const [user, pass] = authString.split(':');
        
        // Use constant-time comparison to prevent timing attacks
        const userMatch = user === authInfo.user;
        const passMatch = pass === authInfo.pass;
        
        return userMatch && passMatch;
      }
      default:
        throw new Error(`Unsupported authentication method: ${authInfo.type}`);
    }
  }

  /**
   * Forwards a request to the destination
   */
  private async forwardRequest(
    reqId: string,
    originRequest: plugins.http.IncomingMessage,
    originResponse: plugins.http.ServerResponse,
    destinationUrl: string
  ): Promise<void> {
    try {
      const proxyRequest = await plugins.smartrequest.request(
        destinationUrl,
        {
          method: originRequest.method,
          headers: this.prepareForwardHeaders(originRequest),
          keepAlive: true,
          timeout: 30000 // 30 second timeout
        },
        true, // streaming
        (proxyRequestStream) => this.setupRequestStreaming(originRequest, proxyRequestStream)
      );
      
      // Handle the response
      this.processProxyResponse(reqId, originResponse, proxyRequest);
    } catch (error) {
      this.log('error', `[${reqId}] Error forwarding request`, error);
      this.sendErrorResponse(originResponse, 502, 'Bad Gateway: Unable to reach upstream server');
      throw error; // Let the main handler catch this
    }
  }

  /**
   * Prepares headers to forward to the backend
   */
  private prepareForwardHeaders(req: plugins.http.IncomingMessage): plugins.http.OutgoingHttpHeaders {
    const safeHeaders = { ...req.headers };
    
    // Add forwarding headers
    safeHeaders['X-Forwarded-Host'] = req.headers.host;
    safeHeaders['X-Forwarded-Proto'] = 'https';
    safeHeaders['X-Forwarded-For'] = (req.socket.remoteAddress || '').replace(/^::ffff:/, '');
    
    // Add proxy-specific headers
    safeHeaders['X-Proxy-Id'] = `NetworkProxy-${this.options.port}`;
    
    // Remove sensitive headers we don't want to forward
    const sensitiveHeaders = ['connection', 'upgrade', 'http2-settings'];
    for (const header of sensitiveHeaders) {
      delete safeHeaders[header];
    }
    
    return safeHeaders;
  }

  /**
   * Sets up request streaming for the proxy
   */
  private setupRequestStreaming(
    originRequest: plugins.http.IncomingMessage,
    proxyRequest: plugins.http.ClientRequest
  ): void {
    // Forward request body data
    originRequest.on('data', (chunk) => {
      proxyRequest.write(chunk);
    });
    
    // End the request when done
    originRequest.on('end', () => {
      proxyRequest.end();
    });
    
    // Handle request errors
    originRequest.on('error', (error) => {
      this.log('error', 'Error in client request stream', error);
      proxyRequest.destroy(error);
    });
    
    // Handle client abort/timeout
    originRequest.on('close', () => {
      if (!originRequest.complete) {
        this.log('debug', 'Client closed connection before request completed');
        proxyRequest.destroy();
      }
    });
    
    originRequest.on('timeout', () => {
      this.log('debug', 'Client request timeout');
      proxyRequest.destroy(new Error('Client request timeout'));
    });
    
    // Handle proxy request errors
    proxyRequest.on('error', (error) => {
      this.log('error', 'Error in outgoing proxy request', error);
    });
  }

  /**
   * Processes a proxy response
   */
  private processProxyResponse(
    reqId: string,
    originResponse: plugins.http.ServerResponse,
    proxyResponse: plugins.http.IncomingMessage
  ): void {
    this.log('debug', `[${reqId}] Received upstream response: ${proxyResponse.statusCode}`);
    
    // Set status code
    originResponse.statusCode = proxyResponse.statusCode;
    
    // Add default headers
    for (const [headerName, headerValue] of Object.entries(this.defaultHeaders)) {
      originResponse.setHeader(headerName, headerValue);
    }
    
    // Add CORS headers if enabled
    if (this.options.cors) {
      originResponse.setHeader('Access-Control-Allow-Origin', this.options.cors.allowOrigin);
    }
    
    // Copy response headers
    for (const [headerName, headerValue] of Object.entries(proxyResponse.headers)) {
      // Skip hop-by-hop headers
      const hopByHopHeaders = ['connection', 'keep-alive', 'transfer-encoding', 'te', 
                               'trailer', 'upgrade', 'proxy-authorization', 'proxy-authenticate'];
      if (!hopByHopHeaders.includes(headerName.toLowerCase())) {
        originResponse.setHeader(headerName, headerValue);
      }
    }
    
    // Stream response body
    proxyResponse.on('data', (chunk) => {
      const canContinue = originResponse.write(chunk);
      
      // Apply backpressure if needed
      if (!canContinue) {
        proxyResponse.pause();
        originResponse.once('drain', () => {
          proxyResponse.resume();
        });
      }
    });
    
    // End the response when done
    proxyResponse.on('end', () => {
      originResponse.end();
    });
    
    // Handle response errors
    proxyResponse.on('error', (error) => {
      this.log('error', `[${reqId}] Error in proxy response stream`, error);
      originResponse.destroy(error);
    });
    
    originResponse.on('error', (error) => {
      this.log('error', `[${reqId}] Error in client response stream`, error);
      proxyResponse.destroy();
    });
  }

  /**
   * Sends an error response to the client
   */
  private sendErrorResponse(
    res: plugins.http.ServerResponse,
    statusCode: number = 500,
    message: string = 'Internal Server Error',
    headers: plugins.http.OutgoingHttpHeaders = {}
  ): void {
    try {
      // If headers already sent, just end the response
      if (res.headersSent) {
        res.end();
        return;
      }
      
      // Add default headers
      for (const [key, value] of Object.entries(this.defaultHeaders)) {
        res.setHeader(key, value);
      }
      
      // Add provided headers
      for (const [key, value] of Object.entries(headers)) {
        res.setHeader(key, value);
      }
      
      // Send error response
      res.writeHead(statusCode, message);
      
      // Send error body as JSON for API clients
      if (res.getHeader('Content-Type') === 'application/json') {
        res.end(JSON.stringify({ error: { status: statusCode, message } }));
      } else {
        // Send as plain text
        res.end(message);
      }
    } catch (error) {
      this.log('error', 'Error sending error response', error);
      try {
        res.destroy();
      } catch (destroyError) {
        // Last resort - nothing more we can do
      }
    }
  }

  /**
   * Updates proxy configurations
   */
  public async updateProxyConfigs(
    proxyConfigsArg: plugins.tsclass.network.IReverseProxyConfig[]
  ): Promise<void> {
    this.log('info', `Updating proxy configurations (${proxyConfigsArg.length} configs)`);
    
    // Update internal configs
    this.proxyConfigs = proxyConfigsArg;
    this.router.setNewProxyConfigs(proxyConfigsArg);
    
    // Collect all hostnames for cleanup later
    const currentHostNames = new Set<string>();
    
    // Add/update SSL contexts for each host
    for (const config of proxyConfigsArg) {
      currentHostNames.add(config.hostName);
      
      try {
        // Check if we need to update the cert
        const currentCert = this.certificateCache.get(config.hostName);
        const shouldUpdate = !currentCert || 
                            currentCert.key !== config.privateKey || 
                            currentCert.cert !== config.publicKey;
        
        if (shouldUpdate) {
          this.log('debug', `Updating SSL context for ${config.hostName}`);
          
          // Update the HTTPS server context
          this.httpsServer.addContext(config.hostName, {
            key: config.privateKey,
            cert: config.publicKey
          });
          
          // Update the cache
          this.certificateCache.set(config.hostName, {
            key: config.privateKey,
            cert: config.publicKey
          });
          
          this.activeContexts.add(config.hostName);
        }
      } catch (error) {
        this.log('error', `Failed to add SSL context for ${config.hostName}`, error);
      }
    }
    
    // Clean up removed contexts
    // Note: Node.js doesn't officially support removing contexts
    // This would require server restart in production
    for (const hostname of this.activeContexts) {
      if (!currentHostNames.has(hostname)) {
        this.log('info', `Hostname ${hostname} removed from configuration`);
        this.activeContexts.delete(hostname);
        this.certificateCache.delete(hostname);
      }
    }
  }

  /**
   * Adds default headers to be included in all responses
   */
  public async addDefaultHeaders(headersArg: { [key: string]: string }): Promise<void> {
    this.log('info', 'Adding default headers', headersArg);
    this.defaultHeaders = {
      ...this.defaultHeaders,
      ...headersArg
    };
  }

  /**
   * Stops the proxy server
   */
  public async stop(): Promise<void> {
    this.log('info', 'Stopping NetworkProxy server');
    
    // Clear intervals
    if (this.heartbeatInterval) {
      clearInterval(this.heartbeatInterval);
    }
    
    if (this.metricsInterval) {
      clearInterval(this.metricsInterval);
    }
    
    // Close WebSocket server if exists
    if (this.wsServer) {
      for (const client of this.wsServer.clients) {
        try {
          client.terminate();
        } catch (error) {
          this.log('error', 'Error terminating WebSocket client', error);
        }
      }
    }
    
    // Close all tracked sockets
    for (const socket of this.socketMap.getArray()) {
      try {
        socket.destroy();
      } catch (error) {
        this.log('error', 'Error destroying socket', error);
      }
    }
    
    // Close the HTTPS server
    return new Promise((resolve) => {
      this.httpsServer.close(() => {
        this.log('info', 'NetworkProxy server stopped successfully');
        resolve();
      });
    });
  }

  /**
   * Logs a message according to the configured log level
   */
  private log(level: 'error' | 'warn' | 'info' | 'debug', message: string, data?: any): void {
    const logLevels = {
      error: 0,
      warn: 1,
      info: 2,
      debug: 3
    };
    
    // Skip if log level is higher than configured
    if (logLevels[level] > logLevels[this.options.logLevel]) {
      return;
    }
    
    const timestamp = new Date().toISOString();
    const prefix = `[${timestamp}] [${level.toUpperCase()}]`;
    
    switch (level) {
      case 'error':
        console.error(`${prefix} ${message}`, data || '');
        break;
      case 'warn':
        console.warn(`${prefix} ${message}`, data || '');
        break;
      case 'info':
        console.log(`${prefix} ${message}`, data || '');
        break;
      case 'debug':
        console.log(`${prefix} ${message}`, data || '');
        break;
    }
  }
}