import dayjs from 'dayjs'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'

import type { LogsBarChartDatum } from '../ProjectHome/ProjectUsage.metrics'
import {
  calculateAggregatedMetrics,
  calculateDateRange,
  calculateHealthMetrics,
  transformToBarChartData,
} from './useServiceHealthMetrics.utils'

describe('calculateDateRange', () => {
  beforeEach(() => {
    // Mock the current time to ensure consistent test results
    vi.useFakeTimers()
    vi.setSystemTime(new Date('2024-01-15T12:00:00Z'))
  })

  afterEach(() => {
    vi.useRealTimers()
  })

  it('calculates correct date range for 1hr interval', () => {
    const result = calculateDateRange('1hr')

    expect(result.startDate).toBe('2024-01-15T11:00:00.000Z')
    expect(result.endDate).toBe('2024-01-15T12:00:00.000Z')
  })

  it('calculates correct date range for 1day interval', () => {
    const result = calculateDateRange('1day')

    expect(result.startDate).toBe('2024-01-14T12:00:00.000Z')
    expect(result.endDate).toBe('2024-01-15T12:00:00.000Z')
  })

  it('calculates correct date range for 7day interval', () => {
    const result = calculateDateRange('7day')

    expect(result.startDate).toBe('2024-01-08T12:00:00.000Z')
    expect(result.endDate).toBe('2024-01-15T12:00:00.000Z')
  })

  it('returns ISO format strings', () => {
    const result = calculateDateRange('1hr')

    expect(dayjs(result.startDate).isValid()).toBe(true)
    expect(dayjs(result.endDate).isValid()).toBe(true)
  })

  it('end date is always after start date', () => {
    const intervals: Array<'1hr' | '1day' | '7day'> = ['1hr', '1day', '7day']

    intervals.forEach((interval) => {
      const result = calculateDateRange(interval)
      expect(dayjs(result.endDate).isAfter(dayjs(result.startDate))).toBe(true)
    })
  })
})

