/**
 * Route Helper Functions
 *
 * This file provides utility functions for creating route configurations for common scenarios.
 * These functions aim to simplify the creation of route configurations for typical use cases.
 *
 * This module includes helper functions for creating:
 * - HTTP routes (createHttpRoute)
 * - HTTPS routes with TLS termination (createHttpsTerminateRoute)
 * - HTTP to HTTPS redirects (createHttpToHttpsRedirect)
 * - HTTPS passthrough routes (createHttpsPassthroughRoute)
 * - Complete HTTPS servers with redirects (createCompleteHttpsServer)
 * - Load balancer routes (createLoadBalancerRoute)
 * - API routes (createApiRoute)
 * - WebSocket routes (createWebSocketRoute)
 * - Port mapping routes (createPortMappingRoute, createOffsetPortMappingRoute)
 * - Dynamic routing (createDynamicRoute, createSmartLoadBalancer)
 * - NFTables routes (createNfTablesRoute, createNfTablesTerminateRoute)
 */

import * as plugins from '../../../plugins.js';
import type { IRouteConfig, IRouteMatch, IRouteAction, IRouteTarget, TPortRange, IRouteContext } from '../models/route-types.js';
import { mergeRouteConfigs } from './route-utils.js';
import { ProtocolDetector, HttpDetector } from '../../../detection/index.js';

/**
 * Create an HTTP-only route configuration
 * @param domains Domain(s) to match
 * @param target Target host and port
 * @param options Additional route options
 * @returns Route configuration object
 */
export function createHttpRoute(
  domains: string | string[],
  target: { host: string | string[]; port: number },
  options: Partial<IRouteConfig> = {}
): IRouteConfig {
  // Create route match
  const match: IRouteMatch = {
    ports: options.match?.ports || 80,
    domains
  };

  // Create route action
  const action: IRouteAction = {
    type: 'forward',
    targets: [target]
  };

  // Create the route config
  return {
    match,
    action,
    name: options.name || `HTTP Route for ${Array.isArray(domains) ? domains.join(', ') : domains}`,
    ...options
  };
}

/**
 * Create an HTTPS route with TLS termination (including HTTP redirect to HTTPS)
 * @param domains Domain(s) to match
 * @param target Target host and port
 * @param options Additional route options
 * @returns Route configuration object
 */
export function createHttpsTerminateRoute(
  domains: string | string[],
  target: { host: string | string[]; port: number },
  options: {
    certificate?: 'auto' | { key: string; cert: string };
    httpPort?: number | number[];
    httpsPort?: number | number[];
    reencrypt?: boolean;
    name?: string;
    [key: string]: any;
  } = {}
): IRouteConfig {
  // Create route match
  const match: IRouteMatch = {
    ports: options.httpsPort || 443,
    domains
  };

  // Create route action
  const action: IRouteAction = {
    type: 'forward',
    targets: [target],
    tls: {
      mode: options.reencrypt ? 'terminate-and-reencrypt' : 'terminate',
      certificate: options.certificate || 'auto'
    }
  };

  // Create the route config
  return {
    match,
    action,
    name: options.name || `HTTPS Route for ${Array.isArray(domains) ? domains.join(', ') : domains}`,
    ...options
  };
}

/**
 * Create an HTTP to HTTPS redirect route
 * @param domains Domain(s) to match
 * @param httpsPort HTTPS port to redirect to (default: 443)
 * @param options Additional route options
 * @returns Route configuration object
 */
export function createHttpToHttpsRedirect(
  domains: string | string[],
  httpsPort: number = 443,
  options: Partial<IRouteConfig> = {}
): IRouteConfig {
  // Create route match
  const match: IRouteMatch = {
    ports: options.match?.ports || 80,
    domains
  };

  // Create route action
  const action: IRouteAction = {
    type: 'socket-handler',
    socketHandler: SocketHandlers.httpRedirect(`https://{domain}:${httpsPort}{path}`, 301)
  };

  // Create the route config
  return {
    match,
    action,
    name: options.name || `HTTP to HTTPS Redirect for ${Array.isArray(domains) ? domains.join(', ') : domains}`,
    ...options
  };
}

/**
 * Create an HTTPS passthrough route (SNI-based forwarding without TLS termination)
 * @param domains Domain(s) to match
 * @param target Target host and port
 * @param options Additional route options
 * @returns Route configuration object
 */
