/**
 * Hedging Account Pool Implementation
 *
 * Manages pools of accounts for hedging operations across multiple platforms.
 * Provides load balancing, failover, and health monitoring for Delta-neutral strategies.
 */

import { Platform, Account } from '@/types/credential'
import { AccountStatus } from './AccountStatus'

// ============================================================================
// Types and Interfaces
// ============================================================================

export interface HedgingAccountPoolConfig {
  /**
   * Primary accounts for normal hedging operations
   */
  primaryAccounts: string[]

  /**
   * Backup accounts for failover scenarios
   */
  backupAccounts: string[]

  /**
   * Test accounts for development and testing
   */
  testAccounts: string[]

  /**
   * Load balancing strategy
   */
  loadBalanceStrategy: LoadBalanceStrategy

  /**
   * Health check configuration
   */
  healthCheck: {
    enabled: boolean
    intervalMs: number
    failureThreshold: number
  }

  /**
   * Failover configuration
   */
  failover: {
    enabled: boolean
    autoFailoverTimeoutMs: number
    maxFailoverAttempts: number
  }
}

export enum LoadBalanceStrategy {
  ROUND_ROBIN = 'round-robin',
  RANDOM = 'random',
  WEIGHTED = 'weighted',
  LEAST_USED = 'least-used'
}

export interface AccountPoolStatus {
  platform: Platform
  totalAccounts: number
  activeAccounts: number
  failedAccounts: number
  lastHealthCheck: Date
  loadBalanceIndex: number
}

export interface AccountSelection {
  accountId: string
  platform: Platform
  selectionReason: string
  isFailover: boolean
  poolStatus: AccountPoolStatus
}

// ============================================================================
// Main Implementation
// ============================================================================

export class HedgingAccountPool {
  private config: HedgingAccountPoolConfig
  private accountStatuses: Map<string, AccountStatus> = new Map()
  private loadBalanceIndexes: Map<Platform, number> = new Map()
  private healthCheckInterval?: NodeJS.Timeout
  private accountUsageStats: Map<string, number> = new Map()

  constructor(config: HedgingAccountPoolConfig) {
    this.config = config
    this.initializeLoadBalanceIndexes()

    if (config.healthCheck.enabled) {
      this.startHealthChecking()
    }
  }

  // ============================================================================
  // Account Selection for Hedging Operations
  // ============================================================================

  /**
   * Select best account for hedging operation
   */
  async selectAccount(platform: Platform, criteria?: AccountSelectionCriteria): Promise<AccountSelection> {
    const availableAccounts = this.getAvailableAccounts(platform)

    if (availableAccounts.length === 0) {
      throw new Error(`No available accounts for platform: ${platform}`)
    }

    let selectedAccountId: string
    let isFailover = false
    let selectionReason: string

    // Try primary accounts first
    const primaryAccounts = availableAccounts.filter(id =>
      this.config.primaryAccounts.includes(id)
    )

    if (primaryAccounts.length > 0) {
      selectedAccountId = this.selectFromPool(primaryAccounts, platform)
      selectionReason = `Primary account selected via ${this.config.loadBalanceStrategy}`
    } else {
      // Failover to backup accounts
      const backupAccounts = availableAccounts.filter(id =>
        this.config.backupAccounts.includes(id)
      )

      if (backupAccounts.length > 0) {
        selectedAccountId = this.selectFromPool(backupAccounts, platform)
        selectionReason = `Failover to backup account via ${this.config.loadBalanceStrategy}`
        isFailover = true
      } else {
        throw new Error(`No primary or backup accounts available for platform: ${platform}`)
      }
    }

    // Update usage statistics
    const currentUsage = this.accountUsageStats.get(selectedAccountId) || 0
    this.accountUsageStats.set(selectedAccountId, currentUsage + 1)

    return {
      accountId: selectedAccountId,
      platform,
      selectionReason,
      isFailover,
      poolStatus: this.getPoolStatus(platform)
    }
  }

