import { describe, it, expect, beforeEach, afterEach } from '@jest/globals'
import { RiskMonitoringService } from '../../src/services/RiskMonitoringService.js'
import { MonitoringEventManager } from '../../src/models/MonitoringEvent.js'

/**
 * RiskMonitoringService 单元测试
 * 测试风险监控服务的核心功能
 */
describe('RiskMonitoringService Unit Tests', () => {
  let riskService: RiskMonitoringService
  let mockEventManager: jest.Mocked<MonitoringEventManager>

  beforeEach(() => {
    // 创建模拟的事件管理器
    mockEventManager = {
      addEvent: jest.fn(),
      getRecentEvents: jest.fn().mockReturnValue([]),
      getEventsByType: jest.fn().mockReturnValue([]),
      clearOldEvents: jest.fn(),
    } as any

    riskService = new RiskMonitoringService(mockEventManager)
  })

  afterEach(async () => {
    await riskService.stop()
  })

  describe('Service Lifecycle', () => {
    it('should initialize with stopped status', () => {
      expect(riskService.getStatus()).toBe('stopped')
    })

    it('should start monitoring successfully', async () => {
      await riskService.start()
      expect(riskService.getStatus()).toBe('running')
    })

    it('should stop monitoring successfully', async () => {
      await riskService.start()
      await riskService.stop()
      expect(riskService.getStatus()).toBe('stopped')
    })
  })

  describe('Risk Metrics Calculation', () => {
    beforeEach(async () => {
      await riskService.start()
    })

    it('should return null for non-existent account', async () => {
      const metrics = await riskService.getRiskMetrics('non-existent-account')
      expect(metrics).toBeNull()
    })

    it('should calculate risk metrics for valid account state', async () => {
      // 更新账户状态
      await riskService.updateAccountRisk('test-account', {
        netPosition: 0.5,     // 0.5 BTC净仓位
        unrealizedPnl: 100,   // $100 未实现盈亏
        leverage: 2,          // 2x杠杆
        entryPrice: 50000,    // $50,000入场价
        currentPrice: 51000,  // $51,000当前价格
      })

      const metrics = await riskService.getRiskMetrics('test-account')

      expect(metrics).not.toBeNull()
      expect(metrics!.accountId).toBe('test-account')
      expect(metrics!.deltaDeviation).toBe(0.5) // 净仓位偏差
      expect(metrics!.utilizationRate).toBeGreaterThan(0)
      expect(metrics!.leverageRatio).toBe(2)
      expect(metrics!.unrealizedPnl).toBe(100)
    })

    it('should track maximum drawdown correctly', async () => {
      await riskService.updateAccountRisk('test-account', {
        netPosition: 1.0,
        unrealizedPnl: -500, // 负的P&L
        leverage: 3,
      })

      const metrics = await riskService.getRiskMetrics('test-account')
      expect(metrics!.maxDrawdown).toBe(500) // 最大回撤为正值
    })
  })

  describe('Risk Alert Generation', () => {
    beforeEach(async () => {
      await riskService.start()
    })

    it('should generate delta alert for high position deviation', async () => {
      await riskService.updateAccountRisk('test-account', {
        netPosition: 2.5, // 高净仓位偏差
        unrealizedPnl: 0,
        leverage: 1,
      })

      const alerts = riskService.getActiveAlerts('test-account')
      const deltaAlert = alerts.find(alert => alert.type === 'delta-alert')
      expect(deltaAlert).toBeDefined()
      expect(deltaAlert!.severity).toBe('WARN')
    })

    it('should generate utilization alert for high usage', async () => {
      await riskService.updateAccountRisk('test-account', {
        netPosition: 0.1,
        unrealizedPnl: 0,
        leverage: 1,
        utilizationRate: 0.85, // 85% 高利用率
      })

      const alerts = riskService.getActiveAlerts('test-account')
      const utilizationAlert = alerts.find(alert => alert.type === 'utilization-alert')
      expect(utilizationAlert).toBeDefined()
      expect(utilizationAlert!.severity).toBe('WARN')
    })

    it('should generate critical alert for excessive drawdown', async () => {
      await riskService.updateAccountRisk('test-account', {
        netPosition: 0.5,
        unrealizedPnl: -2500, // 高回撤
        leverage: 5,
      })

      const alerts = riskService.getActiveAlerts('test-account')
      const criticalAlert = alerts.find(alert => alert.severity === 'CRITICAL')
      expect(criticalAlert).toBeDefined()
    })
  })

  describe('Historical Risk Tracking', () => {
    beforeEach(async () => {
      await riskService.start()
    })

    it('should maintain risk metrics history', async () => {
      // 添加第一个风险指标
      await riskService.updateAccountRisk('test-account', {
        netPosition: 0.5,
        unrealizedPnl: 100,
        leverage: 2,
      })

      // 等待一小段时间
      await new Promise(resolve => setTimeout(resolve, 10))

      // 添加第二个风险指标
      await riskService.updateAccountRisk('test-account', {
        netPosition: 0.3,
        unrealizedPnl: 150,
        leverage: 2,
      })

      const history = riskService.getRiskHistory('test-account')
      expect(history.length).toBeGreaterThanOrEqual(2)
      expect(history[0].deltaDeviation).toBe(0.5)
      expect(history[history.length - 1].deltaDeviation).toBe(0.3)
    })

    it('should limit risk history to maximum size', async () => {
      // 添加大量风险指标 (超过限制)
      for (let i = 0; i < 1100; i++) {
        await riskService.updateAccountRisk('test-account', {
          netPosition: i * 0.001,
          unrealizedPnl: i,
          leverage: 1,
        })
      }

      const history = riskService.getRiskHistory('test-account')
      expect(history.length).toBeLessThanOrEqual(1000) // 最大1000条历史记录
    })
  })

  describe('Event Integration', () => {
    beforeEach(async () => {
      await riskService.start()
    })

    it('should log risk events to monitoring system', async () => {
      await riskService.updateAccountRisk('test-account', {
        netPosition: 2.0, // 触发风险警报
        unrealizedPnl: -1000,
        leverage: 5,
      })

      // 验证事件被记录
      expect(mockEventManager.addEvent).toHaveBeenCalled()
      const eventCall = mockEventManager.addEvent.mock.calls[0][0]
      expect(eventCall.type).toBe('delta-alert')
      expect(eventCall.accountId).toBe('test-account')
    })

    it('should include detailed risk data in events', async () => {
      await riskService.updateAccountRisk('test-account', {
        netPosition: 1.5,
        unrealizedPnl: -800,
        leverage: 4,
        entryPrice: 50000,
        currentPrice: 49000,
      })

      expect(mockEventManager.addEvent).toHaveBeenCalled()
      const eventCall = mockEventManager.addEvent.mock.calls[0][0]
      expect(eventCall.data).toMatchObject({
        deltaDeviation: 1.5,
        unrealizedPnl: -800,
        leverageRatio: 4,
        maxDrawdown: 800,
      })
    })
  })

  describe('Multi-Account Risk Management', () => {
    beforeEach(async () => {
      await riskService.start()
    })

    it('should handle multiple accounts independently', async () => {
      await riskService.updateAccountRisk('account-1', {
        netPosition: 0.5,
        unrealizedPnl: 100,
        leverage: 2,
      })

      await riskService.updateAccountRisk('account-2', {
        netPosition: -0.3,
        unrealizedPnl: -50,
        leverage: 1,
      })

      const metrics1 = await riskService.getRiskMetrics('account-1')
      const metrics2 = await riskService.getRiskMetrics('account-2')

      expect(metrics1!.deltaDeviation).toBe(0.5)
      expect(metrics2!.deltaDeviation).toBe(0.3)
      expect(metrics1!.unrealizedPnl).toBe(100)
      expect(metrics2!.unrealizedPnl).toBe(-50)
    })

    it('should return all active alerts across accounts', async () => {
      await riskService.updateAccountRisk('account-1', {
        netPosition: 2.0, // 触发警报
        unrealizedPnl: 0,
        leverage: 1,
      })

      await riskService.updateAccountRisk('account-2', {
        netPosition: 1.8, // 触发警报
        unrealizedPnl: 0,
        leverage: 1,
      })

      const allAlerts = riskService.getActiveAlerts()
      expect(allAlerts.length).toBeGreaterThanOrEqual(2)

      const account1Alerts = riskService.getActiveAlerts('account-1')
      const account2Alerts = riskService.getActiveAlerts('account-2')
      expect(account1Alerts.length).toBeGreaterThan(0)
      expect(account2Alerts.length).toBeGreaterThan(0)
    })
  })

  describe('Performance and Cleanup', () => {
    beforeEach(async () => {
      await riskService.start()
    })

    it('should clean up old alerts automatically', async () => {
      // 创建过期警报
      await riskService.updateAccountRisk('test-account', {
        netPosition: 2.0, // 触发警报
        unrealizedPnl: 0,
        leverage: 1,
      })

      // 获取初始警报数量
      const initialAlerts = riskService.getActiveAlerts()
      expect(initialAlerts.length).toBeGreaterThan(0)

      // 手动触发清理 (模拟时间流逝)
      await new Promise(resolve => setTimeout(resolve, 100))

      // 验证服务正在运行清理过程
      expect(riskService.getStatus()).toBe('running')
    })

    it('should handle concurrent risk updates safely', async () => {
      const promises = []

      // 并发更新同一账户的风险状态
      for (let i = 0; i < 10; i++) {
        promises.push(
          riskService.updateAccountRisk('test-account', {
            netPosition: i * 0.1,
            unrealizedPnl: i * 10,
            leverage: 1,
          })
        )
      }

      await Promise.all(promises)

      const metrics = await riskService.getRiskMetrics('test-account')
      expect(metrics).not.toBeNull()
      expect(metrics!.accountId).toBe('test-account')
    })
  })
})