/**
 * Performance Monitor
 *
 * Monitors and collects performance metrics for HTTP requests.
 * Provides detailed analytics on response times, success rates, and optimization opportunities.
 */

import { EventEmitter } from 'events'

export interface PerformanceMetrics {
  /** Total number of requests */
  totalRequests: number

  /** Number of successful requests */
  successfulRequests: number

  /** Number of failed requests */
  failedRequests: number

  /** Average response time in milliseconds */
  averageResponseTime: number

  /** 95th percentile response time */
  p95ResponseTime: number

  /** 99th percentile response time */
  p99ResponseTime: number

  /** Success rate (0-1) */
  successRate: number

  /** Platform-specific metrics */
  platformMetrics: Record<string, PlatformMetrics>

  /** Account-specific metrics */
  accountMetrics: Record<string, AccountMetrics>

  /** Time period for these metrics */
  timePeriod: {
    start: Date
    end: Date
    durationMs: number
  }
}

export interface PlatformMetrics {
  /** Platform identifier */
  platform: string

  /** Total requests to this platform */
  totalRequests: number

  /** Successful requests */
  successfulRequests: number

  /** Average response time */
  averageResponseTime: number

  /** Error rate */
  errorRate: number

  /** Most common errors */
  commonErrors: Array<{ error: string; count: number }>
}

export interface AccountMetrics {
  /** Account identifier */
  accountId: string

  /** Platform this account belongs to */
  platform: string

  /** Total requests for this account */
  totalRequests: number

  /** Authentication success rate */
  authSuccessRate: number

  /** Average signature time */
  averageSignatureTime: number

  /** Proxy usage count */
  proxyUsageCount: number
}

export interface RequestPerformanceData {
  /** Request identifier */
  requestId: string

  /** Platform identifier */
  platform: string

  /** Account identifier */
  accountId: string

  /** Start timestamp */
  startTime: Date

  /** End timestamp */
  endTime: Date

  /** Total duration in milliseconds */
  duration: number

  /** Network latency in milliseconds */
  networkLatency?: number

  /** Processing time in milliseconds */
  processingTime?: number

  /** Whether request was successful */
  success: boolean

  /** HTTP status code */
  statusCode: number

  /** Response size in bytes */
  responseSize: number

  /** Whether proxy was used */
  usedProxy: boolean

  /** Whether response came from cache */
  cacheHit?: boolean

  /** Retry count */
  retryCount?: number

  /** Error information if failed */
  error?: {
    type: string
    message: string
    code: string
  }
}

export interface PerformanceOptimizationSuggestion {
  /** Suggestion type */
  type: 'caching' | 'proxy' | 'batching' | 'timeout' | 'retry'

  /** Suggestion priority */
  priority: 'low' | 'medium' | 'high' | 'critical'

  /** Description of the suggestion */
  description: string

  /** Estimated performance improvement */
  estimatedImprovement: number

  /** Platforms affected */
  affectedPlatforms: string[]

  /** Implementation difficulty */
  difficulty: 'easy' | 'medium' | 'hard'
}

export class PerformanceMonitor extends EventEmitter {
  private requests: RequestPerformanceData[] = []
  private readonly maxRequestHistory = 10000
  private readonly metricsWindow = 24 * 60 * 60 * 1000 // 24 hours
  private platformMetrics: Map<string, PlatformMetrics> = new Map()
  private accountMetrics: Map<string, AccountMetrics> = new Map()
  private performanceTargets = {
    maxResponseTime: 100, // 100ms target
    minSuccessRate: 0.999, // 99.9% success rate
    maxErrorRate: 0.001, // 0.1% error rate
  }

  constructor() {
    super()
    this.setupCleanupInterval()
  }

  /**
   * Record request performance data
   */
  recordRequest(data: RequestPerformanceData): void {
    this.requests.push(data)

    // Update platform metrics
    this.updatePlatformMetrics(data)

    // Update account metrics
    this.updateAccountMetrics(data)

    // Emit performance event
    this.emit('request:recorded', data)

    // Check for performance issues
    this.checkPerformanceIssues(data)

    // Cleanup old requests if needed
    if (this.requests.length > this.maxRequestHistory) {
      this.requests = this.requests.slice(-this.maxRequestHistory)
    }
  }

