/**
 * Performance Test for Hot-Reload Configuration
 *
 * Validates that configuration hot-reload operations meet the <100ms performance requirement
 * and that service remains available during configuration updates.
 */

import { CredentialManager } from '@/core/credential-manager/CredentialManager'
import { ConfigLoader } from '@/core/credential-manager/ConfigLoader'
import { Platform } from '@/types/credential'
import fs from 'fs/promises'
import path from 'path'
import { tmpdir } from 'os'

describe('Hot-Reload Performance Test', () => {
  let credentialManager: CredentialManager
  let configLoader: ConfigLoader
  let tempConfigPath: string
  let tempDir: string

  beforeEach(async () => {
    // Create temporary directory for test configs
    tempDir = await fs.mkdtemp(path.join(tmpdir(), 'hot-reload-perf-test-'))
    tempConfigPath = path.join(tempDir, 'performance-config.json')

    // Initial small configuration
    const initialConfig = {
      accounts: [
        {
          id: 'initial-perf-account',
          name: 'Initial Performance Account',
          platform: Platform.PACIFICA,
          enabled: true,
          credentials: {
            type: 'ed25519' as const,
            privateKey: 'f26670e2ca334117f8859f9f32e50251641953a30b54f6ffcf82db836cfdfea5'
          }
        }
      ],
      hedging: {
        platforms: {
          [Platform.PACIFICA]: {
            enabled: true,
            primaryAccounts: ['initial-perf-account'],
            backupAccounts: [],
            loadBalanceStrategy: 'round-robin',
            healthCheckInterval: 30000,
            failoverThreshold: 3
          }
        },
        hedging: {
          enableCrossplatformBalancing: false,
          maxAccountsPerPlatform: 5,
          reservationTimeoutMs: 60000
        }
      }
    }

    await fs.writeFile(tempConfigPath, JSON.stringify(initialConfig, null, 2))

    credentialManager = new CredentialManager()
    configLoader = new ConfigLoader()

    await credentialManager.loadConfigurationFromFile(tempConfigPath, {
      enableHotReload: true,
      watchDebounceMs: 50 // Faster for testing
    })
  })

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

    // Clean up temp files
    try {
      await fs.rm(tempDir, { recursive: true })
    } catch (error) {
      // Ignore cleanup errors
    }
  })

  describe('Single Configuration Reload Performance', () => {
    test('should reload small configuration within 100ms', async () => {
      const updatedConfig = {
        accounts: [
          {
            id: 'updated-perf-account',
            name: 'Updated Performance Account',
            platform: Platform.PACIFICA,
            enabled: true,
            credentials: {
              type: 'ed25519' as const,
              privateKey: 'f26670e2ca334117f8859f9f32e50251641953a30b54f6ffcf82db836cfdfea5'
            }
          }
        ],
        hedging: {
          platforms: {
            [Platform.PACIFICA]: {
              enabled: true,
              primaryAccounts: ['updated-perf-account'],
              backupAccounts: [],
              loadBalanceStrategy: 'round-robin',
              healthCheckInterval: 30000,
              failoverThreshold: 3
            }
          },
          hedging: {
            enableCrossplatformBalancing: false,
            maxAccountsPerPlatform: 5,
            reservationTimeoutMs: 60000
          }
        }
      }

      const startTime = performance.now()
      await fs.writeFile(tempConfigPath, JSON.stringify(updatedConfig, null, 2))

      // Wait for reload to complete
      let reloaded = false
      const maxWaitTime = 100
      const checkInterval = 5

      for (let elapsed = 0; elapsed < maxWaitTime; elapsed += checkInterval) {
        await new Promise(resolve => setTimeout(resolve, checkInterval))

        const account = credentialManager.getAccount('updated-perf-account')
        if (account) {
          reloaded = true
          break
        }
      }

      const reloadTime = performance.now() - startTime

      expect(reloaded).toBe(true)
      expect(reloadTime).toBeLessThan(100) // Performance requirement
    })

    test('should reload medium-sized configuration within 100ms', async () => {
      // Configuration with 10 accounts across 3 platforms
      const mediumConfig = {
        accounts: Array.from({ length: 10 }, (_, i) => ({
          id: `perf-account-${i}`,
          name: `Performance Account ${i}`,
          platform: [Platform.PACIFICA, Platform.ASTER, Platform.BINANCE][i % 3],
          enabled: true,
          credentials: i % 3 === 0 ? {
            type: 'ed25519' as const,
            privateKey: 'f26670e2ca334117f8859f9f32e50251641953a30b54f6ffcf82db836cfdfea5'
          } : i % 3 === 1 ? {
            type: 'secp256k1' as const,
            privateKey: '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef'
          } : {
            type: 'hmac' as const,
            apiKey: `api-key-${i}`,
            secretKey: `secret-key-${i}`
          }
        })),
        hedging: {
          platforms: {
            [Platform.PACIFICA]: {
              enabled: true,
              primaryAccounts: ['perf-account-0', 'perf-account-3', 'perf-account-6'],
              backupAccounts: ['perf-account-9'],
              loadBalanceStrategy: 'round-robin',
              healthCheckInterval: 30000,
              failoverThreshold: 3
            },
            [Platform.ASTER]: {
              enabled: true,
              primaryAccounts: ['perf-account-1', 'perf-account-4', 'perf-account-7'],
              backupAccounts: [],
              loadBalanceStrategy: 'weighted',
              healthCheckInterval: 30000,
              failoverThreshold: 3
            },
            [Platform.BINANCE]: {
              enabled: true,
              primaryAccounts: ['perf-account-2', 'perf-account-5', 'perf-account-8'],
              backupAccounts: [],
              loadBalanceStrategy: 'least-used',
              healthCheckInterval: 30000,
              failoverThreshold: 3
            }
          },
          hedging: {
            enableCrossplatformBalancing: true,
            maxAccountsPerPlatform: 10,
            reservationTimeoutMs: 60000
          }
        }
      }

      const startTime = performance.now()
      await fs.writeFile(tempConfigPath, JSON.stringify(mediumConfig, null, 2))

      // Wait for reload to complete
      let reloaded = false
      const maxWaitTime = 100

      for (let elapsed = 0; elapsed < maxWaitTime; elapsed += 5) {
        await new Promise(resolve => setTimeout(resolve, 5))

        const accounts = credentialManager.getAllAccounts()
        if (accounts.length === 10) {
          reloaded = true
          break
        }
      }

      const reloadTime = performance.now() - startTime

      expect(reloaded).toBe(true)
      expect(reloadTime).toBeLessThan(100) // Performance requirement

      // Verify all accounts were loaded
      const accounts = credentialManager.getAllAccounts()
      expect(accounts).toHaveLength(10)
    })

    test('should handle large configuration efficiently', async () => {
      // Configuration with 50 accounts (stress test)
      const largeConfig = {
        accounts: Array.from({ length: 50 }, (_, i) => ({
          id: `large-perf-account-${i}`,
          name: `Large Performance Account ${i}`,
          platform: [Platform.PACIFICA, Platform.ASTER, Platform.BINANCE][i % 3],
          enabled: true,
          credentials: i % 3 === 0 ? {
            type: 'ed25519' as const,
            privateKey: 'f26670e2ca334117f8859f9f32e50251641953a30b54f6ffcf82db836cfdfea5'
          } : i % 3 === 1 ? {
            type: 'secp256k1' as const,
            privateKey: '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef'
          } : {
            type: 'hmac' as const,
            apiKey: `large-api-key-${i}`,
            secretKey: `large-secret-key-${i}`
          }
        })),
        hedging: {
          platforms: {
            [Platform.PACIFICA]: {
              enabled: true,
              primaryAccounts: Array.from({ length: 8 }, (_, i) => `large-perf-account-${i * 3}`),
              backupAccounts: Array.from({ length: 4 }, (_, i) => `large-perf-account-${30 + i * 3}`),
              loadBalanceStrategy: 'round-robin',
              healthCheckInterval: 30000,
              failoverThreshold: 3
            },
            [Platform.ASTER]: {
              enabled: true,
              primaryAccounts: Array.from({ length: 8 }, (_, i) => `large-perf-account-${1 + i * 3}`),
              backupAccounts: Array.from({ length: 4 }, (_, i) => `large-perf-account-${31 + i * 3}`),
              loadBalanceStrategy: 'weighted',
              healthCheckInterval: 30000,
              failoverThreshold: 3
            },
            [Platform.BINANCE]: {
              enabled: true,
              primaryAccounts: Array.from({ length: 8 }, (_, i) => `large-perf-account-${2 + i * 3}`),
              backupAccounts: Array.from({ length: 4 }, (_, i) => `large-perf-account-${32 + i * 3}`),
              loadBalanceStrategy: 'least-used',
              healthCheckInterval: 30000,
              failoverThreshold: 3
            }
          },
          hedging: {
            enableCrossplatformBalancing: true,
            maxAccountsPerPlatform: 20,
            reservationTimeoutMs: 60000
          }
        }
      }

      const startTime = performance.now()
      await fs.writeFile(tempConfigPath, JSON.stringify(largeConfig, null, 2))

      // Wait for reload to complete (allow more time for large config)
      let reloaded = false
      const maxWaitTime = 200 // Allow 200ms for large config

      for (let elapsed = 0; elapsed < maxWaitTime; elapsed += 10) {
        await new Promise(resolve => setTimeout(resolve, 10))

        const accounts = credentialManager.getAllAccounts()
        if (accounts.length === 50) {
          reloaded = true
          break
        }
      }

      const reloadTime = performance.now() - startTime

      expect(reloaded).toBe(true)
      expect(reloadTime).toBeLessThan(200) // Allow more time for large config

      // Verify all accounts were loaded
      const accounts = credentialManager.getAllAccounts()
      expect(accounts).toHaveLength(50)
    })
  })

  describe('Rapid Configuration Changes Performance', () => {
    test('should handle rapid successive configuration changes', async () => {
      const configs = Array.from({ length: 5 }, (_, i) => ({
        accounts: [
          {
            id: `rapid-account-${i}`,
            name: `Rapid Account ${i}`,
            platform: Platform.PACIFICA,
            enabled: true,
            credentials: {
              type: 'ed25519' as const,
              privateKey: 'f26670e2ca334117f8859f9f32e50251641953a30b54f6ffcf82db836cfdfea5'
            }
          }
        ],
        hedging: {
          platforms: {
            [Platform.PACIFICA]: {
              enabled: true,
              primaryAccounts: [`rapid-account-${i}`],
              backupAccounts: [],
              loadBalanceStrategy: 'round-robin',
              healthCheckInterval: 30000,
              failoverThreshold: 3
            }
          },
          hedging: {
            enableCrossplatformBalancing: false,
            maxAccountsPerPlatform: 5,
            reservationTimeoutMs: 60000
          }
        }
      }))

      const startTime = performance.now()

      // Rapid succession of changes
      for (const config of configs) {
        await fs.writeFile(tempConfigPath, JSON.stringify(config, null, 2))
        await new Promise(resolve => setTimeout(resolve, 20)) // Small delay
      }

      // Wait for final state
      let finalStateReached = false
      const maxWaitTime = 200

      for (let elapsed = 0; elapsed < maxWaitTime; elapsed += 10) {
        await new Promise(resolve => setTimeout(resolve, 10))

        const account = credentialManager.getAccount('rapid-account-4')
        if (account) {
          finalStateReached = true
          break
        }
      }

      const totalTime = performance.now() - startTime

      expect(finalStateReached).toBe(true)
      expect(totalTime).toBeLessThan(300) // All changes should complete within 300ms

      // Verify final state
      const accounts = credentialManager.getAllAccounts()
      expect(accounts).toHaveLength(1)
      expect(accounts[0].id).toBe('rapid-account-4')
    })

    test('should maintain service availability during rapid changes', async () => {
      const message = new TextEncoder().encode('availability test during changes')
      let serviceAvailability = 0
      let totalChecks = 0

      // Start making configuration changes in background
      const configChangePromise = (async () => {
        for (let i = 0; i < 10; i++) {
          const config = {
            accounts: [
              {
                id: 'service-test-account',
                name: `Service Test Account ${i}`,
                platform: Platform.PACIFICA,
                enabled: true,
                credentials: {
                  type: 'ed25519' as const,
                  privateKey: 'f26670e2ca334117f8859f9f32e50251641953a30b54f6ffcf82db836cfdfea5'
                }
              }
            ],
            hedging: {
              platforms: {
                [Platform.PACIFICA]: {
                  enabled: true,
                  primaryAccounts: ['service-test-account'],
                  backupAccounts: [],
                  loadBalanceStrategy: 'round-robin',
                  healthCheckInterval: 30000,
                  failoverThreshold: 3
                }
              },
              hedging: {
                enableCrossplatformBalancing: false,
                maxAccountsPerPlatform: 5,
                reservationTimeoutMs: 60000
              }
            }
          }

          await fs.writeFile(tempConfigPath, JSON.stringify(config, null, 2))
          await new Promise(resolve => setTimeout(resolve, 30))
        }
      })()

      // Continuously check service availability
      const availabilityCheckPromise = (async () => {
        const startTime = Date.now()
        while (Date.now() - startTime < 500) { // Check for 500ms
          try {
            const result = await credentialManager.sign('service-test-account', message)
            if (result.success) {
              serviceAvailability++
            }
          } catch (error) {
            // Service unavailable during this check
          }
          totalChecks++
          await new Promise(resolve => setTimeout(resolve, 25))
        }
      })()

      await Promise.all([configChangePromise, availabilityCheckPromise])

      // Service should be available most of the time (>80%)
      const availabilityRate = serviceAvailability / totalChecks
      expect(availabilityRate).toBeGreaterThan(0.8)
      expect(totalChecks).toBeGreaterThan(10) // Should have made multiple checks
    })
  })

  describe('File System Performance', () => {
    test('should efficiently detect file changes', async () => {
      const changeCount = 10
      const detectedChanges: number[] = []

      // Monitor how quickly changes are detected
      for (let i = 0; i < changeCount; i++) {
        const config = {
          accounts: [
            {
              id: `detection-account-${i}`,
              name: `Detection Account ${i}`,
              platform: Platform.PACIFICA,
              enabled: true,
              credentials: {
                type: 'ed25519' as const,
                privateKey: 'f26670e2ca334117f8859f9f32e50251641953a30b54f6ffcf82db836cfdfea5'
              }
            }
          ],
          hedging: {
            platforms: {
              [Platform.PACIFICA]: {
                enabled: true,
                primaryAccounts: [`detection-account-${i}`],
                backupAccounts: [],
                loadBalanceStrategy: 'round-robin',
                healthCheckInterval: 30000,
                failoverThreshold: 3
              }
            },
            hedging: {
              enableCrossplatformBalancing: false,
              maxAccountsPerPlatform: 5,
              reservationTimeoutMs: 60000
            }
          }
        }

        const writeStartTime = performance.now()
        await fs.writeFile(tempConfigPath, JSON.stringify(config, null, 2))

        // Wait for detection
        let detected = false
        const maxDetectionTime = 100

        for (let elapsed = 0; elapsed < maxDetectionTime; elapsed += 5) {
          await new Promise(resolve => setTimeout(resolve, 5))

          const account = credentialManager.getAccount(`detection-account-${i}`)
          if (account) {
            detected = true
            detectedChanges.push(performance.now() - writeStartTime)
            break
          }
        }

        expect(detected).toBe(true)
      }

      // All changes should be detected quickly
      expect(detectedChanges).toHaveLength(changeCount)

      const averageDetectionTime = detectedChanges.reduce((a, b) => a + b, 0) / changeCount
      const maxDetectionTime = Math.max(...detectedChanges)

      expect(averageDetectionTime).toBeLessThan(75) // Average < 75ms
      expect(maxDetectionTime).toBeLessThan(100) // Max < 100ms
    })

    test('should handle file system errors gracefully', async () => {
      // Create invalid JSON to test error handling performance
      const invalidConfigs = [
        '{ invalid json',
        '{ "accounts": [{ "invalid": }',
        '{ "accounts": [], "hedging": { missing bracket',
        '', // Empty file
        'not json at all'
      ]

      for (const invalidConfig of invalidConfigs) {
        const startTime = performance.now()
        await fs.writeFile(tempConfigPath, invalidConfig)

        // Wait a bit to see if system handles error
        await new Promise(resolve => setTimeout(resolve, 100))

        const errorHandlingTime = performance.now() - startTime

        // Should handle errors quickly without crashing
        expect(errorHandlingTime).toBeLessThan(150)

        // System should still be responsive
        const accounts = credentialManager.getAllAccounts()
        expect(Array.isArray(accounts)).toBe(true) // Should not crash
      }
    })
  })

  describe('Memory Performance During Reloads', () => {
    test('should not leak memory during repeated reloads', async () => {
      const initialMemory = process.memoryUsage()

      // Perform many configuration reloads
      for (let i = 0; i < 20; i++) {
        const config = {
          accounts: [
            {
              id: `memory-test-${i}`,
              name: `Memory Test ${i}`,
              platform: Platform.PACIFICA,
              enabled: true,
              credentials: {
                type: 'ed25519' as const,
                privateKey: 'f26670e2ca334117f8859f9f32e50251641953a30b54f6ffcf82db836cfdfea5'
              }
            }
          ],
          hedging: {
            platforms: {
              [Platform.PACIFICA]: {
                enabled: true,
                primaryAccounts: [`memory-test-${i}`],
                backupAccounts: [],
                loadBalanceStrategy: 'round-robin',
                healthCheckInterval: 30000,
                failoverThreshold: 3
              }
            },
            hedging: {
              enableCrossplatformBalancing: false,
              maxAccountsPerPlatform: 5,
              reservationTimeoutMs: 60000
            }
          }
        }

        await fs.writeFile(tempConfigPath, JSON.stringify(config, null, 2))
        await new Promise(resolve => setTimeout(resolve, 60)) // Wait for reload
      }

      // Force garbage collection if available
      if (global.gc) {
        global.gc()
        await new Promise(resolve => setTimeout(resolve, 100))
      }

      const finalMemory = process.memoryUsage()

      // Memory increase should be reasonable (less than 5MB)
      const heapIncrease = finalMemory.heapUsed - initialMemory.heapUsed
      expect(heapIncrease).toBeLessThan(5 * 1024 * 1024) // 5MB
    })

    test('should maintain performance under memory pressure', async () => {
      // Create some memory pressure
      const memoryPressure: string[] = []
      for (let i = 0; i < 1000; i++) {
        memoryPressure.push('x'.repeat(1000)) // 1MB total
      }

      const config = {
        accounts: [
          {
            id: 'pressure-test-account',
            name: 'Pressure Test Account',
            platform: Platform.PACIFICA,
            enabled: true,
            credentials: {
              type: 'ed25519' as const,
              privateKey: 'f26670e2ca334117f8859f9f32e50251641953a30b54f6ffcf82db836cfdfea5'
            }
          }
        ],
        hedging: {
          platforms: {
            [Platform.PACIFICA]: {
              enabled: true,
              primaryAccounts: ['pressure-test-account'],
              backupAccounts: [],
              loadBalanceStrategy: 'round-robin',
              healthCheckInterval: 30000,
              failoverThreshold: 3
            }
          },
          hedging: {
            enableCrossplatformBalancing: false,
            maxAccountsPerPlatform: 5,
            reservationTimeoutMs: 60000
          }
        }
      }

      const startTime = performance.now()
      await fs.writeFile(tempConfigPath, JSON.stringify(config, null, 2))

      // Wait for reload
      let reloaded = false
      const maxWaitTime = 150 // Allow extra time under pressure

      for (let elapsed = 0; elapsed < maxWaitTime; elapsed += 10) {
        await new Promise(resolve => setTimeout(resolve, 10))

        const account = credentialManager.getAccount('pressure-test-account')
        if (account) {
          reloaded = true
          break
        }
      }

      const reloadTime = performance.now() - startTime

      expect(reloaded).toBe(true)
      expect(reloadTime).toBeLessThan(150) // Should still meet requirements under pressure

      // Clean up memory pressure
      memoryPressure.length = 0
    })
  })
})