export function createHttpsPassthroughRoute(
  domains: string | string[],
  target: { host: string | string[]; port: number },
  options: Partial<IRouteConfig> = {}
): IRouteConfig {
  // Create route match
  const match: IRouteMatch = {
    ports: options.match?.ports || 443,
    domains
  };

  // Create route action
  const action: IRouteAction = {
    type: 'forward',
    targets: [target],
    tls: {
      mode: 'passthrough'
    }
  };

  // Create the route config
  return {
    match,
    action,
    name: options.name || `HTTPS Passthrough for ${Array.isArray(domains) ? domains.join(', ') : domains}`,
    ...options
  };
}

/**
 * Create a complete HTTPS server with HTTP to HTTPS redirects
 * @param domains Domain(s) to match
 * @param target Target host and port
 * @param options Additional configuration options
 * @returns Array of two route configurations (HTTPS and HTTP redirect)
 */
export function createCompleteHttpsServer(
  domains: string | string[],
  target: { host: string | string[]; port: number },
  options: {
    certificate?: 'auto' | { key: string; cert: string };
    httpPort?: number | number[];
    httpsPort?: number | number[];
    reencrypt?: boolean;
    name?: string;
    [key: string]: any;
  } = {}
): IRouteConfig[] {
  // Create the HTTPS route
  const httpsRoute = createHttpsTerminateRoute(domains, target, options);
  
  // Create the HTTP redirect route
  const httpRedirectRoute = createHttpToHttpsRedirect(
    domains,
    // Extract the HTTPS port from the HTTPS route - ensure it's a number
    typeof options.httpsPort === 'number' ? options.httpsPort :
      Array.isArray(options.httpsPort) ? options.httpsPort[0] : 443,
    {
      // Set the HTTP port
      match: {
        ports: options.httpPort || 80,
        domains
      },
      name: `HTTP to HTTPS Redirect for ${Array.isArray(domains) ? domains.join(', ') : domains}`
    }
  );
  
  return [httpsRoute, httpRedirectRoute];
}

/**
 * Create a load balancer route (round-robin between multiple backend hosts)
 * @param domains Domain(s) to match
 * @param backendsOrHosts Array of backend servers OR array of host strings (legacy)
 * @param portOrOptions Port number (legacy) OR options object
 * @param options Additional route options (legacy)
 * @returns Route configuration object
 */
export function createLoadBalancerRoute(
  domains: string | string[],
  backendsOrHosts: Array<{ host: string; port: number }> | string[],
  portOrOptions?: number | {
    tls?: {
      mode: 'passthrough' | 'terminate' | 'terminate-and-reencrypt';
      certificate?: 'auto' | { key: string; cert: string };
    };
    useTls?: boolean;
    certificate?: 'auto' | { key: string; cert: string };
    algorithm?: 'round-robin' | 'least-connections' | 'ip-hash';
    healthCheck?: {
      path: string;
      interval: number;
      timeout: number;
      unhealthyThreshold: number;
      healthyThreshold: number;
    };
    [key: string]: any;
  },
  options?: {
    tls?: {
      mode: 'passthrough' | 'terminate' | 'terminate-and-reencrypt';
      certificate?: 'auto' | { key: string; cert: string };
    };
    [key: string]: any;
  }
): IRouteConfig {
  // Handle legacy signature: (domains, hosts[], port, options)
  let backends: Array<{ host: string; port: number }>;
  let finalOptions: any;
  
  if (Array.isArray(backendsOrHosts) && backendsOrHosts.length > 0 && typeof backendsOrHosts[0] === 'string') {
    // Legacy signature
    const hosts = backendsOrHosts as string[];
    const port = portOrOptions as number;
    backends = hosts.map(host => ({ host, port }));
    finalOptions = options || {};
  } else {
    // New signature
    backends = backendsOrHosts as Array<{ host: string; port: number }>;
    finalOptions = (portOrOptions as any) || {};
  }
  
  // Extract hosts and ensure all backends use the same port
  const port = backends[0].port;
  const hosts = backends.map(backend => backend.host);
  
  // Create route match
  const match: IRouteMatch = {
    ports: finalOptions.match?.ports || (finalOptions.tls || finalOptions.useTls ? 443 : 80),
    domains
  };

  // Create route target
  const target: IRouteTarget = {
    host: hosts,
    port
  };

  // Create route action
  const action: IRouteAction = {
    type: 'forward',
    targets: [target]
  };

  // Add TLS configuration if provided
  if (finalOptions.tls || finalOptions.useTls) {
    action.tls = {
      mode: finalOptions.tls?.mode || 'terminate',
      certificate: finalOptions.tls?.certificate || finalOptions.certificate || 'auto'
    };
  }

  // Add load balancing options
  if (finalOptions.algorithm || finalOptions.healthCheck) {
    action.loadBalancing = {
      algorithm: finalOptions.algorithm || 'round-robin',
      healthCheck: finalOptions.healthCheck
    };
  }

  // Create the route config
  return {
    match,
    action,
    name: finalOptions.name || `Load Balancer for ${Array.isArray(domains) ? domains.join(', ') : domains}`,
    ...finalOptions
  };
}

