package services

import (
	"fmt"
	"strings"
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestNewHLSPlaylistGenerator(t *testing.T) {
	generator := NewHLSPlaylistGenerator()
	assert.NotNil(t, generator)
}

func TestHLSPlaylistGenerator_GenerateMasterPlaylist(t *testing.T) {
	generator := NewHLSPlaylistGenerator()

	bitrates := []int{128, 192, 320}
	baseURL := "track_123"
	playlist := generator.GenerateMasterPlaylist(bitrates, baseURL)

	// Vérifier l'en-tête HLS
	assert.Contains(t, playlist, "#EXTM3U")
	assert.Contains(t, playlist, "#EXT-X-VERSION:3")

	// Vérifier que tous les bitrates sont présents
	assert.Contains(t, playlist, "128k/playlist.m3u8")
	assert.Contains(t, playlist, "192k/playlist.m3u8")
	assert.Contains(t, playlist, "320k/playlist.m3u8")

	// Vérifier les bandwidths
	assert.Contains(t, playlist, "BANDWIDTH=128000")
	assert.Contains(t, playlist, "BANDWIDTH=192000")
	assert.Contains(t, playlist, "BANDWIDTH=320000")

	// Vérifier le format HLS standard
	lines := strings.Split(strings.TrimSpace(playlist), "\n")
	assert.GreaterOrEqual(t, len(lines), 5) // Au moins 2 lignes d'en-tête + 3 entrées (2 lignes chacune)
}

func TestHLSPlaylistGenerator_GenerateMasterPlaylist_EmptyBitrates(t *testing.T) {
	generator := NewHLSPlaylistGenerator()

	bitrates := []int{}
	baseURL := "track_123"
	playlist := generator.GenerateMasterPlaylist(bitrates, baseURL)

	// Devrait contenir uniquement l'en-tête
	assert.Contains(t, playlist, "#EXTM3U")
	assert.Contains(t, playlist, "#EXT-X-VERSION:3")
	assert.NotContains(t, playlist, "BANDWIDTH")
}

func TestHLSPlaylistGenerator_GenerateMasterPlaylist_SingleBitrate(t *testing.T) {
	generator := NewHLSPlaylistGenerator()

	bitrates := []int{128}
	baseURL := "track_123"
	playlist := generator.GenerateMasterPlaylist(bitrates, baseURL)

	assert.Contains(t, playlist, "#EXTM3U")
	assert.Contains(t, playlist, "#EXT-X-VERSION:3")
	assert.Contains(t, playlist, "128k/playlist.m3u8")
	assert.Contains(t, playlist, "BANDWIDTH=128000")
}

func TestHLSPlaylistGenerator_GenerateMasterPlaylist_UnsortedBitrates(t *testing.T) {
	generator := NewHLSPlaylistGenerator()

	// Bitrates dans un ordre non trié
	bitrates := []int{320, 128, 192}
	baseURL := "track_123"
	playlist := generator.GenerateMasterPlaylist(bitrates, baseURL)

	// Vérifier que les bitrates sont présents
	assert.Contains(t, playlist, "128k/playlist.m3u8")
	assert.Contains(t, playlist, "192k/playlist.m3u8")
	assert.Contains(t, playlist, "320k/playlist.m3u8")

	// Vérifier que les bandwidths sont dans l'ordre croissant
	lines := strings.Split(strings.TrimSpace(playlist), "\n")

	// Trouver les lignes BANDWIDTH
	var bandwidthLines []string
	for _, line := range lines {
		if strings.Contains(line, "BANDWIDTH=") {
			bandwidthLines = append(bandwidthLines, line)
		}
	}

	// Vérifier qu'il y a 3 lignes de bandwidth
	assert.Equal(t, 3, len(bandwidthLines))

	// Vérifier que les bandwidths sont triés (128k, 192k, 320k)
	assert.Contains(t, bandwidthLines[0], "128000")
	assert.Contains(t, bandwidthLines[1], "192000")
	assert.Contains(t, bandwidthLines[2], "320000")
}

func TestHLSPlaylistGenerator_GenerateMasterPlaylist_BandwidthCalculation(t *testing.T) {
	generator := NewHLSPlaylistGenerator()

	bitrates := []int{64, 128, 256}
	baseURL := "track_123"
	playlist := generator.GenerateMasterPlaylist(bitrates, baseURL)

	// Vérifier que les bandwidths sont calculés correctement (bitrate * 1000)
	assert.Contains(t, playlist, "BANDWIDTH=64000")  // 64 * 1000
	assert.Contains(t, playlist, "BANDWIDTH=128000") // 128 * 1000
	assert.Contains(t, playlist, "BANDWIDTH=256000") // 256 * 1000
}

func TestHLSPlaylistGenerator_GenerateMasterPlaylist_BaseURL(t *testing.T) {
	generator := NewHLSPlaylistGenerator()

	bitrates := []int{128}
	baseURL := "http://example.com/tracks/123"
	playlist := generator.GenerateMasterPlaylist(bitrates, baseURL)

	// Vérifier que le baseURL est utilisé correctement
	assert.Contains(t, playlist, "http://example.com/tracks/123/128k/playlist.m3u8")
}

func TestHLSPlaylistGenerator_GenerateMasterPlaylist_FormatHLS(t *testing.T) {
	generator := NewHLSPlaylistGenerator()

	bitrates := []int{128, 192}
	baseURL := "track_123"
	playlist := generator.GenerateMasterPlaylist(bitrates, baseURL)

	// Vérifier le format HLS standard
	lines := strings.Split(strings.TrimSpace(playlist), "\n")

	// Première ligne doit être #EXTM3U
	assert.Equal(t, "#EXTM3U", lines[0])

	// Deuxième ligne doit être #EXT-X-VERSION:3
	assert.Equal(t, "#EXT-X-VERSION:3", lines[1])

	// Les lignes suivantes doivent alterner entre #EXT-X-STREAM-INF et l'URL
	// Format attendu:
	// #EXTM3U
	// #EXT-X-VERSION:3
	// #EXT-X-STREAM-INF:BANDWIDTH=128000
	// track_123/128k/playlist.m3u8
	// #EXT-X-STREAM-INF:BANDWIDTH=192000
	// track_123/192k/playlist.m3u8

	assert.GreaterOrEqual(t, len(lines), 6) // Au moins 2 lignes d'en-tête + 4 lignes pour 2 bitrates
}

func TestHLSPlaylistGenerator_GenerateMasterPlaylistWithCodecs(t *testing.T) {
	generator := NewHLSPlaylistGenerator()

	bitrates := []int{128, 192}
	baseURL := "track_123"
	codec := "mp4a.40.2"
	playlist := generator.GenerateMasterPlaylistWithCodecs(bitrates, baseURL, codec)

	// Vérifier l'en-tête
	assert.Contains(t, playlist, "#EXTM3U")
	assert.Contains(t, playlist, "#EXT-X-VERSION:3")

	// Vérifier que les codecs sont présents
	assert.Contains(t, playlist, "CODECS=\"mp4a.40.2\"")

	// Vérifier que les bitrates sont présents
	assert.Contains(t, playlist, "128k/playlist.m3u8")
	assert.Contains(t, playlist, "192k/playlist.m3u8")

	// Vérifier les bandwidths
	assert.Contains(t, playlist, "BANDWIDTH=128000")
	assert.Contains(t, playlist, "BANDWIDTH=192000")
}

func TestHLSPlaylistGenerator_GenerateMasterPlaylistWithCodecs_EmptyBitrates(t *testing.T) {
	generator := NewHLSPlaylistGenerator()

	bitrates := []int{}
	baseURL := "track_123"
	codec := "mp4a.40.2"
	playlist := generator.GenerateMasterPlaylistWithCodecs(bitrates, baseURL, codec)

	// Devrait contenir uniquement l'en-tête
	assert.Contains(t, playlist, "#EXTM3U")
	assert.Contains(t, playlist, "#EXT-X-VERSION:3")
	assert.NotContains(t, playlist, "CODECS")
	assert.NotContains(t, playlist, "BANDWIDTH")
}

func TestHLSPlaylistGenerator_GenerateMasterPlaylist_MultipleBitrates(t *testing.T) {
	generator := NewHLSPlaylistGenerator()

	// Tester avec plusieurs bitrates
	bitrates := []int{64, 96, 128, 192, 256, 320}
	baseURL := "track_123"
	playlist := generator.GenerateMasterPlaylist(bitrates, baseURL)

	// Vérifier que tous les bitrates sont présents
	for _, bitrate := range bitrates {
		assert.Contains(t, playlist, fmt.Sprintf("%dk/playlist.m3u8", bitrate))
		assert.Contains(t, playlist, fmt.Sprintf("BANDWIDTH=%d000", bitrate))
	}

	// Vérifier que les bitrates sont triés
	lines := strings.Split(strings.TrimSpace(playlist), "\n")
	var bandwidthValues []int
	for _, line := range lines {
		if strings.Contains(line, "BANDWIDTH=") {
			// Extraire la valeur de bandwidth
			parts := strings.Split(line, "=")
			if len(parts) == 2 {
				var bw int
				if _, err := fmt.Sscanf(parts[1], "%d", &bw); err == nil {
					bandwidthValues = append(bandwidthValues, bw)
				}
			}
		}
	}

	// Vérifier que les bandwidths sont triés par ordre croissant
	for i := 1; i < len(bandwidthValues); i++ {
		assert.GreaterOrEqual(t, bandwidthValues[i], bandwidthValues[i-1], "Bandwidths should be sorted in ascending order")
	}
}

func TestHLSPlaylistGenerator_GenerateQualityPlaylist(t *testing.T) {
	generator := NewHLSPlaylistGenerator()

	segments := []string{"segment_000.ts", "segment_001.ts", "segment_002.ts"}
	segmentDuration := 10.0
	playlist := generator.GenerateQualityPlaylist(segments, segmentDuration)

	// Vérifier l'en-tête HLS
	assert.Contains(t, playlist, "#EXTM3U")
	assert.Contains(t, playlist, "#EXT-X-VERSION:3")
	assert.Contains(t, playlist, "#EXT-X-TARGETDURATION:10")
	assert.Contains(t, playlist, "#EXT-X-MEDIA-SEQUENCE:0")
	assert.Contains(t, playlist, "#EXT-X-PLAYLIST-TYPE:VOD")
	assert.Contains(t, playlist, "#EXT-X-ENDLIST")

	// Vérifier que tous les segments sont présents
	for _, segment := range segments {
		assert.Contains(t, playlist, segment)
	}

	// Vérifier le format EXTINF
	assert.Contains(t, playlist, "#EXTINF:10.00,")
}

func TestHLSPlaylistGenerator_GenerateQualityPlaylist_EmptySegments(t *testing.T) {
	generator := NewHLSPlaylistGenerator()

	segments := []string{}
	segmentDuration := 10.0
	playlist := generator.GenerateQualityPlaylist(segments, segmentDuration)

	// Devrait contenir l'en-tête et ENDLIST
	assert.Contains(t, playlist, "#EXTM3U")
	assert.Contains(t, playlist, "#EXT-X-VERSION:3")
	assert.Contains(t, playlist, "#EXT-X-ENDLIST")
	assert.NotContains(t, playlist, "#EXTINF")
}

func TestHLSPlaylistGenerator_GenerateQualityPlaylist_SingleSegment(t *testing.T) {
	generator := NewHLSPlaylistGenerator()

	segments := []string{"segment_000.ts"}
	segmentDuration := 5.5
	playlist := generator.GenerateQualityPlaylist(segments, segmentDuration)

	assert.Contains(t, playlist, "#EXTM3U")
	assert.Contains(t, playlist, "#EXT-X-VERSION:3")
	assert.Contains(t, playlist, "#EXT-X-TARGETDURATION:6") // Arrondi à l'entier supérieur
	assert.Contains(t, playlist, "segment_000.ts")
	assert.Contains(t, playlist, "#EXTINF:5.50,")
	assert.Contains(t, playlist, "#EXT-X-ENDLIST")
}

func TestHLSPlaylistGenerator_GenerateQualityPlaylist_TargetDurationRounding(t *testing.T) {
	generator := NewHLSPlaylistGenerator()

	segments := []string{"segment_000.ts"}
	segmentDuration := 10.1
	playlist := generator.GenerateQualityPlaylist(segments, segmentDuration)

	// TARGETDURATION doit être arrondi à l'entier supérieur
	assert.Contains(t, playlist, "#EXT-X-TARGETDURATION:11")
}

func TestHLSPlaylistGenerator_GenerateQualityPlaylist_MultipleSegments(t *testing.T) {
	generator := NewHLSPlaylistGenerator()

	segments := []string{"segment_000.ts", "segment_001.ts", "segment_002.ts", "segment_003.ts"}
	segmentDuration := 10.0
	playlist := generator.GenerateQualityPlaylist(segments, segmentDuration)

	// Vérifier que tous les segments sont présents
	for i, segment := range segments {
		assert.Contains(t, playlist, segment, "Segment %d should be present", i)
	}

	// Vérifier le format: chaque segment doit avoir son EXTINF
	lines := strings.Split(strings.TrimSpace(playlist), "\n")
	extinfCount := 0
	for _, line := range lines {
		if strings.HasPrefix(line, "#EXTINF:") {
			extinfCount++
		}
	}
	assert.Equal(t, len(segments), extinfCount, "Should have one EXTINF per segment")
}

func TestHLSPlaylistGenerator_GenerateQualityPlaylist_FormatHLS(t *testing.T) {
	generator := NewHLSPlaylistGenerator()

	segments := []string{"segment_000.ts", "segment_001.ts"}
	segmentDuration := 10.0
	playlist := generator.GenerateQualityPlaylist(segments, segmentDuration)

	// Vérifier le format HLS standard
	lines := strings.Split(strings.TrimSpace(playlist), "\n")

	// Première ligne doit être #EXTM3U
	assert.Equal(t, "#EXTM3U", lines[0])

	// Deuxième ligne doit être #EXT-X-VERSION:3
	assert.Equal(t, "#EXT-X-VERSION:3", lines[1])

	// Vérifier que les segments alternent avec EXTINF
	// Format attendu:
	// #EXTM3U
	// #EXT-X-VERSION:3
	// #EXT-X-TARGETDURATION:10
	// #EXT-X-MEDIA-SEQUENCE:0
	// #EXT-X-PLAYLIST-TYPE:VOD
	// (ligne vide)
	// #EXTINF:10.00,
	// segment_000.ts
	// #EXTINF:10.00,
	// segment_001.ts
	// #EXT-X-ENDLIST

	assert.GreaterOrEqual(t, len(lines), 8) // Au moins 5 lignes d'en-tête + 2 segments (2 lignes chacun) + ENDLIST
}

func TestHLSPlaylistGenerator_GenerateQualityPlaylist_DurationPrecision(t *testing.T) {
	generator := NewHLSPlaylistGenerator()

	segments := []string{"segment_000.ts"}
	segmentDuration := 9.999
	playlist := generator.GenerateQualityPlaylist(segments, segmentDuration)

	// Vérifier que la durée est formatée avec 2 décimales
	assert.Contains(t, playlist, "#EXTINF:10.00,")
}

func TestHLSPlaylistGenerator_GenerateQualityPlaylistWithVariableDurations(t *testing.T) {
	generator := NewHLSPlaylistGenerator()

	segments := []SegmentInfo{
		{Filename: "segment_000.ts", Duration: 10.0},
		{Filename: "segment_001.ts", Duration: 9.5},
		{Filename: "segment_002.ts", Duration: 10.2},
	}
	playlist := generator.GenerateQualityPlaylistWithVariableDurations(segments)

	// Vérifier l'en-tête
	assert.Contains(t, playlist, "#EXTM3U")
	assert.Contains(t, playlist, "#EXT-X-VERSION:3")
	assert.Contains(t, playlist, "#EXT-X-TARGETDURATION:11") // Max duration rounded up
	assert.Contains(t, playlist, "#EXT-X-MEDIA-SEQUENCE:0")
	assert.Contains(t, playlist, "#EXT-X-PLAYLIST-TYPE:VOD")
	assert.Contains(t, playlist, "#EXT-X-ENDLIST")

	// Vérifier que tous les segments sont présents avec leurs durées
	assert.Contains(t, playlist, "segment_000.ts")
	assert.Contains(t, playlist, "#EXTINF:10.00,")
	assert.Contains(t, playlist, "segment_001.ts")
	assert.Contains(t, playlist, "#EXTINF:9.50,")
	assert.Contains(t, playlist, "segment_002.ts")
	assert.Contains(t, playlist, "#EXTINF:10.20,")
}

func TestHLSPlaylistGenerator_GenerateQualityPlaylistWithVariableDurations_Empty(t *testing.T) {
	generator := NewHLSPlaylistGenerator()

	segments := []SegmentInfo{}
	playlist := generator.GenerateQualityPlaylistWithVariableDurations(segments)

	// Devrait contenir uniquement l'en-tête minimal
	assert.Contains(t, playlist, "#EXTM3U")
	assert.Contains(t, playlist, "#EXT-X-VERSION:3")
	assert.Contains(t, playlist, "#EXT-X-ENDLIST")
	assert.NotContains(t, playlist, "#EXTINF")
}