  /**
   * Get current performance metrics
   */
  getMetrics(timePeriod?: { start: Date; end: Date }): PerformanceMetrics {
    const now = new Date()
    const period = timePeriod || {
      start: new Date(now.getTime() - this.metricsWindow),
      end: now,
    }

    const relevantRequests = this.requests.filter(req => req.startTime >= period.start && req.startTime <= period.end)

    if (relevantRequests.length === 0) {
      return this.getEmptyMetrics(period)
    }

    const totalRequests = relevantRequests.length
    const successfulRequests = relevantRequests.filter(req => req.success).length
    const responseTimes = relevantRequests.map(req => req.duration).sort((a, b) => a - b)

    return {
      totalRequests,
      successfulRequests,
      failedRequests: totalRequests - successfulRequests,
      averageResponseTime: responseTimes.reduce((sum, time) => sum + time, 0) / responseTimes.length,
      p95ResponseTime: responseTimes[Math.floor(responseTimes.length * 0.95)] || 0,
      p99ResponseTime: responseTimes[Math.floor(responseTimes.length * 0.99)] || 0,
      successRate: successfulRequests / totalRequests,
      platformMetrics: Object.fromEntries(this.platformMetrics),
      accountMetrics: Object.fromEntries(this.accountMetrics),
      timePeriod: {
        start: period.start,
        end: period.end,
        durationMs: period.end.getTime() - period.start.getTime(),
      },
    }
  }

  /**
   * Get performance optimization suggestions
   */
  getOptimizationSuggestions(): PerformanceOptimizationSuggestion[] {
    const metrics = this.getMetrics()
    const suggestions: PerformanceOptimizationSuggestion[] = []

    // Check response time performance
    if (metrics.averageResponseTime > this.performanceTargets.maxResponseTime) {
      suggestions.push({
        type: 'caching',
        priority: 'high',
        description: `Average response time (${metrics.averageResponseTime.toFixed(1)}ms) exceeds target (${
          this.performanceTargets.maxResponseTime
        }ms). Consider implementing response caching.`,
        estimatedImprovement: 0.6,
        affectedPlatforms: Object.keys(metrics.platformMetrics),
        difficulty: 'medium',
      })
    }

    // Check success rate
    if (metrics.successRate < this.performanceTargets.minSuccessRate) {
      suggestions.push({
        type: 'retry',
        priority: 'critical',
        description: `Success rate (${(metrics.successRate * 100).toFixed(2)}%) is below target (${(
          this.performanceTargets.minSuccessRate * 100
        ).toFixed(1)}%). Review retry logic and error handling.`,
        estimatedImprovement: 0.3,
        affectedPlatforms: Object.keys(metrics.platformMetrics),
        difficulty: 'medium',
      })
    }

    // Check for slow platforms
    for (const [platform, platformMetrics] of Object.entries(metrics.platformMetrics)) {
      if (platformMetrics.averageResponseTime > this.performanceTargets.maxResponseTime * 1.5) {
        suggestions.push({
          type: 'proxy',
          priority: 'medium',
          description: `Platform ${platform} has slow response times (${platformMetrics.averageResponseTime.toFixed(
            1,
          )}ms). Consider dedicated proxy or connection optimization.`,
          estimatedImprovement: 0.4,
          affectedPlatforms: [platform],
          difficulty: 'easy',
        })
      }
    }

    // Check for batch opportunities
    const recentRequests = this.requests.slice(-100)
    const platformCounts = new Map<string, number>()
    recentRequests.forEach(req => {
      platformCounts.set(req.platform, (platformCounts.get(req.platform) || 0) + 1)
    })

    for (const [platform, count] of platformCounts) {
      if (count > 5) {
        suggestions.push({
          type: 'batching',
          priority: 'low',
          description: `Platform ${platform} has ${count} recent requests. Consider batching similar requests for better performance.`,
          estimatedImprovement: 0.2,
          affectedPlatforms: [platform],
          difficulty: 'hard',
        })
      }
    }

    return suggestions.sort((a, b) => {
      const priorityOrder = { critical: 4, high: 3, medium: 2, low: 1 }
      return priorityOrder[b.priority] - priorityOrder[a.priority]
    })
  }

  /**
   * Reset all metrics
   */
  resetMetrics(): void {
    this.requests = []
    this.platformMetrics.clear()
    this.accountMetrics.clear()
    this.emit('metrics:reset')
  }

  /**
   * Get performance health status
   */
  getHealthStatus(): {
    status: 'healthy' | 'degraded' | 'unhealthy'
    issues: string[]
    recommendations: string[]
  } {
    const metrics = this.getMetrics()
    const issues: string[] = []
    const recommendations: string[] = []

    let status: 'healthy' | 'degraded' | 'unhealthy' = 'healthy'

    // Check response time
    if (metrics.averageResponseTime > this.performanceTargets.maxResponseTime * 2) {
      status = 'unhealthy'
      issues.push(`Response time severely degraded: ${metrics.averageResponseTime.toFixed(1)}ms`)
      recommendations.push('Investigate network connectivity and consider proxy optimization')
    } else if (metrics.averageResponseTime > this.performanceTargets.maxResponseTime) {
      status = 'degraded'
      issues.push(`Response time above target: ${metrics.averageResponseTime.toFixed(1)}ms`)
      recommendations.push('Consider enabling response caching')
    }

    // Check success rate
    if (metrics.successRate < 0.95) {
      status = 'unhealthy'
      issues.push(`Success rate critically low: ${(metrics.successRate * 100).toFixed(1)}%`)
      recommendations.push('Review error handling and increase retry attempts')
    } else if (metrics.successRate < this.performanceTargets.minSuccessRate) {
      if (status === 'healthy') status = 'degraded'
      issues.push(`Success rate below target: ${(metrics.successRate * 100).toFixed(2)}%`)
      recommendations.push('Monitor platform health and implement circuit breakers')
    }

    return { status, issues, recommendations }
  }