/**
 * Create an API route configuration
 * @param domains Domain(s) to match
 * @param apiPath API base path (e.g., "/api")
 * @param target Target host and port
 * @param options Additional route options
 * @returns Route configuration object
 */
export function createApiRoute(
  domains: string | string[],
  apiPath: string,
  target: { host: string | string[]; port: number },
  options: {
    useTls?: boolean;
    certificate?: 'auto' | { key: string; cert: string };
    addCorsHeaders?: boolean;
    httpPort?: number | number[];
    httpsPort?: number | number[];
    name?: string;
    [key: string]: any;
  } = {}
): IRouteConfig {
  // Normalize API path
  const normalizedPath = apiPath.startsWith('/') ? apiPath : `/${apiPath}`;
  const pathWithWildcard = normalizedPath.endsWith('/')
    ? `${normalizedPath}*`
    : `${normalizedPath}/*`;

  // Create route match
  const match: IRouteMatch = {
    ports: options.useTls
      ? (options.httpsPort || 443)
      : (options.httpPort || 80),
    domains,
    path: pathWithWildcard
  };

  // Create route action
  const action: IRouteAction = {
    type: 'forward',
    targets: [target]
  };

  // Add TLS configuration if using HTTPS
  if (options.useTls) {
    action.tls = {
      mode: 'terminate',
      certificate: options.certificate || 'auto'
    };
  }

  // Add CORS headers if requested
  const headers: Record<string, Record<string, string>> = {};
  if (options.addCorsHeaders) {
    headers.response = {
      'Access-Control-Allow-Origin': '*',
      'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
      'Access-Control-Allow-Headers': 'Content-Type, Authorization',
      'Access-Control-Max-Age': '86400'
    };
  }

  // Create the route config
  return {
    match,
    action,
    headers: Object.keys(headers).length > 0 ? headers : undefined,
    name: options.name || `API Route ${normalizedPath} for ${Array.isArray(domains) ? domains.join(', ') : domains}`,
    priority: options.priority || 100, // Higher priority for specific path matches
    ...options
  };
}

/**
 * Create a WebSocket route configuration
 * @param domains Domain(s) to match
 * @param targetOrPath Target server OR WebSocket path (legacy)
 * @param targetOrOptions Target server (legacy) OR options
 * @param options Additional route options (legacy)
 * @returns Route configuration object
 */
export function createWebSocketRoute(
  domains: string | string[],
  targetOrPath: { host: string | string[]; port: number } | string,
  targetOrOptions?: { host: string | string[]; port: number } | {
    useTls?: boolean;
    certificate?: 'auto' | { key: string; cert: string };
    path?: string;
    httpPort?: number | number[];
    httpsPort?: number | number[];
    pingInterval?: number;
    pingTimeout?: number;
    name?: string;
    [key: string]: any;
  },
  options?: {
    useTls?: boolean;
    certificate?: 'auto' | { key: string; cert: string };
    httpPort?: number | number[];
    httpsPort?: number | number[];
    pingInterval?: number;
    pingTimeout?: number;
    name?: string;
    [key: string]: any;
  }
): IRouteConfig {
  // Handle different signatures
  let target: { host: string | string[]; port: number };
  let wsPath: string;
  let finalOptions: any;
  
  if (typeof targetOrPath === 'string') {
    // Legacy signature: (domains, path, target, options)
    wsPath = targetOrPath;
    target = targetOrOptions as { host: string | string[]; port: number };
    finalOptions = options || {};
  } else {
    // New signature: (domains, target, options)
    target = targetOrPath;
    finalOptions = (targetOrOptions as any) || {};
    wsPath = finalOptions.path || '/ws';
  }
  
  // Normalize WebSocket path
  const normalizedPath = wsPath.startsWith('/') ? wsPath : `/${wsPath}`;

  // Create route match
  const match: IRouteMatch = {
    ports: finalOptions.useTls
      ? (finalOptions.httpsPort || 443)
      : (finalOptions.httpPort || 80),
    domains,
    path: normalizedPath
  };

  // Create route action
  const action: IRouteAction = {
    type: 'forward',
    targets: [target],
    websocket: {
      enabled: true,
      pingInterval: finalOptions.pingInterval || 30000, // 30 seconds
      pingTimeout: finalOptions.pingTimeout || 5000    // 5 seconds
    }
  };

  // Add TLS configuration if using HTTPS
  if (finalOptions.useTls) {
    action.tls = {
      mode: 'terminate',
      certificate: finalOptions.certificate || 'auto'
    };
  }

  // Create the route config
  return {
    match,
    action,
    name: finalOptions.name || `WebSocket Route ${normalizedPath} for ${Array.isArray(domains) ? domains.join(', ') : domains}`,
    priority: finalOptions.priority || 100, // Higher priority for WebSocket routes
    ...finalOptions
  };
}