  /**
   * Select multiple accounts for distributed hedging
   */
  async selectMultipleAccounts(
    platform: Platform,
    count: number,
    criteria?: AccountSelectionCriteria
  ): Promise<AccountSelection[]> {
    const availableAccounts = this.getAvailableAccounts(platform)

    if (availableAccounts.length < count) {
      throw new Error(`Insufficient accounts available. Requested: ${count}, Available: ${availableAccounts.length}`)
    }

    const selections: AccountSelection[] = []
    const usedAccounts = new Set<string>()

    for (let i = 0; i < count; i++) {
      const availableForSelection = availableAccounts.filter(id => !usedAccounts.has(id))

      if (availableForSelection.length === 0) {
        break
      }

      const accountId = this.selectFromPool(availableForSelection, platform)
      usedAccounts.add(accountId)

      const isPrimary = this.config.primaryAccounts.includes(accountId)

      selections.push({
        accountId,
        platform,
        selectionReason: `Multi-account selection ${i + 1}/${count} - ${isPrimary ? 'primary' : 'backup'}`,
        isFailover: !isPrimary,
        poolStatus: this.getPoolStatus(platform)
      })

      // Update usage statistics
      const currentUsage = this.accountUsageStats.get(accountId) || 0
      this.accountUsageStats.set(accountId, currentUsage + 1)
    }

    return selections
  }

  // ============================================================================
  // Account Health Management
  // ============================================================================

  /**
   * Register account status
   */
  registerAccount(accountId: string, platform: Platform): void {
    if (!this.accountStatuses.has(accountId)) {
      this.accountStatuses.set(accountId, new AccountStatus(accountId, platform))
    }
  }

  /**
   * Update account health status
   */
  updateAccountHealth(accountId: string, isHealthy: boolean, details?: any): void {
    const status = this.accountStatuses.get(accountId)
    if (status) {
      status.updateHealth(isHealthy, details)
    }
  }

  /**
   * Mark account as failed
   */
  markAccountFailed(accountId: string, error: Error): void {
    const status = this.accountStatuses.get(accountId)
    if (status) {
      status.recordFailure(error)
    }
  }

  /**
   * Mark account operation as successful
   */
  markAccountSuccess(accountId: string): void {
    const status = this.accountStatuses.get(accountId)
    if (status) {
      status.recordSuccess()
    }
  }

  // ============================================================================
  // Pool Management
  // ============================================================================

  /**
   * Get pool status for platform
   */
  getPoolStatus(platform: Platform): AccountPoolStatus {
    const allAccounts = [...this.config.primaryAccounts, ...this.config.backupAccounts]
      .filter(accountId => {
        const status = this.accountStatuses.get(accountId)
        return status && status.platform === platform
      })

    const activeAccounts = allAccounts.filter(accountId => {
      const status = this.accountStatuses.get(accountId)
      return status && status.isActive()
    })

    const failedAccounts = allAccounts.filter(accountId => {
      const status = this.accountStatuses.get(accountId)
      return status && !status.isActive()
    })

    return {
      platform,
      totalAccounts: allAccounts.length,
      activeAccounts: activeAccounts.length,
      failedAccounts: failedAccounts.length,
      lastHealthCheck: new Date(),
      loadBalanceIndex: this.loadBalanceIndexes.get(platform) || 0
    }
  }

  /**
   * Get detailed pool statistics
   */
  getPoolStatistics(): PoolStatistics {
    const platforms = [Platform.PACIFICA, Platform.ASTER, Platform.BINANCE]
    const platformStats: Record<Platform, AccountPoolStatus> = {} as any

    platforms.forEach(platform => {
      platformStats[platform] = this.getPoolStatus(platform)
    })

    const totalUsage = Array.from(this.accountUsageStats.values()).reduce((sum, usage) => sum + usage, 0)

    return {
      platformStats,
      loadBalanceStrategy: this.config.loadBalanceStrategy,
      totalUsage,
      accountUsageStats: new Map(this.accountUsageStats),
      healthCheckEnabled: this.config.healthCheck.enabled,
      failoverEnabled: this.config.failover.enabled
    }
  }

  // ============================================================================
  // Private Helper Methods
  // ============================================================================

  private getAvailableAccounts(platform: Platform): string[] {
    const allAccounts = [...this.config.primaryAccounts, ...this.config.backupAccounts]

    return allAccounts.filter(accountId => {
      const status = this.accountStatuses.get(accountId)
      return status && status.platform === platform && status.isActive()
    })
  }

