import * as plugins from '../plugins.js';

/**
 * Configuration for HTTP/3 (QUIC) route augmentation.
 * HTTP/3 is enabled by default on all qualifying HTTPS routes.
 */
export interface IHttp3Config {
  /** Enable HTTP/3 augmentation on qualifying routes (default: true) */
  enabled?: boolean;
  /** QUIC-specific settings applied to all augmented routes */
  quicSettings?: {
    /** QUIC connection idle timeout in ms (default: 30000) */
    maxIdleTimeout?: number;
    /** Max concurrent bidirectional streams per connection (default: 100) */
    maxConcurrentBidiStreams?: number;
    /** Max concurrent unidirectional streams per connection (default: 100) */
    maxConcurrentUniStreams?: number;
    /** Initial congestion window size in bytes */
    initialCongestionWindow?: number;
  };
  /** Alt-Svc header settings */
  altSvc?: {
    /** Port advertised in Alt-Svc header (default: same as listening port) */
    port?: number;
    /** Max age for Alt-Svc advertisement in seconds (default: 86400) */
    maxAge?: number;
  };
  /** UDP session settings */
  udpSettings?: {
    /** Idle timeout for UDP sessions in ms (default: 60000) */
    sessionTimeout?: number;
    /** Max concurrent UDP sessions per source IP (default: 1000) */
    maxSessionsPerIP?: number;
    /** Max accepted datagram size in bytes (default: 65535) */
    maxDatagramSize?: number;
  };
}

/**
 * Check if a route name indicates an email route that should not get HTTP/3.
 */
function isEmailRoute(route: plugins.smartproxy.IRouteConfig): boolean {
  const name = route.name?.toLowerCase() || '';
  return (
    name.startsWith('smtp-') ||
    name.startsWith('submission-') ||
    name.startsWith('smtps-') ||
    name.startsWith('email-')
  );
}

/**
 * Determine if a route qualifies for HTTP/3 augmentation.
 */
export function routeQualifiesForHttp3(
  route: plugins.smartproxy.IRouteConfig,
  globalConfig: IHttp3Config,
): boolean {
  // Check global enable + per-route override
  const globalEnabled = globalConfig.enabled !== false; // default true
  const perRouteOverride = route.action.options?.http3;

  // If per-route explicitly set, use that; otherwise use global
  const shouldAugment =
    perRouteOverride !== undefined ? perRouteOverride : globalEnabled;
  if (!shouldAugment) return false;

  // Must be forward type
  if (route.action.type !== 'forward') return false;

  // Must include port 443
  if (!plugins.smartproxy.portRangeIncludes(route.match.ports, 443)) return false;

  // Must have TLS
  if (!route.action.tls) return false;

  // Skip email routes
  if (isEmailRoute(route)) return false;

  // Skip if already configured with transport 'all' or 'udp'
  if (route.match.transport === 'all' || route.match.transport === 'udp') return false;

  // Skip if already has QUIC config
  if (route.action.udp?.quic) return false;

  return true;
}

/**
 * Augment a single route with HTTP/3 fields.
 * Returns a new route object (does not mutate the original).
 */
export function augmentRouteWithHttp3(
  route: plugins.smartproxy.IRouteConfig,
  config: IHttp3Config,
): plugins.smartproxy.IRouteConfig {
  if (!routeQualifiesForHttp3(route, config)) {
    return route;
  }

  return {
    ...route,
    match: {
      ...route.match,
      transport: 'all' as const,
    },
    action: {
      ...route.action,
      udp: {
        ...(route.action.udp || {}),
        sessionTimeout: config.udpSettings?.sessionTimeout,
        maxSessionsPerIP: config.udpSettings?.maxSessionsPerIP,
        maxDatagramSize: config.udpSettings?.maxDatagramSize,
        quic: {
          enableHttp3: true,
          maxIdleTimeout: config.quicSettings?.maxIdleTimeout,
          maxConcurrentBidiStreams: config.quicSettings?.maxConcurrentBidiStreams,
          maxConcurrentUniStreams: config.quicSettings?.maxConcurrentUniStreams,
          altSvcPort: config.altSvc?.port,
          altSvcMaxAge: config.altSvc?.maxAge ?? 86400,
          initialCongestionWindow: config.quicSettings?.initialCongestionWindow,
        },
      },
    },
  };
}

/**
 * Augment all qualifying routes in an array.
 * Returns a new array (does not mutate originals).
 */
export function augmentRoutesWithHttp3(
  routes: plugins.smartproxy.IRouteConfig[],
  config: IHttp3Config,
): plugins.smartproxy.IRouteConfig[] {
  return routes.map((route) => augmentRouteWithHttp3(route, config));
}
