import type { ConnectionPoolConfig } from './types';

export interface PoolSizeRecommendation {
  min: number;
  max: number;
  idle: number;
}

export class PoolSizeCalculator {
  private static readonly DEFAULT_SIZES: Record<string, PoolSizeRecommendation> = {
    // Service-level defaults
    'data-ingestion': { min: 5, max: 50, idle: 10 },
    'data-pipeline': { min: 3, max: 30, idle: 5 },
    'processing-service': { min: 2, max: 20, idle: 3 },
    'web-api': { min: 2, max: 10, idle: 2 },
    'portfolio-service': { min: 2, max: 15, idle: 3 },
    'strategy-service': { min: 3, max: 25, idle: 5 },
    'execution-service': { min: 2, max: 10, idle: 2 },

    // Handler-level defaults
    'batch-import': { min: 10, max: 100, idle: 20 },
    'real-time': { min: 2, max: 10, idle: 3 },
    analytics: { min: 5, max: 30, idle: 10 },
    reporting: { min: 3, max: 20, idle: 5 },
  };

  static calculate(
    serviceName: string,
    handlerName?: string,
    customConfig?: Partial<ConnectionPoolConfig>
  ): PoolSizeRecommendation {
    // Check for custom configuration first
    if (customConfig?.minConnections && customConfig?.maxConnections) {
      return {
        min: customConfig.minConnections,
        max: customConfig.maxConnections,
        idle: Math.floor((customConfig.minConnections + customConfig.maxConnections) / 4),
      };
    }

    // Try handler-specific sizes first, then service-level
    const key = handlerName || serviceName;
    const recommendation = this.DEFAULT_SIZES[key] || this.DEFAULT_SIZES[serviceName];

    if (recommendation) {
      return { ...recommendation };
    }

    // Fall back to generic defaults
    return {
      min: 2,
      max: 10,
      idle: 3,
    };
  }

  static getOptimalPoolSize(
    expectedConcurrency: number,
    averageQueryTimeMs: number,
    targetLatencyMs: number
  ): number {
    // Little's Law: L = λ * W
    // L = number of connections needed
    // λ = arrival rate (requests per second)
    // W = average time in system (seconds)

    const requestsPerSecond = expectedConcurrency;
    const averageTimeInSystem = averageQueryTimeMs / 1000;

    const minConnections = Math.ceil(requestsPerSecond * averageTimeInSystem);

    // Add buffer for burst traffic (20% overhead)
    const recommendedSize = Math.ceil(minConnections * 1.2);

    // Ensure we meet target latency
    const latencyBasedSize = Math.ceil(
      expectedConcurrency * (averageQueryTimeMs / targetLatencyMs)
    );

    return Math.max(recommendedSize, latencyBasedSize, 2); // Minimum 2 connections
  }
}

// Export convenience functions
export function calculatePoolSize(
  serviceName: string,
  handlerName?: string,
  customConfig?: Partial<ConnectionPoolConfig>
): PoolSizeRecommendation {
  return PoolSizeCalculator.calculate(serviceName, handlerName, customConfig);
}

export function getServicePoolSize(serviceName: string): PoolSizeRecommendation {
  return PoolSizeCalculator.calculate(serviceName);
}

export function getHandlerPoolSize(
  serviceName: string,
  handlerName: string
): PoolSizeRecommendation {
  return PoolSizeCalculator.calculate(serviceName, handlerName);
}
