/**
 * Routing Information Extractor
 * 
 * Extracts minimal routing information from protocols
 * without full parsing
 */

import type { IRoutingInfo, IConnectionContext, TProtocolType } from '../../protocols/common/types.js';
import { SniExtraction } from '../../protocols/tls/sni/sni-extraction.js';
import { HttpParser } from '../../protocols/http/index.js';

/**
 * Extracts routing information from protocol data
 */
export class RoutingExtractor {
  /**
   * Extract routing info based on protocol type
   */
  static extract(
    data: Buffer, 
    protocol: TProtocolType,
    context?: IConnectionContext
  ): IRoutingInfo | null {
    switch (protocol) {
      case 'tls':
      case 'https':
        return this.extractTlsRouting(data, context);
      
      case 'http':
        return this.extractHttpRouting(data);
      
      default:
        return null;
    }
  }
  
  /**
   * Extract routing from TLS ClientHello (SNI)
   */
  private static extractTlsRouting(
    data: Buffer,
    context?: IConnectionContext
  ): IRoutingInfo | null {
    try {
      // Quick SNI extraction without full parsing
      const sni = SniExtraction.extractSNI(data);
      
      if (sni) {
        return {
          domain: sni,
          protocol: 'tls',
          port: 443  // Default HTTPS port
        };
      }
      
      return null;
    } catch (error) {
      // Extraction failed, return null
      return null;
    }
  }
  
  /**
   * Extract routing from HTTP headers (Host header)
   */
  private static extractHttpRouting(data: Buffer): IRoutingInfo | null {
    try {
      // Look for first line
      const firstLineEnd = data.indexOf('\n');
      if (firstLineEnd === -1) {
        return null;
      }
      
      // Parse request line
      const firstLine = data.subarray(0, firstLineEnd).toString('ascii').trim();
      const requestLine = HttpParser.parseRequestLine(firstLine);
      
      if (!requestLine) {
        return null;
      }
      
      // Look for Host header
      let pos = firstLineEnd + 1;
      const maxSearch = Math.min(data.length, 4096); // Don't search too far
      
      while (pos < maxSearch) {
        const lineEnd = data.indexOf('\n', pos);
        if (lineEnd === -1) break;
        
        const line = data.subarray(pos, lineEnd).toString('ascii').trim();
        
        // Empty line means end of headers
        if (line.length === 0) break;
        
        // Check for Host header
        if (line.toLowerCase().startsWith('host:')) {
          const hostValue = line.substring(5).trim();
          const domain = HttpParser.extractDomainFromHost(hostValue);
          
          return {
            domain,
            path: requestLine.path,
            protocol: 'http',
            port: 80  // Default HTTP port
          };
        }
        
        pos = lineEnd + 1;
      }
      
      // No Host header found, but we have the path
      return {
        path: requestLine.path,
        protocol: 'http',
        port: 80
      };
    } catch (error) {
      // Extraction failed
      return null;
    }
  }
  
  /**
   * Try to extract domain from any protocol
   */
  static extractDomain(data: Buffer, hint?: TProtocolType): string | null {
    // If we have a hint, use it
    if (hint) {
      const routing = this.extract(data, hint);
      return routing?.domain || null;
    }
    
    // Try TLS first (more specific)
    const tlsRouting = this.extractTlsRouting(data);
    if (tlsRouting?.domain) {
      return tlsRouting.domain;
    }
    
    // Try HTTP
    const httpRouting = this.extractHttpRouting(data);
    if (httpRouting?.domain) {
      return httpRouting.domain;
    }
    
    return null;
  }
}