package services

import (
	"testing"
	"time"

	"go.uber.org/zap"
)

func TestNewAudioTranscodeService(t *testing.T) {
	logger := zap.NewNop()
	service := NewAudioTranscodeService("", logger)

	if service == nil {
		t.Error("NewAudioTranscodeService() returned nil")
	}
	if service.logger == nil {
		t.Error("NewAudioTranscodeService() returned service with nil logger")
	}
	if service.ffmpegPath == "" {
		t.Error("NewAudioTranscodeService() should set default ffmpeg path")
	}
}

func TestAudioTranscodeService_GetSupportedFormats(t *testing.T) {
	service := NewAudioTranscodeService("", zap.NewNop())
	formats := service.GetSupportedFormats()

	if len(formats) == 0 {
		t.Error("GetSupportedFormats() returned empty list")
	}

	// Check that common formats are included
	expectedFormats := []AudioFormat{FormatMP3, FormatAAC, FormatFLAC, FormatOGG, FormatWAV}
	for _, expected := range expectedFormats {
		found := false
		for _, format := range formats {
			if format == expected {
				found = true
				break
			}
		}
		if !found {
			t.Errorf("GetSupportedFormats() missing format: %s", expected)
		}
	}
}

func TestAudioTranscodeService_ValidateFormat(t *testing.T) {
	service := NewAudioTranscodeService("", zap.NewNop())

	tests := []struct {
		name     string
		format   AudioFormat
		expected bool
	}{
		{
			name:     "valid MP3 format",
			format:   FormatMP3,
			expected: true,
		},
		{
			name:     "valid AAC format",
			format:   FormatAAC,
			expected: true,
		},
		{
			name:     "valid FLAC format",
			format:   FormatFLAC,
			expected: true,
		},
		{
			name:     "invalid format",
			format:   AudioFormat("invalid"),
			expected: false,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result := service.ValidateFormat(tt.format)
			if result != tt.expected {
				t.Errorf("ValidateFormat(%s) = %v, want %v", tt.format, result, tt.expected)
			}
		})
	}
}

func TestAudioTranscodeService_getCodecForFormat(t *testing.T) {
	service := NewAudioTranscodeService("", zap.NewNop())

	tests := []struct {
		name     string
		format   AudioFormat
		expected string
	}{
		{
			name:     "MP3 codec",
			format:   FormatMP3,
			expected: "libmp3lame",
		},
		{
			name:     "AAC codec",
			format:   FormatAAC,
			expected: "aac",
		},
		{
			name:     "FLAC codec",
			format:   FormatFLAC,
			expected: "flac",
		},
		{
			name:     "OGG codec",
			format:   FormatOGG,
			expected: "libvorbis",
		},
		{
			name:     "WAV codec",
			format:   FormatWAV,
			expected: "pcm_s16le",
		},
		{
			name:     "M4A codec",
			format:   FormatM4A,
			expected: "aac",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result := service.getCodecForFormat(tt.format)
			if result != tt.expected {
				t.Errorf("getCodecForFormat(%s) = %s, want %s", tt.format, result, tt.expected)
			}
		})
	}
}

func TestAudioTranscodeService_getBitrateForQuality(t *testing.T) {
	service := NewAudioTranscodeService("", zap.NewNop())

	tests := []struct {
		name     string
		quality  AudioQuality
		format   AudioFormat
		expected int
	}{
		{
			name:     "low quality MP3",
			quality:  QualityLow,
			format:   FormatMP3,
			expected: 96,
		},
		{
			name:     "low quality AAC",
			quality:  QualityLow,
			format:   FormatAAC,
			expected: 64,
		},
		{
			name:     "medium quality MP3",
			quality:  QualityMedium,
			format:   FormatMP3,
			expected: 192,
		},
		{
			name:     "medium quality AAC",
			quality:  QualityMedium,
			format:   FormatAAC,
			expected: 128,
		},
		{
			name:     "high quality MP3",
			quality:  QualityHigh,
			format:   FormatMP3,
			expected: 320,
		},
		{
			name:     "high quality AAC",
			quality:  QualityHigh,
			format:   FormatAAC,
			expected: 256,
		},
		{
			name:     "lossless FLAC",
			quality:  QualityLossless,
			format:   FormatFLAC,
			expected: 0,
		},
		{
			name:     "lossless WAV",
			quality:  QualityLossless,
			format:   FormatWAV,
			expected: 0,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result := service.getBitrateForQuality(tt.quality, tt.format)
			if result != tt.expected {
				t.Errorf("getBitrateForQuality(%s, %s) = %d, want %d", tt.quality, tt.format, result, tt.expected)
			}
		})
	}
}