/**
 * Create a helper function that applies a port offset
 * @param offset The offset to apply to the matched port
 * @returns A function that adds the offset to the matched port
 */
export function createPortOffset(offset: number): (context: IRouteContext) => number {
  return (context: IRouteContext) => context.port + offset;
}

/**
 * Create a port mapping route with context-based port function
 * @param options Port mapping route options
 * @returns Route configuration object
 */
export function createPortMappingRoute(options: {
  sourcePortRange: TPortRange;
  targetHost: string | string[] | ((context: IRouteContext) => string | string[]);
  portMapper: (context: IRouteContext) => number;
  name?: string;
  domains?: string | string[];
  priority?: number;
  [key: string]: any;
}): IRouteConfig {
  // Create route match
  const match: IRouteMatch = {
    ports: options.sourcePortRange,
    domains: options.domains
  };

  // Create route action
  const action: IRouteAction = {
    type: 'forward',
    targets: [{
      host: options.targetHost,
      port: options.portMapper
    }]
  };

  // Create the route config
  return {
    match,
    action,
    name: options.name || `Port Mapping Route for ${options.domains || 'all domains'}`,
    priority: options.priority,
    ...options
  };
}

/**
 * Create a simple offset port mapping route
 * @param options Offset port mapping route options
 * @returns Route configuration object
 */
export function createOffsetPortMappingRoute(options: {
  ports: TPortRange;
  targetHost: string | string[];
  offset: number;
  name?: string;
  domains?: string | string[];
  priority?: number;
  [key: string]: any;
}): IRouteConfig {
  return createPortMappingRoute({
    sourcePortRange: options.ports,
    targetHost: options.targetHost,
    portMapper: (context) => context.port + options.offset,
    name: options.name || `Offset Mapping (${options.offset > 0 ? '+' : ''}${options.offset}) for ${options.domains || 'all domains'}`,
    domains: options.domains,
    priority: options.priority,
    ...options
  });
}

/**
 * Create a dynamic route with context-based host and port mapping
 * @param options Dynamic route options
 * @returns Route configuration object
 */
export function createDynamicRoute(options: {
  ports: TPortRange;
  targetHost: (context: IRouteContext) => string | string[];
  portMapper: (context: IRouteContext) => number;
  name?: string;
  domains?: string | string[];
  path?: string;
  clientIp?: string[];
  priority?: number;
  [key: string]: any;
}): IRouteConfig {
  // Create route match
  const match: IRouteMatch = {
    ports: options.ports,
    domains: options.domains,
    path: options.path,
    clientIp: options.clientIp
  };

  // Create route action
  const action: IRouteAction = {
    type: 'forward',
    targets: [{
      host: options.targetHost,
      port: options.portMapper
    }]
  };

  // Create the route config
  return {
    match,
    action,
    name: options.name || `Dynamic Route for ${options.domains || 'all domains'}`,
    priority: options.priority,
    ...options
  };
}

/**
 * Create a smart load balancer with dynamic domain-based backend selection
 * @param options Smart load balancer options
 * @returns Route configuration object
 */
export function createSmartLoadBalancer(options: {
  ports: TPortRange;
  domainTargets: Record<string, string | string[]>;
  portMapper: (context: IRouteContext) => number;
  name?: string;
  defaultTarget?: string | string[];
  priority?: number;
  [key: string]: any;
}): IRouteConfig {
  // Extract all domain keys to create the match criteria
  const domains = Object.keys(options.domainTargets);

  // Create the smart host selector function
  const hostSelector = (context: IRouteContext) => {
    const domain = context.domain || '';
    return options.domainTargets[domain] || options.defaultTarget || 'localhost';
  };

  // Create route match
  const match: IRouteMatch = {
    ports: options.ports,
    domains
  };

  // Create route action
  const action: IRouteAction = {
    type: 'forward',
    targets: [{
      host: hostSelector,
      port: options.portMapper
    }]
  };

  // Create the route config
  return {
    match,
    action,
    name: options.name || `Smart Load Balancer for ${domains.join(', ')}`,
    priority: options.priority,
    ...options
  };
}