  private selectFromPool(accountIds: string[], platform: Platform): string {
    if (accountIds.length === 0) {
      throw new Error('No accounts available for selection')
    }

    if (accountIds.length === 1) {
      return accountIds[0]
    }

    switch (this.config.loadBalanceStrategy) {
      case LoadBalanceStrategy.ROUND_ROBIN:
        return this.selectRoundRobin(accountIds, platform)

      case LoadBalanceStrategy.RANDOM:
        return this.selectRandom(accountIds)

      case LoadBalanceStrategy.WEIGHTED:
        return this.selectWeighted(accountIds)

      case LoadBalanceStrategy.LEAST_USED:
        return this.selectLeastUsed(accountIds)

      default:
        return this.selectRoundRobin(accountIds, platform)
    }
  }

  private selectRoundRobin(accountIds: string[], platform: Platform): string {
    const currentIndex = this.loadBalanceIndexes.get(platform) || 0
    const selectedIndex = currentIndex % accountIds.length

    this.loadBalanceIndexes.set(platform, selectedIndex + 1)

    return accountIds[selectedIndex]
  }

  private selectRandom(accountIds: string[]): string {
    const randomIndex = Math.floor(Math.random() * accountIds.length)
    return accountIds[randomIndex]
  }

  private selectWeighted(accountIds: string[]): string {
    // Simple weighted selection based on inverse failure rate
    const weights = accountIds.map(accountId => {
      const status = this.accountStatuses.get(accountId)
      const failureRate = status ? status.getFailureRate() : 0
      return Math.max(0.1, 1 - failureRate) // Minimum weight of 0.1
    })

    const totalWeight = weights.reduce((sum, weight) => sum + weight, 0)
    let random = Math.random() * totalWeight

    for (let i = 0; i < accountIds.length; i++) {
      random -= weights[i]
      if (random <= 0) {
        return accountIds[i]
      }
    }

    return accountIds[accountIds.length - 1]
  }

  private selectLeastUsed(accountIds: string[]): string {
    let leastUsedAccount = accountIds[0]
    let minUsage = this.accountUsageStats.get(leastUsedAccount) || 0

    for (const accountId of accountIds) {
      const usage = this.accountUsageStats.get(accountId) || 0
      if (usage < minUsage) {
        minUsage = usage
        leastUsedAccount = accountId
      }
    }

    return leastUsedAccount
  }

  private initializeLoadBalanceIndexes(): void {
    this.loadBalanceIndexes.set(Platform.PACIFICA, 0)
    this.loadBalanceIndexes.set(Platform.ASTER, 0)
    this.loadBalanceIndexes.set(Platform.BINANCE, 0)
  }

  private startHealthChecking(): void {
    this.healthCheckInterval = setInterval(() => {
      this.performHealthCheck()
    }, this.config.healthCheck.intervalMs)
  }

  private async performHealthCheck(): Promise<void> {
    const allAccounts = [...this.config.primaryAccounts, ...this.config.backupAccounts]

    for (const accountId of allAccounts) {
      const status = this.accountStatuses.get(accountId)
      if (status) {
        // Simple health check - could be enhanced with actual API calls
        const isHealthy = status.getFailureRate() < 0.5 // Less than 50% failure rate
        status.updateHealth(isHealthy, { lastHealthCheck: new Date() })
      }
    }
  }

  /**
   * Cleanup resources
   */
  destroy(): void {
    if (this.healthCheckInterval) {
      clearInterval(this.healthCheckInterval)
      this.healthCheckInterval = undefined
    }
  }
}

// ============================================================================
// Supporting Types
// ============================================================================

export interface AccountSelectionCriteria {
  preferPrimary?: boolean
  excludeAccounts?: string[]
  minHealthScore?: number
  maxUsageCount?: number
}

export interface PoolStatistics {
  platformStats: Record<Platform, AccountPoolStatus>
  loadBalanceStrategy: LoadBalanceStrategy
  totalUsage: number
  accountUsageStats: Map<string, number>
  healthCheckEnabled: boolean
  failoverEnabled: boolean
}