/**
 * Video Utils Unit Tests
 *
 * Tests for the video utility module.
 * Covers URL parsing, embed URL generation, duration formatting, and validation.
 */

import { describe, it, expect } from 'vitest'
import {
  parseVideoUrl,
  generateEmbedUrl,
  formatDuration,
  parseDuration,
  getAspectRatioClass,
  extractVideoId,
  isValidVideoUrl,
  getVideoPlatform,
  getVideoThumbnail,
  validateVideoUrl,
} from '@/lib/video'

describe('Video Utils', () => {
  describe('parseVideoUrl', () => {
    describe('YouTube URLs', () => {
      it('parses standard watch URL', () => {
        const result = parseVideoUrl('https://www.youtube.com/watch?v=dQw4w9WgXcQ')

        expect(result).not.toBeNull()
        expect(result?.platform).toBe('youtube')
        expect(result?.videoId).toBe('dQw4w9WgXcQ')
        expect(result?.embedUrl).toBe('https://www.youtube.com/embed/dQw4w9WgXcQ')
        expect(result?.thumbnailUrl).toBe('https://img.youtube.com/vi/dQw4w9WgXcQ/maxresdefault.jpg')
      })

      it('parses short URL (youtu.be)', () => {
        const result = parseVideoUrl('https://youtu.be/dQw4w9WgXcQ')

        expect(result?.platform).toBe('youtube')
        expect(result?.videoId).toBe('dQw4w9WgXcQ')
      })

      it('parses embed URL', () => {
        const result = parseVideoUrl('https://www.youtube.com/embed/dQw4w9WgXcQ')

        expect(result?.platform).toBe('youtube')
        expect(result?.videoId).toBe('dQw4w9WgXcQ')
      })

      it('parses youtube-nocookie URL', () => {
        const result = parseVideoUrl('https://www.youtube-nocookie.com/embed/dQw4w9WgXcQ')

        expect(result?.platform).toBe('youtube')
        expect(result?.videoId).toBe('dQw4w9WgXcQ')
      })

      it('parses shorts URL', () => {
        const result = parseVideoUrl('https://www.youtube.com/shorts/dQw4w9WgXcQ')

        expect(result?.platform).toBe('youtube')
        expect(result?.videoId).toBe('dQw4w9WgXcQ')
      })

      it('parses URL with additional parameters', () => {
        const result = parseVideoUrl('https://www.youtube.com/watch?v=dQw4w9WgXcQ&t=120&list=PLrAXtmErZgOeiKm4sgNOknGvNjby9efdf')

        expect(result?.platform).toBe('youtube')
        expect(result?.videoId).toBe('dQw4w9WgXcQ')
      })

      it('handles URL without https://', () => {
        const result = parseVideoUrl('youtube.com/watch?v=dQw4w9WgXcQ')

        expect(result?.platform).toBe('youtube')
        expect(result?.videoId).toBe('dQw4w9WgXcQ')
      })
    })

    describe('Vimeo URLs', () => {
      it('parses standard Vimeo URL', () => {
        const result = parseVideoUrl('https://vimeo.com/123456789')

        expect(result?.platform).toBe('vimeo')
        expect(result?.videoId).toBe('123456789')
        expect(result?.embedUrl).toBe('https://player.vimeo.com/video/123456789')
        expect(result?.thumbnailUrl).toBeNull() // Vimeo needs API call
      })

      it('parses player URL', () => {
        const result = parseVideoUrl('https://player.vimeo.com/video/123456789')

        expect(result?.platform).toBe('vimeo')
        expect(result?.videoId).toBe('123456789')
      })

      it('parses channel URL', () => {
        const result = parseVideoUrl('https://vimeo.com/channels/staffpicks/123456789')

        expect(result?.platform).toBe('vimeo')
        expect(result?.videoId).toBe('123456789')
      })

      it('parses groups URL', () => {
        const result = parseVideoUrl('https://vimeo.com/groups/shortfilms/videos/123456789')

        expect(result?.platform).toBe('vimeo')
        expect(result?.videoId).toBe('123456789')
      })
    })

    describe('External Video URLs', () => {
      it('recognizes direct MP4 URL', () => {
        const result = parseVideoUrl('https://example.com/video.mp4')

        expect(result?.platform).toBe('external')
        expect(result?.videoId).toBeNull()
        expect(result?.embedUrl).toBe('https://example.com/video.mp4')
      })

      it('recognizes WebM URL', () => {
        const result = parseVideoUrl('https://example.com/video.webm')

        expect(result?.platform).toBe('external')
      })

      it('recognizes MOV URL', () => {
        const result = parseVideoUrl('https://cdn.example.com/uploads/movie.mov')

        expect(result?.platform).toBe('external')
      })
    })

    describe('Edge Cases', () => {
      it('returns null for empty string', () => {
        expect(parseVideoUrl('')).toBeNull()
      })

      it('returns null for null input', () => {
        expect(parseVideoUrl(null as unknown as string)).toBeNull()
      })

      it('returns null for undefined input', () => {
        expect(parseVideoUrl(undefined as unknown as string)).toBeNull()
      })

      it('returns unknown for invalid URL', () => {
        const result = parseVideoUrl('https://example.com/page')

        expect(result?.platform).toBe('unknown')
        expect(result?.videoId).toBeNull()
        expect(result?.embedUrl).toBeNull()
      })

      it('handles whitespace', () => {
        const result = parseVideoUrl('  https://www.youtube.com/watch?v=dQw4w9WgXcQ  ')

        expect(result?.platform).toBe('youtube')
        expect(result?.videoId).toBe('dQw4w9WgXcQ')
      })
    })
  })

  describe('generateEmbedUrl', () => {
    const youtubeInfo = {
      platform: 'youtube' as const,
      videoId: 'dQw4w9WgXcQ',
      originalUrl: 'https://www.youtube.com/watch?v=dQw4w9WgXcQ',
      embedUrl: 'https://www.youtube.com/embed/dQw4w9WgXcQ',
      thumbnailUrl: 'https://img.youtube.com/vi/dQw4w9WgXcQ/maxresdefault.jpg',
    }

    const vimeoInfo = {
      platform: 'vimeo' as const,
      videoId: '123456789',
      originalUrl: 'https://vimeo.com/123456789',
      embedUrl: 'https://player.vimeo.com/video/123456789',
      thumbnailUrl: null,
    }

    describe('YouTube', () => {
      it('generates basic embed URL', () => {
        const url = generateEmbedUrl(youtubeInfo)

        expect(url).toContain('youtube.com/embed/dQw4w9WgXcQ')
        expect(url).toContain('modestbranding=1')
      })

      it('adds autoplay parameter', () => {
        const url = generateEmbedUrl(youtubeInfo, { autoplay: true })

        expect(url).toContain('autoplay=1')
      })

      it('adds mute parameter', () => {
        const url = generateEmbedUrl(youtubeInfo, { muted: true })

        expect(url).toContain('mute=1')
      })

      it('adds loop parameter with playlist', () => {
        const url = generateEmbedUrl(youtubeInfo, { loop: true })

        expect(url).toContain('loop=1')
        expect(url).toContain('playlist=dQw4w9WgXcQ')
      })

      it('hides controls when specified', () => {
        const url = generateEmbedUrl(youtubeInfo, { controls: false })

        expect(url).toContain('controls=0')
      })

      it('adds start time', () => {
        const url = generateEmbedUrl(youtubeInfo, { startTime: 120 })

        expect(url).toContain('start=120')
      })

      it('uses privacy mode (youtube-nocookie)', () => {
        const url = generateEmbedUrl(youtubeInfo, { privacyMode: true })

        expect(url).toContain('youtube-nocookie.com')
        expect(url).not.toContain('www.youtube.com')
      })

      it('disables related videos', () => {
        const url = generateEmbedUrl(youtubeInfo, { showRelated: false })

        expect(url).toContain('rel=0')
      })

      it('combines multiple options', () => {
        const url = generateEmbedUrl(youtubeInfo, {
          autoplay: true,
          muted: true,
          loop: true,
          privacyMode: true,
          startTime: 30,
        })

        expect(url).toContain('youtube-nocookie.com')
        expect(url).toContain('autoplay=1')
        expect(url).toContain('mute=1')
        expect(url).toContain('loop=1')
        expect(url).toContain('start=30')
      })
    })

    describe('Vimeo', () => {
      it('generates basic embed URL', () => {
        const url = generateEmbedUrl(vimeoInfo)

        expect(url).toBe('https://player.vimeo.com/video/123456789')
      })

      it('adds autoplay parameter', () => {
        const url = generateEmbedUrl(vimeoInfo, { autoplay: true })

        expect(url).toContain('autoplay=1')
      })

      it('adds muted parameter', () => {
        const url = generateEmbedUrl(vimeoInfo, { muted: true })

        expect(url).toContain('muted=1')
      })

      it('adds loop parameter', () => {
        const url = generateEmbedUrl(vimeoInfo, { loop: true })

        expect(url).toContain('loop=1')
      })

      it('adds start time as hash', () => {
        const url = generateEmbedUrl(vimeoInfo, { startTime: 60 })

        expect(url).toContain('#t=60s')
      })
    })

    describe('Edge Cases', () => {
      it('returns null for null input', () => {
        expect(generateEmbedUrl(null as never)).toBeNull()
      })

      it('returns null for video info without embed URL', () => {
        expect(generateEmbedUrl({ ...youtubeInfo, embedUrl: null })).toBeNull()
      })

      it('floors start time to integer', () => {
        const url = generateEmbedUrl(youtubeInfo, { startTime: 30.5 })

        expect(url).toContain('start=30')
        expect(url).not.toContain('start=30.5')
      })
    })
  })

  describe('formatDuration', () => {
    it('formats seconds under a minute', () => {
      expect(formatDuration(45)).toBe('0:45')
    })

    it('formats minutes and seconds', () => {
      expect(formatDuration(150)).toBe('2:30')
    })

    it('formats hours, minutes, and seconds', () => {
      expect(formatDuration(3723)).toBe('1:02:03')
    })

    it('pads single digits', () => {
      expect(formatDuration(65)).toBe('1:05')
      expect(formatDuration(3605)).toBe('1:00:05')
    })

    it('handles zero', () => {
      expect(formatDuration(0)).toBe('0:00')
    })

    it('handles negative numbers', () => {
      expect(formatDuration(-10)).toBe('0:00')
    })

    it('handles NaN', () => {
      expect(formatDuration(NaN)).toBe('0:00')
    })

    it('handles non-number input', () => {
      expect(formatDuration('invalid' as unknown as number)).toBe('0:00')
    })
  })

  describe('parseDuration', () => {
    it('parses MM:SS format', () => {
      expect(parseDuration('2:30')).toBe(150)
    })

    it('parses HH:MM:SS format', () => {
      expect(parseDuration('1:02:30')).toBe(3750)
    })

    it('parses seconds only', () => {
      expect(parseDuration('90')).toBe(90)
    })

    it('parses "Xh Ym Zs" format', () => {
      expect(parseDuration('1h 30m 45s')).toBe(5445)
    })

    it('parses partial formats', () => {
      expect(parseDuration('2h')).toBe(7200)
      expect(parseDuration('30m')).toBe(1800)
      expect(parseDuration('45s')).toBe(45)
      expect(parseDuration('1h 30m')).toBe(5400)
    })

    it('handles whitespace', () => {
      expect(parseDuration('  2:30  ')).toBe(150)
    })

    it('handles empty string', () => {
      expect(parseDuration('')).toBe(0)
    })

    it('handles null/undefined', () => {
      expect(parseDuration(null as unknown as string)).toBe(0)
      expect(parseDuration(undefined as unknown as string)).toBe(0)
    })

    it('handles invalid input', () => {
      expect(parseDuration('invalid')).toBe(0)
    })
  })

  describe('getAspectRatioClass', () => {
    it('returns aspect-video for 16:9', () => {
      expect(getAspectRatioClass('16:9')).toBe('aspect-video')
    })

    it('returns correct class for 4:3', () => {
      expect(getAspectRatioClass('4:3')).toBe('aspect-[4/3]')
    })

    it('returns aspect-square for 1:1', () => {
      expect(getAspectRatioClass('1:1')).toBe('aspect-square')
    })

    it('returns correct class for 9:16', () => {
      expect(getAspectRatioClass('9:16')).toBe('aspect-[9/16]')
    })

    it('returns correct class for 21:9', () => {
      expect(getAspectRatioClass('21:9')).toBe('aspect-[21/9]')
    })

    it('returns default for unknown ratio', () => {
      expect(getAspectRatioClass('unknown')).toBe('aspect-video')
    })
  })

  describe('extractVideoId', () => {
    it('extracts YouTube video ID', () => {
      expect(extractVideoId('https://www.youtube.com/watch?v=dQw4w9WgXcQ')).toBe('dQw4w9WgXcQ')
    })

    it('extracts Vimeo video ID', () => {
      expect(extractVideoId('https://vimeo.com/123456789')).toBe('123456789')
    })

    it('returns null for external URLs', () => {
      expect(extractVideoId('https://example.com/video.mp4')).toBeNull()
    })

    it('returns null for invalid URLs', () => {
      expect(extractVideoId('not-a-url')).toBeNull()
    })
  })

  describe('isValidVideoUrl', () => {
    it('returns true for YouTube URLs', () => {
      expect(isValidVideoUrl('https://www.youtube.com/watch?v=dQw4w9WgXcQ')).toBe(true)
    })

    it('returns true for Vimeo URLs', () => {
      expect(isValidVideoUrl('https://vimeo.com/123456789')).toBe(true)
    })

    it('returns true for direct video URLs', () => {
      expect(isValidVideoUrl('https://example.com/video.mp4')).toBe(true)
    })

    it('returns false for non-video URLs', () => {
      expect(isValidVideoUrl('https://example.com/page')).toBe(false)
    })

    it('returns false for empty string', () => {
      expect(isValidVideoUrl('')).toBe(false)
    })
  })

  describe('getVideoPlatform', () => {
    it('returns youtube for YouTube URLs', () => {
      expect(getVideoPlatform('https://www.youtube.com/watch?v=dQw4w9WgXcQ')).toBe('youtube')
    })

    it('returns vimeo for Vimeo URLs', () => {
      expect(getVideoPlatform('https://vimeo.com/123456789')).toBe('vimeo')
    })

    it('returns external for direct video URLs', () => {
      expect(getVideoPlatform('https://example.com/video.mp4')).toBe('external')
    })

    it('returns unknown for non-video URLs', () => {
      expect(getVideoPlatform('https://example.com/page')).toBe('unknown')
    })
  })

  describe('getVideoThumbnail', () => {
    it('returns YouTube thumbnail in default quality', () => {
      const url = getVideoThumbnail('https://www.youtube.com/watch?v=dQw4w9WgXcQ', 'default')

      expect(url).toBe('https://img.youtube.com/vi/dQw4w9WgXcQ/default.jpg')
    })

    it('returns YouTube thumbnail in high quality', () => {
      const url = getVideoThumbnail('https://www.youtube.com/watch?v=dQw4w9WgXcQ', 'high')

      expect(url).toBe('https://img.youtube.com/vi/dQw4w9WgXcQ/hqdefault.jpg')
    })

    it('returns YouTube thumbnail in max quality', () => {
      const url = getVideoThumbnail('https://www.youtube.com/watch?v=dQw4w9WgXcQ', 'max')

      expect(url).toBe('https://img.youtube.com/vi/dQw4w9WgXcQ/maxresdefault.jpg')
    })

    it('returns null for Vimeo (requires API)', () => {
      expect(getVideoThumbnail('https://vimeo.com/123456789')).toBeNull()
    })

    it('returns null for external URLs', () => {
      expect(getVideoThumbnail('https://example.com/video.mp4')).toBeNull()
    })

    it('returns null for invalid URLs', () => {
      expect(getVideoThumbnail('not-a-url')).toBeNull()
    })
  })

  describe('validateVideoUrl', () => {
    it('returns valid for YouTube URL', () => {
      const result = validateVideoUrl('https://www.youtube.com/watch?v=dQw4w9WgXcQ')

      expect(result.valid).toBe(true)
      expect(result.error).toBeUndefined()
    })

    it('returns valid for Vimeo URL', () => {
      const result = validateVideoUrl('https://vimeo.com/123456789')

      expect(result.valid).toBe(true)
    })

    it('returns valid for direct video URL', () => {
      const result = validateVideoUrl('https://example.com/video.mp4')

      expect(result.valid).toBe(true)
    })

    it('returns invalid for empty URL', () => {
      const result = validateVideoUrl('')

      expect(result.valid).toBe(false)
      expect(result.error).toBe('URL ist erforderlich')
    })

    it('returns invalid for URL without protocol', () => {
      const result = validateVideoUrl('youtube.com/watch?v=dQw4w9WgXcQ')

      expect(result.valid).toBe(false)
      expect(result.error).toContain('http')
    })

    it('returns invalid for unknown URL format', () => {
      const result = validateVideoUrl('https://example.com/page')

      expect(result.valid).toBe(false)
      expect(result.error).toContain('Unbekanntes Video-Format')
    })
  })
})