func TestTranscodeOptions_Defaults(t *testing.T) {
	options := TranscodeOptions{}

	// Test that defaults are applied in Transcode method
	if options.Format == "" {
		options.Format = FormatMP3
	}
	if options.Timeout == 0 {
		options.Timeout = 5 * time.Minute
	}

	if options.Format != FormatMP3 {
		t.Errorf("Expected default format MP3, got %v", options.Format)
	}
	if options.Timeout != 5*time.Minute {
		t.Errorf("Expected default timeout 5 minutes, got %v", options.Timeout)
	}
}

func TestAudioTranscodeService_buildFFmpegArgs(t *testing.T) {
	service := NewAudioTranscodeService("", zap.NewNop())

	tests := []struct {
		name    string
		input   string
		output  string
		options TranscodeOptions
		bitrate int
		checkFn func([]string) bool
	}{
		{
			name:   "MP3 with bitrate",
			input:  "input.mp3",
			output: "output.mp3",
			options: TranscodeOptions{
				Format: FormatMP3,
			},
			bitrate: 192,
			checkFn: func(args []string) bool {
				hasCodec := false
				hasBitrate := false
				for i, arg := range args {
					if arg == "-codec:a" && i+1 < len(args) && args[i+1] == "libmp3lame" {
						hasCodec = true
					}
					if arg == "-b:a" && i+1 < len(args) && args[i+1] == "192k" {
						hasBitrate = true
					}
				}
				return hasCodec && hasBitrate
			},
		},
		{
			name:   "FLAC with compression",
			input:  "input.wav",
			output: "output.flac",
			options: TranscodeOptions{
				Format: FormatFLAC,
			},
			bitrate: 0,
			checkFn: func(args []string) bool {
				hasCodec := false
				hasCompression := false
				for i, arg := range args {
					if arg == "-codec:a" && i+1 < len(args) && args[i+1] == "flac" {
						hasCodec = true
					}
					if arg == "-compression_level" && i+1 < len(args) && args[i+1] == "5" {
						hasCompression = true
					}
				}
				return hasCodec && hasCompression
			},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			args := service.buildFFmpegArgs(tt.input, tt.output, tt.options, tt.bitrate)
			if !tt.checkFn(args) {
				t.Errorf("buildFFmpegArgs() did not produce expected arguments")
			}
		})
	}
}

// Note: Full integration tests would require:
// 1. FFmpeg installed on the system
// 2. Test audio files (MP3, WAV, FLAC, etc.)
// 3. Verification of transcoded output files
// 4. Performance testing with large files
//
// Example integration test structure:
// func TestAudioTranscodeService_Transcode_Integration(t *testing.T) {
//     // Skip if FFmpeg not available
//     service := NewAudioTranscodeService("", zap.NewNop())
//     ctx := context.Background()
//     if !service.IsFFmpegAvailable(ctx) {
//         t.Skip("FFmpeg not available")
//     }
//
//     // Create test audio file
//     testFile := createTestAudioFile(t)
//     defer os.Remove(testFile)
//
//     options := TranscodeOptions{
//         Format:  FormatMP3,
//         Quality: QualityMedium,
//     }
//
//     result, err := service.Transcode(ctx, testFile, options)
//     if err != nil {
//         t.Fatalf("Transcode() error = %v", err)
//     }
//
//     if result.Format != FormatMP3 {
//         t.Errorf("Transcode() format = %v, want %v", result.Format, FormatMP3)
//     }
//
//     if result.FileSize == 0 {
//         t.Error("Transcode() produced empty file")
//     }
// }
