import { describe, it, expect } from 'vitest'
import {
  getMetricValue,
  evaluateCondition,
  AlertEvaluator,
} from '@/lib/monitoring/alert-evaluator'

describe('getMetricValue', () => {
  it('resolves simple paths', () => {
    const metrics = { system: { cpuUsagePercent: 92 } }
    expect(getMetricValue(metrics, 'system.cpuUsagePercent')).toBe(92)
  })

  it('resolves deeply nested paths', () => {
    const metrics = { services: { redis: { memoryUsedMB: 512 } } }
    expect(getMetricValue(metrics, 'services.redis.memoryUsedMB')).toBe(512)
  })

  it('returns undefined for non-existent paths', () => {
    const metrics = { system: { cpuUsagePercent: 92 } }
    expect(getMetricValue(metrics, 'system.nonExistent')).toBeUndefined()
  })

  it('returns undefined for non-numeric values', () => {
    const metrics = { system: { name: 'test' } }
    expect(getMetricValue(metrics, 'system.name')).toBeUndefined()
  })

  it('returns undefined when traversing through null', () => {
    const metrics = { system: null }
    expect(getMetricValue(metrics as Record<string, unknown>, 'system.cpu')).toBeUndefined()
  })

  it('resolves top-level numeric values', () => {
    const metrics = { uptime: 3600 }
    expect(getMetricValue(metrics, 'uptime')).toBe(3600)
  })
})

describe('evaluateCondition', () => {
  it('gt: fires when value exceeds threshold', () => {
    expect(evaluateCondition('gt', 92, 80)).toBe(true)
    expect(evaluateCondition('gt', 80, 80)).toBe(false)
    expect(evaluateCondition('gt', 45, 80)).toBe(false)
  })

  it('lt: fires when value is below threshold', () => {
    expect(evaluateCondition('lt', 5, 10)).toBe(true)
    expect(evaluateCondition('lt', 10, 10)).toBe(false)
    expect(evaluateCondition('lt', 15, 10)).toBe(false)
  })

  it('gte: fires when value >= threshold', () => {
    expect(evaluateCondition('gte', 80, 80)).toBe(true)
    expect(evaluateCondition('gte', 81, 80)).toBe(true)
    expect(evaluateCondition('gte', 79, 80)).toBe(false)
  })

  it('lte: fires when value <= threshold', () => {
    expect(evaluateCondition('lte', 10, 10)).toBe(true)
    expect(evaluateCondition('lte', 9, 10)).toBe(true)
    expect(evaluateCondition('lte', 11, 10)).toBe(false)
  })

  it('eq: fires when value equals threshold', () => {
    expect(evaluateCondition('eq', 100, 100)).toBe(true)
    expect(evaluateCondition('eq', 99, 100)).toBe(false)
  })

  it('returns false for unknown condition', () => {
    expect(evaluateCondition('unknown' as never, 50, 50)).toBe(false)
  })
})

describe('AlertEvaluator.shouldFire + recordFired', () => {
  it('allows first fire', () => {
    const evaluator = new AlertEvaluator()
    expect(evaluator.shouldFire('rule-1', 15)).toBe(true)
  })

  it('blocks during cooldown after recordFired', () => {
    const evaluator = new AlertEvaluator()
    expect(evaluator.shouldFire('rule-1', 15)).toBe(true)
    evaluator.recordFired('rule-1')
    expect(evaluator.shouldFire('rule-1', 15)).toBe(false)
  })

  it('allows re-check if recordFired was not called', () => {
    const evaluator = new AlertEvaluator()
    expect(evaluator.shouldFire('rule-1', 15)).toBe(true)
    // Without recordFired, the cooldown is not active
    expect(evaluator.shouldFire('rule-1', 15)).toBe(true)
  })

  it('different rules have independent cooldowns', () => {
    const evaluator = new AlertEvaluator()
    expect(evaluator.shouldFire('rule-1', 15)).toBe(true)
    evaluator.recordFired('rule-1')
    expect(evaluator.shouldFire('rule-2', 15)).toBe(true)
  })

  it('allows fire after cooldown expires', () => {
    const evaluator = new AlertEvaluator()
    evaluator.recordFired('rule-1')
    // With 0-minute cooldown, immediate re-fire should be allowed
    expect(evaluator.shouldFire('rule-1', 0)).toBe(true)
  })
})