  // Private helper methods

  private updatePlatformMetrics(data: RequestPerformanceData): void {
    const existing = this.platformMetrics.get(data.platform) || {
      platform: data.platform,
      totalRequests: 0,
      successfulRequests: 0,
      averageResponseTime: 0,
      errorRate: 0,
      commonErrors: [],
    }

    existing.totalRequests++
    if (data.success) {
      existing.successfulRequests++
    }

    // Update average response time (rolling average)
    existing.averageResponseTime =
      (existing.averageResponseTime * (existing.totalRequests - 1) + data.duration) / existing.totalRequests
    existing.errorRate = (existing.totalRequests - existing.successfulRequests) / existing.totalRequests

    // Track common errors
    if (!data.success && data.error) {
      const errorEntry = existing.commonErrors.find(e => e.error === data.error!.message)
      if (errorEntry) {
        errorEntry.count++
      } else {
        existing.commonErrors.push({ error: data.error.message, count: 1 })
      }
      // Keep only top 5 errors
      existing.commonErrors.sort((a, b) => b.count - a.count).slice(0, 5)
    }

    this.platformMetrics.set(data.platform, existing)
  }

  private updateAccountMetrics(data: RequestPerformanceData): void {
    const existing = this.accountMetrics.get(data.accountId) || {
      accountId: data.accountId,
      platform: data.platform,
      totalRequests: 0,
      authSuccessRate: 1.0,
      averageSignatureTime: 0,
      proxyUsageCount: 0,
    }

    existing.totalRequests++
    if (data.usedProxy) {
      existing.proxyUsageCount++
    }

    // Update average signature time if available
    if (data.processingTime) {
      existing.averageSignatureTime =
        (existing.averageSignatureTime * (existing.totalRequests - 1) + data.processingTime) / existing.totalRequests
    }

    this.accountMetrics.set(data.accountId, existing)
  }

  private checkPerformanceIssues(data: RequestPerformanceData): void {
    // Alert on slow requests
    if (data.duration > this.performanceTargets.maxResponseTime * 3) {
      this.emit('performance:alert', {
        type: 'slow_request',
        requestId: data.requestId,
        platform: data.platform,
        duration: data.duration,
        threshold: this.performanceTargets.maxResponseTime * 3,
      })
    }

    // Alert on authentication failures
    if (!data.success && data.error?.type === 'auth_error') {
      this.emit('performance:alert', {
        type: 'auth_failure',
        requestId: data.requestId,
        platform: data.platform,
        accountId: data.accountId,
        error: data.error,
      })
    }

    // Alert on proxy issues
    if (data.usedProxy && !data.success && data.error?.type === 'network_error') {
      this.emit('performance:alert', {
        type: 'proxy_issue',
        requestId: data.requestId,
        platform: data.platform,
        error: data.error,
      })
    }
  }

  private getEmptyMetrics(period: { start: Date; end: Date }): PerformanceMetrics {
    return {
      totalRequests: 0,
      successfulRequests: 0,
      failedRequests: 0,
      averageResponseTime: 0,
      p95ResponseTime: 0,
      p99ResponseTime: 0,
      successRate: 0,
      platformMetrics: {},
      accountMetrics: {},
      timePeriod: {
        start: period.start,
        end: period.end,
        durationMs: period.end.getTime() - period.start.getTime(),
      },
    }
  }

  private setupCleanupInterval(): void {
    // Clean up old requests every hour
    setInterval(
      () => {
        const cutoff = new Date(Date.now() - this.metricsWindow)
        this.requests = this.requests.filter(req => req.startTime > cutoff)
      },
      60 * 60 * 1000,
    )
  }
}

/**
 * Global performance monitor instance
 */
export const globalPerformanceMonitor = new PerformanceMonitor()

/**
 * Create performance monitor with custom configuration
 */
export function createPerformanceMonitor(config?: {
  maxRequestHistory?: number
  metricsWindow?: number
  performanceTargets?: {
    maxResponseTime?: number
    minSuccessRate?: number
    maxErrorRate?: number
  }
}): PerformanceMonitor {
  const monitor = new PerformanceMonitor()

  if (config?.performanceTargets) {
    ;(monitor as any).performanceTargets = {
      ...(monitor as any).performanceTargets,
      ...config.performanceTargets,
    }
  }

  return monitor
}

export default PerformanceMonitor
