/**
 * Integration Test for Hot-Reload Configuration
 *
 * Tests the file watching and hot-reload functionality of the credential manager.
 * Validates that configuration changes are detected and applied without manual restarts.
 */

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

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

  beforeEach(async () => {
    // Create temporary directory for test configs
    tempDir = await fs.mkdtemp(path.join(tmpdir(), 'credential-manager-test-'))
    tempConfigPath = path.join(tempDir, 'accounts.json')

    // Initial configuration
    const initialConfig = {
      accounts: [
        {
          id: 'initial-account',
          name: 'Initial Account',
          platform: Platform.PACIFICA,
          enabled: true,
          credentials: {
            type: 'ed25519' as const,
            privateKey: 'f26670e2ca334117f8859f9f32e50251641953a30b54f6ffcf82db836cfdfea5'
          }
        }
      ],
      hedging: {
        platforms: {
          [Platform.PACIFICA]: {
            enabled: true,
            primaryAccounts: ['initial-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()
    await credentialManager.loadConfigurationFromFile(tempConfigPath, {
      enableHotReload: true,
      watchDebounceMs: 100
    })
  })

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

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

  describe('Configuration File Watching', () => {
    test('should detect new account additions', async () => {
      // Initial state - should have 1 account
      let accounts = credentialManager.getAllAccounts()
      expect(accounts).toHaveLength(1)
      expect(accounts[0].id).toBe('initial-account')

      // Update configuration with new account
      const updatedConfig = {
        accounts: [
          {
            id: 'initial-account',
            name: 'Initial Account',
            platform: Platform.PACIFICA,
            enabled: true,
            credentials: {
              type: 'ed25519' as const,
              privateKey: 'f26670e2ca334117f8859f9f32e50251641953a30b54f6ffcf82db836cfdfea5'
            }
          },
          {
            id: 'new-account',
            name: 'New Account',
            platform: Platform.ASTER,
            enabled: true,
            credentials: {
              type: 'secp256k1' as const,
              privateKey: '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef'
            }
          }
        ],
        hedging: {
          platforms: {
            [Platform.PACIFICA]: {
              enabled: true,
              primaryAccounts: ['initial-account'],
              backupAccounts: [],
              loadBalanceStrategy: 'round-robin',
              healthCheckInterval: 30000,
              failoverThreshold: 3
            },
            [Platform.ASTER]: {
              enabled: true,
              primaryAccounts: ['new-account'],
              backupAccounts: [],
              loadBalanceStrategy: 'round-robin',
              healthCheckInterval: 30000,
              failoverThreshold: 3
            }
          },
          hedging: {
            enableCrossplatformBalancing: true,
            maxAccountsPerPlatform: 5,
            reservationTimeoutMs: 60000
          }
        }
      }

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

      // Wait for file watcher to detect change
      await new Promise(resolve => setTimeout(resolve, 200))

      // Should now have 2 accounts
      accounts = credentialManager.getAllAccounts()
      expect(accounts).toHaveLength(2)
      expect(accounts.map(a => a.id)).toContain('initial-account')
      expect(accounts.map(a => a.id)).toContain('new-account')
    })

    test('should detect account removal', async () => {
      // Initial state
      let accounts = credentialManager.getAllAccounts()
      expect(accounts).toHaveLength(1)

      // Remove account from configuration
      const updatedConfig = {
        accounts: [],
        hedging: {
          platforms: {},
          hedging: {
            enableCrossplatformBalancing: false,
            maxAccountsPerPlatform: 5,
            reservationTimeoutMs: 60000
          }
        }
      }

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

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

      // Should have no accounts
      accounts = credentialManager.getAllAccounts()
      expect(accounts).toHaveLength(0)
    })

    test('should detect account modifications', async () => {
      // Initial state
      let account = credentialManager.getAccount('initial-account')
      expect(account?.name).toBe('Initial Account')
      expect(account?.enabled).toBe(true)

      // Update account properties
      const updatedConfig = {
        accounts: [
          {
            id: 'initial-account',
            name: 'Modified Account Name',
            platform: Platform.PACIFICA,
            enabled: false, // Disable the account
            credentials: {
              type: 'ed25519' as const,
              privateKey: 'f26670e2ca334117f8859f9f32e50251641953a30b54f6ffcf82db836cfdfea5'
            }
          }
        ],
        hedging: {
          platforms: {
            [Platform.PACIFICA]: {
              enabled: true,
              primaryAccounts: ['initial-account'],
              backupAccounts: [],
              loadBalanceStrategy: 'round-robin',
              healthCheckInterval: 30000,
              failoverThreshold: 3
            }
          },
          hedging: {
            enableCrossplatformBalancing: false,
            maxAccountsPerPlatform: 5,
            reservationTimeoutMs: 60000
          }
        }
      }

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

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

      // Account should be updated
      account = credentialManager.getAccount('initial-account')
      expect(account?.name).toBe('Modified Account Name')
      expect(account?.enabled).toBe(false)
    })
  })

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

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

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

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

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

      const reloadTime = Date.now() - startTime

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

    test('should handle rapid configuration changes', async () => {
      const configs = [
        {
          accounts: [
            {
              id: 'rapid-test-1',
              name: 'Rapid Test 1',
              platform: Platform.PACIFICA,
              enabled: true,
              credentials: {
                type: 'ed25519' as const,
                privateKey: 'f26670e2ca334117f8859f9f32e50251641953a30b54f6ffcf82db836cfdfea5'
              }
            }
          ]
        },
        {
          accounts: [
            {
              id: 'rapid-test-2',
              name: 'Rapid Test 2',
              platform: Platform.ASTER,
              enabled: true,
              credentials: {
                type: 'secp256k1' as const,
                privateKey: '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef'
              }
            }
          ]
        }
      ]

      // Rapid succession of changes
      for (const config of configs) {
        const fullConfig = {
          ...config,
          hedging: {
            platforms: {},
            hedging: {
              enableCrossplatformBalancing: false,
              maxAccountsPerPlatform: 5,
              reservationTimeoutMs: 60000
            }
          }
        }

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

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

      // Should have the last configuration
      const accounts = credentialManager.getAllAccounts()
      expect(accounts).toHaveLength(1)
      expect(accounts[0].id).toBe('rapid-test-2')
    })
  })

  describe('Error Handling', () => {
    test('should handle invalid JSON gracefully', async () => {
      const invalidJson = '{ invalid json content'

      await fs.writeFile(tempConfigPath, invalidJson)

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

      // Should still have original accounts (no change due to error)
      const accounts = credentialManager.getAllAccounts()
      expect(accounts).toHaveLength(1)
      expect(accounts[0].id).toBe('initial-account')
    })

    test('should handle missing file gracefully', async () => {
      // Delete the config file
      await fs.unlink(tempConfigPath)

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

      // Should handle missing file without crashing
      // Behavior depends on implementation - might keep existing accounts or clear them
      const accounts = credentialManager.getAllAccounts()
      expect(Array.isArray(accounts)).toBe(true)
    })

    test('should validate configuration before applying changes', async () => {
      const invalidConfig = {
        accounts: [
          {
            id: '', // Invalid empty ID
            name: 'Invalid Account',
            platform: Platform.PACIFICA,
            enabled: true,
            credentials: {
              type: 'ed25519' as const,
              privateKey: 'invalid-key' // Invalid key
            }
          }
        ]
      }

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

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

      // Should reject invalid config and keep original
      const accounts = credentialManager.getAllAccounts()
      expect(accounts).toHaveLength(1)
      expect(accounts[0].id).toBe('initial-account')
    })
  })

  describe('Configuration Backup and Recovery', () => {
    test('should maintain service availability during configuration updates', async () => {
      const message = new TextEncoder().encode('availability test')

      // Service should work before update
      let result = await credentialManager.sign('initial-account', message)
      expect(result.success).toBe(true)

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

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

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

      // Service should still work after update
      result = await credentialManager.sign('initial-account', message)
      expect(result.success).toBe(true)

      // Account should have updated name
      const account = credentialManager.getAccount('initial-account')
      expect(account?.name).toBe('Updated Account')
    })

    test('should handle partial configuration updates', async () => {
      // Add second account first
      const configWithTwoAccounts = {
        accounts: [
          {
            id: 'initial-account',
            name: 'Initial Account',
            platform: Platform.PACIFICA,
            enabled: true,
            credentials: {
              type: 'ed25519' as const,
              privateKey: 'f26670e2ca334117f8859f9f32e50251641953a30b54f6ffcf82db836cfdfea5'
            }
          },
          {
            id: 'second-account',
            name: 'Second Account',
            platform: Platform.ASTER,
            enabled: true,
            credentials: {
              type: 'secp256k1' as const,
              privateKey: '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef'
            }
          }
        ],
        hedging: {
          platforms: {
            [Platform.PACIFICA]: {
              enabled: true,
              primaryAccounts: ['initial-account'],
              backupAccounts: [],
              loadBalanceStrategy: 'round-robin',
              healthCheckInterval: 30000,
              failoverThreshold: 3
            },
            [Platform.ASTER]: {
              enabled: true,
              primaryAccounts: ['second-account'],
              backupAccounts: [],
              loadBalanceStrategy: 'round-robin',
              healthCheckInterval: 30000,
              failoverThreshold: 3
            }
          },
          hedging: {
            enableCrossplatformBalancing: true,
            maxAccountsPerPlatform: 5,
            reservationTimeoutMs: 60000
          }
        }
      }

      await fs.writeFile(tempConfigPath, JSON.stringify(configWithTwoAccounts, null, 2))
      await new Promise(resolve => setTimeout(resolve, 200))

      // Should have both accounts
      let accounts = credentialManager.getAllAccounts()
      expect(accounts).toHaveLength(2)

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

      await fs.writeFile(tempConfigPath, JSON.stringify(configWithOneAccount, null, 2))
      await new Promise(resolve => setTimeout(resolve, 200))

      // Should have only one account
      accounts = credentialManager.getAllAccounts()
      expect(accounts).toHaveLength(1)
      expect(accounts[0].id).toBe('initial-account')
    })
  })
})