/**
 * Create an NFTables-based route for high-performance packet forwarding
 * @param nameOrDomains Name or domain(s) to match
 * @param target Target host and port
 * @param options Additional route options
 * @returns Route configuration object
 */
export function createNfTablesRoute(
  nameOrDomains: string | string[],
  target: { host: string; port: number | 'preserve' },
  options: {
    ports?: TPortRange;
    protocol?: 'tcp' | 'udp' | 'all';
    preserveSourceIP?: boolean;
    ipAllowList?: string[];
    ipBlockList?: string[];
    maxRate?: string;
    priority?: number;
    useTls?: boolean;
    tableName?: string;
    useIPSets?: boolean;
    useAdvancedNAT?: boolean;
  } = {}
): IRouteConfig {
  // Determine if this is a name or domain
  let name: string;
  let domains: string | string[] | undefined;
  
  if (Array.isArray(nameOrDomains) || (typeof nameOrDomains === 'string' && nameOrDomains.includes('.'))) {
    domains = nameOrDomains;
    name = Array.isArray(nameOrDomains) ? nameOrDomains[0] : nameOrDomains;
  } else {
    name = nameOrDomains;
    domains = undefined; // No domains
  }
  
  // Create route match
  const match: IRouteMatch = {
    domains,
    ports: options.ports || 80
  };
  
  // Create route action
  const action: IRouteAction = {
    type: 'forward',
    targets: [{
      host: target.host,
      port: target.port
    }],
    forwardingEngine: 'nftables',
    nftables: {
      protocol: options.protocol || 'tcp',
      preserveSourceIP: options.preserveSourceIP,
      maxRate: options.maxRate,
      priority: options.priority,
      tableName: options.tableName,
      useIPSets: options.useIPSets,
      useAdvancedNAT: options.useAdvancedNAT
    }
  };
  
  // Add TLS options if needed
  if (options.useTls) {
    action.tls = {
      mode: 'passthrough'
    };
  }
  
  // Create the route config
  const routeConfig: IRouteConfig = {
    name,
    match,
    action
  };
  
  // Add security if allowed or blocked IPs are specified
  if (options.ipAllowList?.length || options.ipBlockList?.length) {
    routeConfig.security = {
      ipAllowList: options.ipAllowList,
      ipBlockList: options.ipBlockList
    };
  }
  
  return routeConfig;
}

/**
 * Create an NFTables-based TLS termination route
 * @param nameOrDomains Name or domain(s) to match
 * @param target Target host and port
 * @param options Additional route options
 * @returns Route configuration object
 */
export function createNfTablesTerminateRoute(
  nameOrDomains: string | string[],
  target: { host: string; port: number | 'preserve' },
  options: {
    ports?: TPortRange;
    protocol?: 'tcp' | 'udp' | 'all';
    preserveSourceIP?: boolean;
    ipAllowList?: string[];
    ipBlockList?: string[];
    maxRate?: string;
    priority?: number;
    tableName?: string;
    useIPSets?: boolean;
    useAdvancedNAT?: boolean;
    certificate?: 'auto' | { key: string; cert: string };
  } = {}
): IRouteConfig {
  // Create basic NFTables route
  const route = createNfTablesRoute(
    nameOrDomains,
    target,
    {
      ...options,
      ports: options.ports || 443,
      useTls: false
    }
  );
  
  // Set TLS termination
  route.action.tls = {
    mode: 'terminate',
    certificate: options.certificate || 'auto'
  };
  
  return route;
}

/**
 * Create a complete NFTables-based HTTPS setup with HTTP redirect
 * @param nameOrDomains Name or domain(s) to match
 * @param target Target host and port
 * @param options Additional route options
 * @returns Array of two route configurations (HTTPS and HTTP redirect)
 */
