/**
 * Integration Test for Hedging Workflows
 *
 * Tests end-to-end hedging operations including account pool management,
 * cross-platform distribution, and delta-neutral strategies.
 */

import { CredentialManager } from '@/core/credential-manager/CredentialManager'
import { Platform } from '@/types/credential'
import { TradingOperation } from '@/core/credential-manager/TradingIntegration'
import { LoadBalanceStrategy } from '@/core/credential-manager/HedgingAccountPool'

describe('Hedging Workflows Integration Test', () => {
  let credentialManager: CredentialManager

  beforeEach(async () => {
    const config = {
      accounts: [
        // Pacifica accounts for hedging
        {
          id: 'pac-hedge-1',
          name: 'Pacifica Hedge 1',
          platform: Platform.PACIFICA,
          enabled: true,
          credentials: {
            type: 'ed25519' as const,
            privateKey: 'f26670e2ca334117f8859f9f32e50251641953a30b54f6ffcf82db836cfdfea5'
          }
        },
        {
          id: 'pac-hedge-2',
          name: 'Pacifica Hedge 2',
          platform: Platform.PACIFICA,
          enabled: true,
          credentials: {
            type: 'ed25519' as const,
            privateKey: 'a26670e2ca334117f8859f9f32e50251641953a30b54f6ffcf82db836cfdfea5'
          }
        },
        {
          id: 'pac-backup-1',
          name: 'Pacifica Backup 1',
          platform: Platform.PACIFICA,
          enabled: true,
          credentials: {
            type: 'ed25519' as const,
            privateKey: 'b26670e2ca334117f8859f9f32e50251641953a30b54f6ffcf82db836cfdfea5'
          }
        },
        // Aster accounts for hedging
        {
          id: 'ast-hedge-1',
          name: 'Aster Hedge 1',
          platform: Platform.ASTER,
          enabled: true,
          credentials: {
            type: 'secp256k1' as const,
            privateKey: '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef'
          }
        },
        {
          id: 'ast-hedge-2',
          name: 'Aster Hedge 2',
          platform: Platform.ASTER,
          enabled: true,
          credentials: {
            type: 'secp256k1' as const,
            privateKey: '0x2234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef'
          }
        },
        // Binance accounts for hedging
        {
          id: 'bnb-hedge-1',
          name: 'Binance Hedge 1',
          platform: Platform.BINANCE,
          enabled: true,
          credentials: {
            type: 'hmac' as const,
            apiKey: 'binance-api-key-1',
            secretKey: 'binance-secret-key-1'
          }
        },
        {
          id: 'bnb-hedge-2',
          name: 'Binance Hedge 2',
          platform: Platform.BINANCE,
          enabled: true,
          credentials: {
            type: 'hmac' as const,
            apiKey: 'binance-api-key-2',
            secretKey: 'binance-secret-key-2'
          }
        }
      ],
      hedging: {
        platforms: {
          [Platform.PACIFICA]: {
            enabled: true,
            primaryAccounts: ['pac-hedge-1', 'pac-hedge-2'],
            backupAccounts: ['pac-backup-1'],
            loadBalanceStrategy: LoadBalanceStrategy.ROUND_ROBIN,
            healthCheckInterval: 10000,
            failoverThreshold: 2
          },
          [Platform.ASTER]: {
            enabled: true,
            primaryAccounts: ['ast-hedge-1', 'ast-hedge-2'],
            backupAccounts: [],
            loadBalanceStrategy: LoadBalanceStrategy.WEIGHTED,
            healthCheckInterval: 10000,
            failoverThreshold: 2
          },
          [Platform.BINANCE]: {
            enabled: true,
            primaryAccounts: ['bnb-hedge-1', 'bnb-hedge-2'],
            backupAccounts: [],
            loadBalanceStrategy: LoadBalanceStrategy.LEAST_USED,
            healthCheckInterval: 10000,
            failoverThreshold: 2
          }
        },
        hedging: {
          enableCrossplatformBalancing: true,
          maxAccountsPerPlatform: 5,
          reservationTimeoutMs: 30000
        }
      }
    }

    credentialManager = new CredentialManager()
    await credentialManager.loadConfiguration(config)
  })

  afterEach(async () => {
    await credentialManager.shutdown()
  })

  describe('Basic Hedging Operations', () => {
    test('should distribute hedge orders across multiple platforms', async () => {
      const hedgeVolume = 100000 // $100k to hedge
      const platforms = [Platform.PACIFICA, Platform.ASTER, Platform.BINANCE]

      const distribution = await credentialManager.getHedgingAccountDistribution(
        hedgeVolume,
        platforms
      )

      // Should distribute across all three platforms
      expect(distribution.size).toBe(3)
      expect(distribution.has(Platform.PACIFICA)).toBe(true)
      expect(distribution.has(Platform.ASTER)).toBe(true)
      expect(distribution.has(Platform.BINANCE)).toBe(true)

      // Each platform should have at least one account
      for (const [platform, accounts] of distribution) {
        expect(accounts.length).toBeGreaterThan(0)
        expect(accounts.every(a => a.platform === platform)).toBe(true)
      }
    })

    test('should handle cross-platform account selection for hedging', async () => {
      const platforms = [Platform.PACIFICA, Platform.ASTER, Platform.BINANCE]
      const accountCount = 4

      const accounts = await credentialManager.selectAccountsAcrossPlatforms(
        platforms,
        accountCount
      )

      expect(accounts.length).toBeLessThanOrEqual(accountCount)

      // Should select from multiple platforms
      const selectedPlatforms = new Set(accounts.map(a => a.platform))
      expect(selectedPlatforms.size).toBeGreaterThan(1)

      // All selected accounts should be from requested platforms
      expect(accounts.every(a => platforms.includes(a.platform))).toBe(true)
    })

    test('should execute simultaneous hedge trades across platforms', async () => {
      const hedgeTrades = [
        {
          operation: TradingOperation.PLACE_ORDER,
          platform: Platform.PACIFICA,
          parameters: {
            symbol: 'SOL/USDC',
            side: 'buy' as const,
            quantity: 100,
            type: 'market' as const
          }
        },
        {
          operation: TradingOperation.PLACE_ORDER,
          platform: Platform.ASTER,
          parameters: {
            symbol: 'ETH/USDC',
            side: 'sell' as const,
            quantity: 50,
            type: 'market' as const
          }
        },
        {
          operation: TradingOperation.PLACE_ORDER,
          platform: Platform.BINANCE,
          parameters: {
            symbol: 'BTCUSDT',
            side: 'buy' as const,
            quantity: 0.1,
            type: 'limit' as const,
            price: 50000
          }
        }
      ]

      const startTime = Date.now()
      const results = await credentialManager.signBatchTradingRequests(hedgeTrades)
      const duration = Date.now() - startTime

      // All trades should succeed
      expect(results).toHaveLength(3)
      expect(results.every(r => r.success)).toBe(true)

      // Should complete within reasonable time for hedging (critical for arbitrage)
      expect(duration).toBeLessThan(200)

      // Each result should use different platform
      const resultPlatforms = results.map(r => r.selectedAccount.platform)
      expect(resultPlatforms).toContain(Platform.PACIFICA)
      expect(resultPlatforms).toContain(Platform.ASTER)
      expect(resultPlatforms).toContain(Platform.BINANCE)
    })
  })

  describe('Load Balancing Strategies', () => {
    test('should implement round-robin strategy for Pacifica', async () => {
      const requests = Array.from({ length: 6 }, () => ({
        operation: TradingOperation.GET_BALANCE,
        platform: Platform.PACIFICA,
        parameters: {}
      }))

      const results = []
      for (const request of requests) {
        const result = await credentialManager.signTradingRequest(request)
        results.push(result)
      }

      const accountIds = results.map(r => r.selectedAccount.accountId)

      // Should cycle through primary accounts in round-robin fashion
      expect(accountIds[0]).toBe('pac-hedge-1')
      expect(accountIds[1]).toBe('pac-hedge-2')
      expect(accountIds[2]).toBe('pac-hedge-1')
      expect(accountIds[3]).toBe('pac-hedge-2')
    })

    test('should implement weighted strategy for Aster', async () => {
      const requests = Array.from({ length: 10 }, () => ({
        operation: TradingOperation.GET_POSITIONS,
        platform: Platform.ASTER,
        parameters: {}
      }))

      const results = []
      for (const request of requests) {
        const result = await credentialManager.signTradingRequest(request)
        results.push(result)
      }

      const accountIds = results.map(r => r.selectedAccount.accountId)
      const accountUsage = accountIds.reduce((acc, id) => {
        acc[id] = (acc[id] || 0) + 1
        return acc
      }, {} as Record<string, number>)

      // Both accounts should be used (weighted distribution)
      expect(Object.keys(accountUsage).length).toBeGreaterThan(1)
      expect(accountUsage['ast-hedge-1']).toBeGreaterThan(0)
      expect(accountUsage['ast-hedge-2']).toBeGreaterThan(0)
    })

    test('should implement least-used strategy for Binance', async () => {
      // First, make some requests to create usage history
      const initialRequests = [
        {
          operation: TradingOperation.GET_BALANCE,
          platform: Platform.BINANCE,
          parameters: {}
        }
      ]

      await credentialManager.signTradingRequest(initialRequests[0])

      // Now make more requests - should prefer the less-used account
      const requests = Array.from({ length: 4 }, () => ({
        operation: TradingOperation.GET_POSITIONS,
        platform: Platform.BINANCE,
        parameters: {}
      }))

      const results = []
      for (const request of requests) {
        const result = await credentialManager.signTradingRequest(request)
        results.push(result)
      }

      const accountIds = results.map(r => r.selectedAccount.accountId)

      // Should use both accounts (least-used balancing)
      const uniqueAccounts = new Set(accountIds)
      expect(uniqueAccounts.size).toBeGreaterThan(1)
    })
  })

  describe('Failover and Recovery', () => {
    test('should failover to backup accounts when primary accounts fail', async () => {
      // Mark primary Pacifica accounts as failed
      credentialManager.updateAccountAfterTrade('pac-hedge-1', {
        success: false,
        error: 'Connection timeout',
        timestamp: new Date()
      })

      credentialManager.updateAccountAfterTrade('pac-hedge-2', {
        success: false,
        error: 'API error',
        timestamp: new Date()
      })

      // Should failover to backup account
      const request = {
        operation: TradingOperation.PLACE_ORDER,
        platform: Platform.PACIFICA,
        parameters: {
          symbol: 'SOL/USDC',
          side: 'buy' as const,
          quantity: 10
        }
      }

      const result = await credentialManager.signTradingRequest(request)

      expect(result.success).toBe(true)
      expect(result.selectedAccount.accountId).toBe('pac-backup-1')
      expect(result.selectedAccount.isPrimary).toBe(false)
    })

    test('should recover primary accounts after successful operations', async () => {
      // Mark account as failed
      credentialManager.updateAccountAfterTrade('pac-hedge-1', {
        success: false,
        error: 'Temporary failure',
        timestamp: new Date()
      })

      // Simulate successful recovery
      credentialManager.updateAccountAfterTrade('pac-hedge-1', {
        success: true,
        tradeId: 'recovery-trade-123',
        timestamp: new Date()
      })

      // Account should be available again
      const healthCheck = await credentialManager.checkAccountHealth(['pac-hedge-1'])
      const health = healthCheck.get('pac-hedge-1')

      expect(health?.isHealthy).toBe(true)
      expect(health?.consecutiveFailures).toBe(0)
    })

    test('should handle complete platform failure gracefully', async () => {
      // Disable all Pacifica accounts
      for (const accountId of ['pac-hedge-1', 'pac-hedge-2', 'pac-backup-1']) {
        credentialManager.updateAccountAfterTrade(accountId, {
          success: false,
          error: 'Platform maintenance',
          timestamp: new Date()
        })
      }

      // Request should fail gracefully for unavailable platform
      const request = {
        operation: TradingOperation.PLACE_ORDER,
        platform: Platform.PACIFICA,
        parameters: {
          symbol: 'SOL/USDC',
          side: 'buy' as const,
          quantity: 10
        }
      }

      await expect(credentialManager.signTradingRequest(request))
        .rejects.toThrow('No available accounts')
    })
  })

  describe('Account Reservation for Hedging', () => {
    test('should reserve accounts for complex hedging strategy', async () => {
      const accountsToReserve = ['pac-hedge-1', 'ast-hedge-1', 'bnb-hedge-1']

      const reservation = await credentialManager.reserveAccountsForTrading(
        accountsToReserve,
        30000 // 30 second reservation
      )

      expect(reservation.success).toBe(true)
      expect(reservation.reservedAccounts).toEqual(expect.arrayContaining(accountsToReserve))

      // Reserved accounts should not be selected for other operations
      const pacificaRequest = {
        operation: TradingOperation.GET_BALANCE,
        platform: Platform.PACIFICA,
        parameters: {}
      }

      const result = await credentialManager.signTradingRequest(pacificaRequest)

      // Should use non-reserved account
      expect(result.selectedAccount.accountId).not.toBe('pac-hedge-1')
      expect(result.selectedAccount.accountId).toBe('pac-hedge-2')
    })

    test('should handle concurrent reservation requests', async () => {
      const reservation1Promise = credentialManager.reserveAccountsForTrading(
        ['pac-hedge-1', 'ast-hedge-1'],
        20000
      )

      const reservation2Promise = credentialManager.reserveAccountsForTrading(
        ['pac-hedge-2', 'bnb-hedge-1'],
        20000
      )

      const [reservation1, reservation2] = await Promise.all([
        reservation1Promise,
        reservation2Promise
      ])

      expect(reservation1.success).toBe(true)
      expect(reservation2.success).toBe(true)

      // No overlap in reserved accounts
      const reserved1 = new Set(reservation1.reservedAccounts)
      const reserved2 = new Set(reservation2.reservedAccounts)

      const intersection = new Set([...reserved1].filter(x => reserved2.has(x)))
      expect(intersection.size).toBe(0)
    })

    test('should auto-release expired reservations', async () => {
      const shortReservation = await credentialManager.reserveAccountsForTrading(
        ['pac-hedge-1'],
        100 // 100ms reservation
      )

      expect(shortReservation.success).toBe(true)

      // Wait for expiration
      await new Promise(resolve => setTimeout(resolve, 200))

      // Account should be available again
      const request = {
        operation: TradingOperation.GET_BALANCE,
        platform: Platform.PACIFICA,
        parameters: {}
      }

      const result = await credentialManager.signTradingRequest(request)

      // Should be able to select the previously reserved account
      expect(result.success).toBe(true)
      // Note: Due to round-robin, might select either account, so we just verify success
    })
  })

  describe('Delta-Neutral Hedging Scenarios', () => {
    test('should execute delta-neutral strategy across platforms', async () => {
      // Simulate a delta-neutral hedging strategy:
      // 1. Buy SOL on Pacifica (long position)
      // 2. Sell SOL equivalent on Aster (short position)
      // 3. Hedge with BTC position on Binance

      const deltaNeutralTrades = [
        {
          operation: TradingOperation.PLACE_ORDER,
          platform: Platform.PACIFICA,
          parameters: {
            symbol: 'SOL/USDC',
            side: 'buy' as const,
            quantity: 100,
            type: 'market' as const
          }
        },
        {
          operation: TradingOperation.PLACE_ORDER,
          platform: Platform.ASTER,
          parameters: {
            symbol: 'SOL/USDC',
            side: 'sell' as const,
            quantity: 100,
            type: 'market' as const
          }
        },
        {
          operation: TradingOperation.PLACE_ORDER,
          platform: Platform.BINANCE,
          parameters: {
            symbol: 'BTCUSDT',
            side: 'buy' as const,
            quantity: 0.05,
            type: 'limit' as const,
            price: 50000
          }
        }
      ]

      const startTime = Date.now()
      const results = await credentialManager.signBatchTradingRequests(deltaNeutralTrades)
      const executionTime = Date.now() - startTime

      // All trades should execute successfully
      expect(results).toHaveLength(3)
      expect(results.every(r => r.success)).toBe(true)

      // Should execute quickly for arbitrage opportunities
      expect(executionTime).toBeLessThan(150)

      // Verify each platform was used
      const platforms = results.map(r => r.selectedAccount.platform)
      expect(platforms).toContain(Platform.PACIFICA)
      expect(platforms).toContain(Platform.ASTER)
      expect(platforms).toContain(Platform.BINANCE)

      // Verify proper signature formats for each platform
      const pacificaResult = results.find(r => r.selectedAccount.platform === Platform.PACIFICA)
      const asterResult = results.find(r => r.selectedAccount.platform === Platform.ASTER)
      const binanceResult = results.find(r => r.selectedAccount.platform === Platform.BINANCE)

      expect(pacificaResult?.platformSignature.format).toBe('base64')
      expect(asterResult?.platformSignature.format).toBe('hex')
      expect(binanceResult?.platformSignature.format).toBe('hex')
    })

    test('should handle partial hedge execution failures', async () => {
      // Mark one account as failed to simulate partial execution
      credentialManager.updateAccountAfterTrade('ast-hedge-1', {
        success: false,
        error: 'Insufficient balance',
        timestamp: new Date()
      })

      credentialManager.updateAccountAfterTrade('ast-hedge-2', {
        success: false,
        error: 'Market closed',
        timestamp: new Date()
      })

      const hedgeTrades = [
        {
          operation: TradingOperation.PLACE_ORDER,
          platform: Platform.PACIFICA,
          parameters: {
            symbol: 'SOL/USDC',
            side: 'buy' as const,
            quantity: 50
          }
        },
        {
          operation: TradingOperation.PLACE_ORDER,
          platform: Platform.ASTER,
          parameters: {
            symbol: 'SOL/USDC',
            side: 'sell' as const,
            quantity: 50
          }
        }
      ]

      const results = await Promise.allSettled([
        credentialManager.signTradingRequest(hedgeTrades[0]),
        credentialManager.signTradingRequest(hedgeTrades[1])
      ])

      // Pacifica should succeed
      expect(results[0].status).toBe('fulfilled')
      if (results[0].status === 'fulfilled') {
        expect(results[0].value.success).toBe(true)
      }

      // Aster should fail (no available accounts)
      expect(results[1].status).toBe('rejected')
    })
  })

  describe('High-Frequency Trading Support', () => {
    test('should handle high-frequency hedge requests', async () => {
      const requestCount = 50
      const requests = Array.from({ length: requestCount }, (_, i) => ({
        operation: TradingOperation.GET_BALANCE,
        platform: [Platform.PACIFICA, Platform.ASTER, Platform.BINANCE][i % 3],
        parameters: {}
      }))

      const startTime = Date.now()
      const results = await Promise.all(
        requests.map(req => credentialManager.signTradingRequest(req))
      )
      const totalTime = Date.now() - startTime

      expect(results).toHaveLength(requestCount)
      expect(results.every(r => r.success)).toBe(true)

      // Should handle high frequency efficiently
      expect(totalTime).toBeLessThan(500) // 50 requests in 500ms
      expect(totalTime / requestCount).toBeLessThan(10) // Average < 10ms per request
    })

    test('should maintain account distribution under load', async () => {
      const requestCount = 30
      const requests = Array.from({ length: requestCount }, () => ({
        operation: TradingOperation.GET_POSITIONS,
        platform: Platform.PACIFICA,
        parameters: {}
      }))

      const results = await Promise.all(
        requests.map(req => credentialManager.signTradingRequest(req))
      )

      const accountUsage = results.reduce((acc, result) => {
        const accountId = result.selectedAccount.accountId
        acc[accountId] = (acc[accountId] || 0) + 1
        return acc
      }, {} as Record<string, number>)

      // Should distribute load across available accounts
      expect(Object.keys(accountUsage).length).toBeGreaterThan(1)

      // With round-robin, distribution should be relatively even
      const usageCounts = Object.values(accountUsage)
      const maxUsage = Math.max(...usageCounts)
      const minUsage = Math.min(...usageCounts)
      expect(maxUsage - minUsage).toBeLessThanOrEqual(2) // Allow small variance
    })
  })
})