describe('transformToBarChartData', () => {
  it('transforms raw data to LogsBarChartDatum format', () => {
    const rawData = [
      { timestamp: '2024-01-15T12:00:00Z', ok_count: 10, warning_count: 2, error_count: 1 },
      { timestamp: '2024-01-15T12:01:00Z', ok_count: 15, warning_count: 0, error_count: 0 },
    ]

    const result = transformToBarChartData(rawData)

    expect(result).toEqual([
      { timestamp: '2024-01-15T12:00:00Z', ok_count: 10, warning_count: 2, error_count: 1 },
      { timestamp: '2024-01-15T12:01:00Z', ok_count: 15, warning_count: 0, error_count: 0 },
    ])
  })

  it('handles missing count fields by setting them to 0', () => {
    const rawData = [
      { timestamp: '2024-01-15T12:00:00Z' },
      { timestamp: '2024-01-15T12:01:00Z', ok_count: 5 },
    ]

    const result = transformToBarChartData(rawData)

    expect(result).toEqual([
      { timestamp: '2024-01-15T12:00:00Z', ok_count: 0, warning_count: 0, error_count: 0 },
      { timestamp: '2024-01-15T12:01:00Z', ok_count: 5, warning_count: 0, error_count: 0 },
    ])
  })

  it('handles null values by converting to 0', () => {
    const rawData = [
      {
        timestamp: '2024-01-15T12:00:00Z',
        ok_count: null,
        warning_count: null,
        error_count: null,
      },
    ]

    const result = transformToBarChartData(rawData)

    expect(result).toEqual([
      { timestamp: '2024-01-15T12:00:00Z', ok_count: 0, warning_count: 0, error_count: 0 },
    ])
  })

  it('handles empty array', () => {
    const result = transformToBarChartData([])

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

  it('preserves timestamp values', () => {
    const rawData = [
      { timestamp: '2024-01-15T12:00:00Z', ok_count: 10, warning_count: 0, error_count: 0 },
    ]

    const result = transformToBarChartData(rawData)

    expect(result[0].timestamp).toBe('2024-01-15T12:00:00Z')
  })
})

describe('calculateHealthMetrics', () => {
  it('calculates metrics correctly with only ok requests', () => {
    const eventChartData: LogsBarChartDatum[] = [
      { timestamp: '2024-01-15T12:00:00Z', ok_count: 100, warning_count: 0, error_count: 0 },
      { timestamp: '2024-01-15T12:01:00Z', ok_count: 50, warning_count: 0, error_count: 0 },
    ]

    const result = calculateHealthMetrics(eventChartData)

    expect(result).toEqual({
      total: 150,
      errorRate: 0,
      successRate: 100,
      errorCount: 0,
      warningCount: 0,
      okCount: 150,
    })
  })

  it('calculates metrics correctly with errors', () => {
    const eventChartData: LogsBarChartDatum[] = [
      { timestamp: '2024-01-15T12:00:00Z', ok_count: 80, warning_count: 10, error_count: 10 },
    ]

    const result = calculateHealthMetrics(eventChartData)

    expect(result).toEqual({
      total: 100,
      errorRate: 10,
      successRate: 80,
      errorCount: 10,
      warningCount: 10,
      okCount: 80,
    })
  })

  it('calculates metrics correctly with warnings', () => {
    const eventChartData: LogsBarChartDatum[] = [
      { timestamp: '2024-01-15T12:00:00Z', ok_count: 70, warning_count: 30, error_count: 0 },
    ]

    const result = calculateHealthMetrics(eventChartData)

    expect(result).toEqual({
      total: 100,
      errorRate: 0,
      successRate: 70,
      errorCount: 0,
      warningCount: 30,
      okCount: 70,
    })
  })

  it('returns 0 error rate when total is 0', () => {
    const eventChartData: LogsBarChartDatum[] = [
      { timestamp: '2024-01-15T12:00:00Z', ok_count: 0, warning_count: 0, error_count: 0 },
    ]

    const result = calculateHealthMetrics(eventChartData)

    expect(result).toEqual({
      total: 0,
      errorRate: 0,
      successRate: 0,
      errorCount: 0,
      warningCount: 0,
      okCount: 0,
    })
  })

  it('handles empty array', () => {
    const result = calculateHealthMetrics([])

    expect(result).toEqual({
      total: 0,
      errorRate: 0,
      successRate: 0,
      errorCount: 0,
      warningCount: 0,
      okCount: 0,
    })
  })

  it('aggregates metrics across multiple time periods', () => {
    const eventChartData: LogsBarChartDatum[] = [
      { timestamp: '2024-01-15T12:00:00Z', ok_count: 50, warning_count: 5, error_count: 5 },
      { timestamp: '2024-01-15T12:01:00Z', ok_count: 30, warning_count: 5, error_count: 5 },
      { timestamp: '2024-01-15T12:02:00Z', ok_count: 20, warning_count: 0, error_count: 0 },
    ]

    const result = calculateHealthMetrics(eventChartData)

    expect(result).toEqual({
      total: 120,
      errorRate: (10 / 120) * 100,
      successRate: (100 / 120) * 100,
      errorCount: 10,
      warningCount: 10,
      okCount: 100,
    })
  })

  it('calculates correct error rate for high error scenario', () => {
    const eventChartData: LogsBarChartDatum[] = [
      { timestamp: '2024-01-15T12:00:00Z', ok_count: 10, warning_count: 10, error_count: 80 },
    ]

    const result = calculateHealthMetrics(eventChartData)

    expect(result.errorRate).toBe(80)
    expect(result.successRate).toBe(10)
  })
})

describe('calculateAggregatedMetrics', () => {
  it('aggregates metrics from multiple services', () => {
    const services = [
      { total: 100, errorCount: 10, warningCount: 5 },
      { total: 200, errorCount: 20, warningCount: 10 },
      { total: 50, errorCount: 5, warningCount: 2 },
    ]

    const result = calculateAggregatedMetrics(services)

    expect(result).toEqual({
      totalRequests: 350,
      totalErrors: 35,
      totalWarnings: 17,
      overallErrorRate: ((35 + 17) / 350) * 100,
      overallSuccessRate: ((350 - 35 - 17) / 350) * 100,
    })
  })

  it('handles empty services array', () => {
    const result = calculateAggregatedMetrics([])

    expect(result).toEqual({
      totalRequests: 0,
      totalErrors: 0,
      totalWarnings: 0,
      overallErrorRate: 0,
      overallSuccessRate: 0,
    })
  })

  it('handles single service', () => {
    const services = [{ total: 100, errorCount: 10, warningCount: 5 }]

    const result = calculateAggregatedMetrics(services)

    expect(result).toEqual({
      totalRequests: 100,
      totalErrors: 10,
      totalWarnings: 5,
      overallErrorRate: 15,
      overallSuccessRate: 85,
    })
  })

  it('handles services with zero metrics', () => {
    const services = [
      { total: 0, errorCount: 0, warningCount: 0 },
      { total: 100, errorCount: 10, warningCount: 5 },
    ]

    const result = calculateAggregatedMetrics(services)

    expect(result).toEqual({
      totalRequests: 100,
      totalErrors: 10,
      totalWarnings: 5,
      overallErrorRate: 15,
      overallSuccessRate: 85,
    })
  })

  it('calculates correct rates when all requests are successful', () => {
    const services = [
      { total: 100, errorCount: 0, warningCount: 0 },
      { total: 200, errorCount: 0, warningCount: 0 },
    ]

    const result = calculateAggregatedMetrics(services)

    expect(result).toEqual({
      totalRequests: 300,
      totalErrors: 0,
      totalWarnings: 0,
      overallErrorRate: 0,
      overallSuccessRate: 100,
    })
  })

  it('calculates correct rates when all requests fail', () => {
    const services = [
      { total: 100, errorCount: 100, warningCount: 0 },
      { total: 200, errorCount: 200, warningCount: 0 },
    ]

    const result = calculateAggregatedMetrics(services)

    expect(result).toEqual({
      totalRequests: 300,
      totalErrors: 300,
      totalWarnings: 0,
      overallErrorRate: 100,
      overallSuccessRate: 0,
    })
  })

  it('handles mixed success/warning/error scenarios', () => {
    const services = [
      { total: 100, errorCount: 20, warningCount: 30 }, // 50% success
      { total: 100, errorCount: 10, warningCount: 10 }, // 80% success
      { total: 100, errorCount: 0, warningCount: 0 }, // 100% success
    ]

    const result = calculateAggregatedMetrics(services)

    expect(result.totalRequests).toBe(300)
    expect(result.totalErrors).toBe(30)
    expect(result.totalWarnings).toBe(40)
    // Overall: 230 success, 40 warnings, 30 errors out of 300
    expect(result.overallSuccessRate).toBeCloseTo((230 / 300) * 100, 2)
    expect(result.overallErrorRate).toBeCloseTo((70 / 300) * 100, 2)
  })
})