export function createCompleteNfTablesHttpsServer(
  nameOrDomains: string | string[],
  target: { host: string; port: number | 'preserve' },
  options: {
    httpPort?: TPortRange;
    httpsPort?: TPortRange;
    protocol?: 'tcp' | 'udp' | 'all';
    preserveSourceIP?: boolean;
    ipAllowList?: string[];
    ipBlockList?: string[];
    maxRate?: string;
    priority?: number;
    tableName?: string;
    useIPSets?: boolean;
    useAdvancedNAT?: boolean;
    certificate?: 'auto' | { key: string; cert: string };
  } = {}
): IRouteConfig[] {
  // Create the HTTPS route using NFTables
  const httpsRoute = createNfTablesTerminateRoute(
    nameOrDomains,
    target,
    {
      ...options,
      ports: options.httpsPort || 443
    }
  );
  
  // Determine the domain(s) for HTTP redirect
  const domains = typeof nameOrDomains === 'string' && !nameOrDomains.includes('.') 
    ? undefined 
    : nameOrDomains;
  
  // Extract the HTTPS port for the redirect destination
  const httpsPort = typeof options.httpsPort === 'number' 
    ? options.httpsPort 
    : Array.isArray(options.httpsPort) && typeof options.httpsPort[0] === 'number' 
      ? options.httpsPort[0] 
      : 443;
  
  // Create the HTTP redirect route (this uses standard forwarding, not NFTables)
  const httpRedirectRoute = createHttpToHttpsRedirect(
    domains as any, // Type cast needed since domains can be undefined now
    httpsPort,
    {
      match: {
        ports: options.httpPort || 80,
        domains: domains as any // Type cast needed since domains can be undefined now
      },
      name: `HTTP to HTTPS Redirect for ${Array.isArray(domains) ? domains.join(', ') : domains || 'all domains'}`
    }
  );
  
  return [httpsRoute, httpRedirectRoute];
}

/**
 * Create a socket handler route configuration
 * @param domains Domain(s) to match
 * @param ports Port(s) to listen on
 * @param handler Socket handler function
 * @param options Additional route options
 * @returns Route configuration object
 */
export function createSocketHandlerRoute(
  domains: string | string[],
  ports: TPortRange,
  handler: (socket: plugins.net.Socket) => void | Promise<void>,
  options: {
    name?: string;
    priority?: number;
    path?: string;
  } = {}
): IRouteConfig {
  return {
    name: options.name || 'socket-handler-route',
    priority: options.priority !== undefined ? options.priority : 50,
    match: {
      domains,
      ports,
      ...(options.path && { path: options.path })
    },
    action: {
      type: 'socket-handler',
      socketHandler: handler
    }
  };
}

/**
 * Pre-built socket handlers for common use cases
 */
