/**
 * YouTube Analytics Helpers Unit Tests
 *
 * Tests comparison, trend, and ROI calculation functions
 * used by the analytics API route.
 */

import { describe, it, expect } from 'vitest'
import {
  calculateComparison,
  calculateTrends,
  calculateROI,
} from '@/lib/youtube/analytics-helpers'
import type { VideoWithPerformance } from '@/lib/youtube/analytics-helpers'

const mockVideos: VideoWithPerformance[] = [
  {
    id: 1,
    title: 'Video A',
    performance: { views: 1000, likes: 50, ctr: 5.2, watchTimeMinutes: 300 },
    costs: { estimatedProductionCost: 100, estimatedRevenue: 200 },
  },
  {
    id: 2,
    title: 'Video B',
    performance: { views: 2000, likes: 80, ctr: 3.1, watchTimeMinutes: 600 },
    costs: { estimatedProductionCost: 150, estimatedRevenue: 100 },
  },
  {
    id: 3,
    title: 'Video C',
    performance: { views: 500, likes: 20, ctr: 7.0, watchTimeMinutes: 150 },
    costs: { estimatedProductionCost: 50, estimatedRevenue: 75 },
  },
]

describe('Analytics Helpers', () => {
  describe('calculateComparison', () => {
    it('should return comparison metrics for all videos', () => {
      const result = calculateComparison(mockVideos, 'views')

      expect(result).toHaveLength(3)
      expect(result[0]).toEqual({ videoId: 1, title: 'Video A', value: 1000 })
      expect(result[1]).toEqual({ videoId: 2, title: 'Video B', value: 2000 })
      expect(result[2]).toEqual({ videoId: 3, title: 'Video C', value: 500 })
    })

    it('should handle different metrics', () => {
      const result = calculateComparison(mockVideos, 'likes')

      expect(result[0].value).toBe(50)
      expect(result[1].value).toBe(80)
      expect(result[2].value).toBe(20)
    })

    it('should return 0 for missing metric values', () => {
      const sparse: VideoWithPerformance[] = [
        { id: 10, title: 'Sparse', performance: {} },
      ]
      const result = calculateComparison(sparse, 'impressions')

      expect(result).toHaveLength(1)
      expect(result[0].value).toBe(0)
    })

    it('should return an empty array for empty input', () => {
      const result = calculateComparison([], 'views')
      expect(result).toEqual([])
    })
  })

  describe('calculateTrends', () => {
    it('should detect an upward trend when latest exceeds average', () => {
      const result = calculateTrends(mockVideos, 'views')

      expect(result.trend).toBeDefined()
      expect(result.average).toBeDefined()
      expect(result.latest).toBeDefined()
      expect(result.growth).toBeDefined()
      expect(result.min).toBeDefined()
      expect(result.max).toBeDefined()
    })

    it('should return insufficient_data for fewer than 2 videos', () => {
      const result = calculateTrends([mockVideos[0]], 'views')

      expect(result.trend).toBe('insufficient_data')
      expect(result.growth).toBe(0)
      expect(result.average).toBeUndefined()
    })

    it('should return insufficient_data for an empty array', () => {
      const result = calculateTrends([], 'views')

      expect(result.trend).toBe('insufficient_data')
      expect(result.growth).toBe(0)
    })

    it('should compute correct average and min/max', () => {
      const result = calculateTrends(mockVideos, 'views')
      // Values sorted: 500, 1000, 2000
      // avg = (500 + 1000 + 2000) / 3 = ~1166.67
      const expectedAvg = (500 + 1000 + 2000) / 3

      expect(result.average).toBeCloseTo(expectedAvg)
      expect(result.min).toBe(500)
      expect(result.max).toBe(2000)
    })

    it('should calculate growth percentage relative to average', () => {
      const result = calculateTrends(mockVideos, 'views')
      const expectedAvg = (500 + 1000 + 2000) / 3
      const expectedGrowth = ((2000 - expectedAvg) / expectedAvg) * 100

      expect(result.growth).toBeCloseTo(expectedGrowth)
    })

    it('should return stable trend when latest equals average', () => {
      const equal: VideoWithPerformance[] = [
        { id: 1, title: 'A', performance: { views: 100 } },
        { id: 2, title: 'B', performance: { views: 100 } },
      ]
      const result = calculateTrends(equal, 'views')

      expect(result.trend).toBe('stable')
      expect(result.growth).toBe(0)
    })

    it('should handle zero values gracefully', () => {
      const zeros: VideoWithPerformance[] = [
        { id: 1, title: 'A', performance: { views: 0 } },
        { id: 2, title: 'B', performance: { views: 0 } },
      ]
      const result = calculateTrends(zeros, 'views')

      expect(result.trend).toBe('stable')
      expect(result.growth).toBe(0)
      expect(result.average).toBe(0)
    })
  })

  describe('calculateROI', () => {
    it('should calculate ROI for videos with cost data', () => {
      const result = calculateROI(mockVideos)

      expect(result).toHaveLength(3)
    })

    it('should compute correct ROI percentage', () => {
      const result = calculateROI(mockVideos)
      const videoA = result.find((r) => r.videoId === 1)!

      // ROI = (200 - 100) / 100 * 100 = 100%
      expect(videoA.roi).toBe(100)
      expect(videoA.cost).toBe(100)
      expect(videoA.revenue).toBe(200)
    })

    it('should compute correct cost-per-view', () => {
      const result = calculateROI(mockVideos)
      const videoA = result.find((r) => r.videoId === 1)!

      // CPV = 100 / 1000 = 0.1
      expect(videoA.cpv).toBeCloseTo(0.1)
    })

    it('should compute correct revenue-per-view', () => {
      const result = calculateROI(mockVideos)
      const videoB = result.find((r) => r.videoId === 2)!

      // revenuePerView = 100 / 2000 = 0.05
      expect(videoB.revenuePerView).toBeCloseTo(0.05)
    })

    it('should handle negative ROI', () => {
      const result = calculateROI(mockVideos)
      const videoB = result.find((r) => r.videoId === 2)!

      // ROI = (100 - 150) / 150 * 100 = -33.33%
      expect(videoB.roi).toBeCloseTo(-33.33, 1)
    })

    it('should skip videos without cost data', () => {
      const noCost: VideoWithPerformance[] = [
        { id: 10, title: 'No Cost', performance: { views: 500 } },
      ]
      const result = calculateROI(noCost)

      expect(result).toHaveLength(0)
    })

    it('should skip videos with zero production cost', () => {
      const zeroCost: VideoWithPerformance[] = [
        {
          id: 10,
          title: 'Zero Cost',
          performance: { views: 500 },
          costs: { estimatedProductionCost: 0, estimatedRevenue: 100 },
        },
      ]
      const result = calculateROI(zeroCost)

      expect(result).toHaveLength(0)
    })

    it('should handle videos with zero views', () => {
      const zeroViews: VideoWithPerformance[] = [
        {
          id: 10,
          title: 'Zero Views',
          performance: { views: 0 },
          costs: { estimatedProductionCost: 100, estimatedRevenue: 0 },
        },
      ]
      const result = calculateROI(zeroViews)

      expect(result).toHaveLength(1)
      expect(result[0].cpv).toBe(0)
      expect(result[0].revenuePerView).toBe(0)
    })

    it('should handle missing revenue', () => {
      const noRevenue: VideoWithPerformance[] = [
        {
          id: 10,
          title: 'No Revenue',
          performance: { views: 100 },
          costs: { estimatedProductionCost: 50 },
        },
      ]
      const result = calculateROI(noRevenue)

      expect(result).toHaveLength(1)
      expect(result[0].revenue).toBe(0)
      // ROI = (0 - 50) / 50 * 100 = -100%
      expect(result[0].roi).toBe(-100)
    })
  })
})
