/**
 * Anomaly Detection Service Tests
 */

import { describe, it, expect, beforeEach, vi } from 'vitest'
import { detectAnomalies, getAnomalies } from '../anomaly-detection'
import type { Context } from '../../types/context'

describe('Anomaly Detection Service', () => {
  let mockContext: Context
  let mockDb: any

  beforeEach(() => {
    mockDb = {
      query: vi.fn(),
    }

    mockContext = {
      db: mockDb as any,
      user: {
        id: 'user-1',
        email: 'test@example.com',
        name: 'Test User',
        role: 'ADMIN',
      },
    } as Context
  })

  describe('detectAnomalies', () => {
    it('should detect spikes in metrics', async () => {
      // Mock metrics data with a spike
      const baseValue = 50
      const spikeValue = 200
      const metrics = Array.from({ length: 20 }, (_, i) => ({
        timestamp: new Date(Date.now() - (20 - i) * 60000),
        value: i === 15 ? spikeValue.toString() : baseValue.toString(),
        labels: {},
      }))

      mockDb.query
        .mockResolvedValueOnce({ rows: metrics })
        .mockResolvedValue({ rows: [] }) // For storing anomalies

      const anomalies = await detectAnomalies(mockContext, {
        resourceId: 'resource-1',
        metricType: 'CPU_USAGE',
        sensitivity: 'MEDIUM',
      })

      expect(anomalies.length).toBeGreaterThan(0)
      expect(anomalies.some((a) => a.anomalyType === 'SPIKE')).toBe(true)
    })

    it('should detect drops in metrics', async () => {
      const baseValue = 50
      const dropValue = 5
      const metrics = Array.from({ length: 20 }, (_, i) => ({
        timestamp: new Date(Date.now() - (20 - i) * 60000),
        value: i === 15 ? dropValue.toString() : baseValue.toString(),
        labels: {},
      }))

      mockDb.query
        .mockResolvedValueOnce({ rows: metrics })
        .mockResolvedValue({ rows: [] })

      const anomalies = await detectAnomalies(mockContext, {
        resourceId: 'resource-1',
        metricType: 'CPU_USAGE',
      })

      expect(anomalies.some((a) => a.anomalyType === 'DROP')).toBe(true)
    })

    it('should return empty array when insufficient data', async () => {
      mockDb.query.mockResolvedValue({ rows: Array.from({ length: 5 }) })

      const anomalies = await detectAnomalies(mockContext, {
        resourceId: 'resource-1',
        metricType: 'CPU_USAGE',
      })

      expect(anomalies).toEqual([])
    })
  })

  describe('getAnomalies', () => {
    it('should retrieve stored anomalies', async () => {
      const mockAnomalies = [
        {
          id: 'anomaly-1',
          resource_id: 'resource-1',
          metric_type: 'CPU_USAGE',
          severity: 'HIGH',
          anomaly_type: 'SPIKE',
          value: '200',
          expected_value: '50',
          deviation: '300',
          timestamp: new Date(),
          description: 'CPU spike detected',
          recommendation: 'Scale up resources',
        },
      ]

      mockDb.query.mockResolvedValue({ rows: mockAnomalies })

      const anomalies = await getAnomalies(mockContext, 'resource-1')

      expect(anomalies).toHaveLength(1)
      expect(anomalies[0].severity).toBe('HIGH')
    })
  })
})