export const SocketHandlers = {
  /**
   * Simple echo server handler
   */
  echo: (socket: plugins.net.Socket, context: IRouteContext) => {
    socket.write('ECHO SERVER READY\n');
    socket.on('data', data => socket.write(data));
  },
  
  /**
   * TCP proxy handler
   */
  proxy: (targetHost: string, targetPort: number) => (socket: plugins.net.Socket, context: IRouteContext) => {
    const target = plugins.net.connect(targetPort, targetHost);
    socket.pipe(target);
    target.pipe(socket);
    socket.on('close', () => target.destroy());
    target.on('close', () => socket.destroy());
    target.on('error', (err) => {
      console.error('Proxy target error:', err);
      socket.destroy();
    });
  },
  
  /**
   * Line-based protocol handler
   */
  lineProtocol: (handler: (line: string, socket: plugins.net.Socket) => void) => (socket: plugins.net.Socket, context: IRouteContext) => {
    let buffer = '';
    socket.on('data', (data) => {
      buffer += data.toString();
      const lines = buffer.split('\n');
      buffer = lines.pop() || '';
      lines.forEach(line => {
        if (line.trim()) {
          handler(line.trim(), socket);
        }
      });
    });
  },
  
  /**
   * Simple HTTP response handler (for testing)
   */
  httpResponse: (statusCode: number, body: string) => (socket: plugins.net.Socket, context: IRouteContext) => {
    const response = [
      `HTTP/1.1 ${statusCode} ${statusCode === 200 ? 'OK' : 'Error'}`,
      'Content-Type: text/plain',
      `Content-Length: ${body.length}`,
      'Connection: close',
      '',
      body
    ].join('\r\n');
    
    socket.write(response);
    socket.end();
  },
  
  /**
   * Block connection immediately
   */
  block: (message?: string) => (socket: plugins.net.Socket, context: IRouteContext) => {
    const finalMessage = message || `Connection blocked from ${context.clientIp}`;
    if (finalMessage) {
      socket.write(finalMessage);
    }
    socket.end();
  },
  
  /**
   * HTTP block response
   */
  httpBlock: (statusCode: number = 403, message?: string) => (socket: plugins.net.Socket, context: IRouteContext) => {
    const defaultMessage = `Access forbidden for ${context.domain || context.clientIp}`;
    const finalMessage = message || defaultMessage;
    
    const response = [
      `HTTP/1.1 ${statusCode} ${finalMessage}`,
      'Content-Type: text/plain',
      `Content-Length: ${finalMessage.length}`,
      'Connection: close',
      '',
      finalMessage
    ].join('\r\n');
    
    socket.write(response);
    socket.end();
  },
  
  /**
   * HTTP redirect handler
   * Now uses the centralized detection module for HTTP parsing
   */
  httpRedirect: (locationTemplate: string, statusCode: number = 301) => (socket: plugins.net.Socket, context: IRouteContext) => {
    const connectionId = ProtocolDetector.createConnectionId({
      socketId: context.connectionId || `${Date.now()}-${Math.random()}`
    });
    
    socket.once('data', async (data) => {
      // Use detection module for parsing
      const detectionResult = await ProtocolDetector.detectWithConnectionTracking(
        data,
        connectionId,
        { extractFullHeaders: false } // We only need method and path
      );
      
      if (detectionResult.protocol === 'http' && detectionResult.connectionInfo.path) {
        const method = detectionResult.connectionInfo.method || 'GET';
        const path = detectionResult.connectionInfo.path || '/';
        
        const domain = context.domain || 'localhost';
        const port = context.port;
        
        let finalLocation = locationTemplate
          .replace('{domain}', domain)
          .replace('{port}', String(port))
          .replace('{path}', path)
          .replace('{clientIp}', context.clientIp);
        
        const message = `Redirecting to ${finalLocation}`;
        const response = [
          `HTTP/1.1 ${statusCode} ${statusCode === 301 ? 'Moved Permanently' : 'Found'}`,
          `Location: ${finalLocation}`,
          'Content-Type: text/plain',
          `Content-Length: ${message.length}`,
          'Connection: close',
          '',
          message
        ].join('\r\n');
        
        socket.write(response);
      } else {
        // Not a valid HTTP request, close connection
        socket.write('HTTP/1.1 400 Bad Request\r\nConnection: close\r\n\r\n');
      }
      
      socket.end();
      // Clean up detection state
      ProtocolDetector.cleanupConnections();
    });
  },
  
  /**
   * HTTP server handler for ACME challenges and other HTTP needs
   * Now uses the centralized detection module for HTTP parsing
   */
  httpServer: (handler: (req: { method: string; url: string; headers: Record<string, string>; body?: string }, res: { status: (code: number) => void; header: (name: string, value: string) => void; send: (data: string) => void; end: () => void }) => void) => (socket: plugins.net.Socket, context: IRouteContext) => {
    let requestParsed = false;
    const connectionId = ProtocolDetector.createConnectionId({
      socketId: context.connectionId || `${Date.now()}-${Math.random()}`
    });
    
    const processData = async (data: Buffer) => {
      if (requestParsed) return; // Only handle the first request
      
      // Use HttpDetector for parsing
      const detectionResult = await ProtocolDetector.detectWithConnectionTracking(
        data,
        connectionId,
        { extractFullHeaders: true }
      );
      
      if (detectionResult.protocol !== 'http' || !detectionResult.isComplete) {
        // Not a complete HTTP request yet
        return;
      }
      
      requestParsed = true;
      const connInfo = detectionResult.connectionInfo;
      
      // Create request object from detection result
      const req = {
        method: connInfo.method || 'GET',
        url: connInfo.path || '/',
        headers: connInfo.headers || {},
        body: detectionResult.remainingBuffer?.toString() || ''
      };
      
      // Create response object
      let statusCode = 200;
      const responseHeaders: Record<string, string> = {};
      let ended = false;
      
      const res = {
        status: (code: number) => {
          statusCode = code;
        },
        header: (name: string, value: string) => {
          responseHeaders[name] = value;
        },
        send: (data: string) => {
          if (ended) return;
          ended = true;
          
          if (!responseHeaders['content-type']) {
            responseHeaders['content-type'] = 'text/plain';
          }
          responseHeaders['content-length'] = String(data.length);
          responseHeaders['connection'] = 'close';
          
          const statusText = statusCode === 200 ? 'OK' : 
                           statusCode === 404 ? 'Not Found' :
                           statusCode === 500 ? 'Internal Server Error' : 'Response';
          
          let response = `HTTP/1.1 ${statusCode} ${statusText}\r\n`;
          for (const [name, value] of Object.entries(responseHeaders)) {
            response += `${name}: ${value}\r\n`;
          }
          response += '\r\n';
          response += data;
          
          socket.write(response);
          socket.end();
        },
        end: () => {
          if (ended) return;
          ended = true;
          socket.write('HTTP/1.1 200 OK\r\nContent-Length: 0\r\nConnection: close\r\n\r\n');
          socket.end();
        }
      };
      
      try {
        handler(req, res);
        // Ensure response is sent even if handler doesn't call send()
        setTimeout(() => {
          if (!ended) {
            res.send('');
          }
        }, 1000);
      } catch (error) {
        if (!ended) {
          res.status(500);
          res.send('Internal Server Error');
        }
      }
    };
    
    socket.on('data', processData);
    
    socket.on('error', () => {
      if (!requestParsed) {
        socket.end();
      }
    });
    
    socket.on('close', () => {
      // Clean up detection state
      ProtocolDetector.cleanupConnections();
    });
  }
};

