import * as plugins from '../../plugins.js';
import { logger } from './logger.js';
import { ProxyProtocolParser as ProtocolParser, type IProxyInfo, type IProxyParseResult } from '../../protocols/proxy/index.js';

// Re-export types from protocols for backward compatibility
export type { IProxyInfo, IProxyParseResult } from '../../protocols/proxy/index.js';

/**
 * Parser for PROXY protocol v1 (text format)
 * Spec: https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt
 * 
 * This class now delegates to the protocol parser but adds 
 * smartproxy-specific features like socket reading and logging
 */
export class ProxyProtocolParser {
  static readonly PROXY_V1_SIGNATURE = ProtocolParser.PROXY_V1_SIGNATURE;
  static readonly MAX_HEADER_LENGTH = ProtocolParser.MAX_HEADER_LENGTH;
  static readonly HEADER_TERMINATOR = ProtocolParser.HEADER_TERMINATOR;
  
  /**
   * Parse PROXY protocol v1 header from buffer
   * Returns proxy info and remaining data after header
   */
  static parse(data: Buffer): IProxyParseResult {
    // Delegate to protocol parser
    return ProtocolParser.parse(data);
  }
  
  /**
   * Generate PROXY protocol v1 header
   */
  static generate(info: IProxyInfo): Buffer {
    // Delegate to protocol parser
    return ProtocolParser.generate(info);
  }
  
  /**
   * Validate IP address format
   */
  private static isValidIP(ip: string, protocol: 'TCP4' | 'TCP6' | 'UNKNOWN'): boolean {
    return ProtocolParser.isValidIP(ip, protocol);
  }
  
  /**
   * Attempt to read a complete PROXY protocol header from a socket
   * Returns null if no PROXY protocol detected or incomplete
   */
  static async readFromSocket(socket: plugins.net.Socket, timeout: number = 5000): Promise<IProxyParseResult | null> {
    return new Promise((resolve) => {
      let buffer = Buffer.alloc(0);
      let resolved = false;
      
      const cleanup = () => {
        socket.removeListener('data', onData);
        socket.removeListener('error', onError);
        clearTimeout(timer);
      };
      
      const timer = setTimeout(() => {
        if (!resolved) {
          resolved = true;
          cleanup();
          resolve({
            proxyInfo: null,
            remainingData: buffer
          });
        }
      }, timeout);
      
      const onData = (chunk: Buffer) => {
        buffer = Buffer.concat([buffer, chunk]);
        
        // Check if we have enough data
        if (!buffer.toString('ascii', 0, Math.min(6, buffer.length)).startsWith(this.PROXY_V1_SIGNATURE)) {
          // Not PROXY protocol
          resolved = true;
          cleanup();
          resolve({
            proxyInfo: null,
            remainingData: buffer
          });
          return;
        }
        
        // Try to parse
        try {
          const result = this.parse(buffer);
          if (result.proxyInfo) {
            // Successfully parsed
            resolved = true;
            cleanup();
            resolve(result);
          } else if (buffer.length > this.MAX_HEADER_LENGTH) {
            // Header too long
            resolved = true;
            cleanup();
            resolve({
              proxyInfo: null,
              remainingData: buffer
            });
          }
          // Otherwise continue reading
        } catch (error) {
          // Parse error
          logger.log('error', `PROXY protocol parse error: ${error.message}`);
          resolved = true;
          cleanup();
          resolve({
            proxyInfo: null,
            remainingData: buffer
          });
        }
      };
      
      const onError = (error: Error) => {
        logger.log('error', `Socket error while reading PROXY protocol: ${error.message}`);
        resolved = true;
        cleanup();
        resolve({
          proxyInfo: null,
          remainingData: buffer
        });
      };
      
      socket.on('data', onData);
      socket.on('error', onError);
    });
  }
}