/**
 * Create an API Gateway route pattern
 * @param domains Domain(s) to match
 * @param apiBasePath Base path for API endpoints (e.g., '/api')
 * @param target Target host and port
 * @param options Additional route options
 * @returns API route configuration
 */
export function createApiGatewayRoute(
  domains: string | string[],
  apiBasePath: string,
  target: { host: string | string[]; port: number },
  options: {
    useTls?: boolean;
    certificate?: 'auto' | { key: string; cert: string };
    addCorsHeaders?: boolean;
    [key: string]: any;
  } = {}
): IRouteConfig {
  // Normalize apiBasePath to ensure it starts with / and doesn't end with /
  const normalizedPath = apiBasePath.startsWith('/') 
    ? apiBasePath 
    : `/${apiBasePath}`;
  
  // Add wildcard to path to match all API endpoints
  const apiPath = normalizedPath.endsWith('/') 
    ? `${normalizedPath}*` 
    : `${normalizedPath}/*`;
  
  // Create base route
  const baseRoute = options.useTls
    ? createHttpsTerminateRoute(domains, target, {
        certificate: options.certificate || 'auto'
      })
    : createHttpRoute(domains, target);
  
  // Add API-specific configurations
  const apiRoute: Partial<IRouteConfig> = {
    match: {
      ...baseRoute.match,
      path: apiPath
    },
    name: options.name || `API Gateway: ${apiPath} -> ${Array.isArray(target.host) ? target.host.join(', ') : target.host}:${target.port}`,
    priority: options.priority || 100 // Higher priority for specific path matching
  };
  
  // Add CORS headers if requested
  if (options.addCorsHeaders) {
    apiRoute.headers = {
      response: {
        'Access-Control-Allow-Origin': '*',
        'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
        'Access-Control-Allow-Headers': 'Content-Type, Authorization',
        'Access-Control-Max-Age': '86400'
      }
    };
  }
  
  return mergeRouteConfigs(baseRoute, apiRoute);
}

/**
 * Create a rate limiting route pattern
 * @param baseRoute Base route to add rate limiting to
 * @param rateLimit Rate limiting configuration
 * @returns Route with rate limiting
 */
export function addRateLimiting(
  baseRoute: IRouteConfig,
  rateLimit: {
    maxRequests: number;
    window: number; // Time window in seconds
    keyBy?: 'ip' | 'path' | 'header';
    headerName?: string; // Required if keyBy is 'header'
    errorMessage?: string;
  }
): IRouteConfig {
  return mergeRouteConfigs(baseRoute, {
    security: {
      rateLimit: {
        enabled: true,
        maxRequests: rateLimit.maxRequests,
        window: rateLimit.window,
        keyBy: rateLimit.keyBy || 'ip',
        headerName: rateLimit.headerName,
        errorMessage: rateLimit.errorMessage || 'Rate limit exceeded. Please try again later.'
      }
    }
  });
}

/**
 * Create a basic authentication route pattern
 * @param baseRoute Base route to add authentication to
 * @param auth Authentication configuration
 * @returns Route with basic authentication
 */
export function addBasicAuth(
  baseRoute: IRouteConfig,
  auth: {
    users: Array<{ username: string; password: string }>;
    realm?: string;
    excludePaths?: string[];
  }
): IRouteConfig {
  return mergeRouteConfigs(baseRoute, {
    security: {
      basicAuth: {
        enabled: true,
        users: auth.users,
        realm: auth.realm || 'Restricted Area',
        excludePaths: auth.excludePaths || []
      }
    }
  });
}

/**
 * Create a JWT authentication route pattern
 * @param baseRoute Base route to add JWT authentication to
 * @param jwt JWT authentication configuration
 * @returns Route with JWT authentication
 */
export function addJwtAuth(
  baseRoute: IRouteConfig,
  jwt: {
    secret: string;
    algorithm?: string;
    issuer?: string;
    audience?: string;
    expiresIn?: number; // Time in seconds
    excludePaths?: string[];
  }
): IRouteConfig {
  return mergeRouteConfigs(baseRoute, {
    security: {
      jwtAuth: {
        enabled: true,
        secret: jwt.secret,
        algorithm: jwt.algorithm || 'HS256',
        issuer: jwt.issuer,
        audience: jwt.audience,
        expiresIn: jwt.expiresIn,
        excludePaths: jwt.excludePaths || []
      }
    }
  });
}
