//go:build cgo
// +build cgo

package audio

import (
	"fmt"
	"testing"
	"time"

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

// TestValidationFunctions provides comprehensive testing of all validation functions
// to ensure they catch breaking changes and regressions effectively
func TestValidationFunctions(t *testing.T) {
	tests := []struct {
		name     string
		testFunc func(t *testing.T)
	}{
		{"AudioQualityValidation", testAudioQualityValidation},
		{"FrameDataValidation", testFrameDataValidation},
		{"BufferSizeValidation", testBufferSizeValidation},
		{"ThreadPriorityValidation", testThreadPriorityValidation},
		{"LatencyValidation", testLatencyValidation},
		{"MetricsIntervalValidation", testMetricsIntervalValidation},
		{"SampleRateValidation", testSampleRateValidation},
		{"ChannelCountValidation", testChannelCountValidation},
		{"BitrateValidation", testBitrateValidation},
		{"FrameDurationValidation", testFrameDurationValidation},
		{"IPCConfigValidation", testIPCConfigValidation},
		{"AdaptiveBufferConfigValidation", testAdaptiveBufferConfigValidation},
		{"AudioConfigCompleteValidation", testAudioConfigCompleteValidation},
		{"ZeroCopyFrameValidation", testZeroCopyFrameValidation},
		{"AudioFrameFastValidation", testAudioFrameFastValidation},
		{"ErrorWrappingValidation", testErrorWrappingValidation},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			tt.testFunc(t)
		})
	}
}

// testAudioQualityValidation tests audio quality validation with boundary conditions
func testAudioQualityValidation(t *testing.T) {
	// Test valid quality levels
	validQualities := []AudioQuality{AudioQualityLow, AudioQualityMedium, AudioQualityHigh, AudioQualityUltra}
	for _, quality := range validQualities {
		err := ValidateAudioQuality(quality)
		assert.NoError(t, err, "Valid quality %d should pass validation", quality)
	}

	// Test invalid quality levels
	invalidQualities := []AudioQuality{-1, 4, 100, -100}
	for _, quality := range invalidQualities {
		err := ValidateAudioQuality(quality)
		assert.Error(t, err, "Invalid quality %d should fail validation", quality)
		assert.Contains(t, err.Error(), "invalid audio quality level", "Error should mention audio quality")
	}
}

// testFrameDataValidation tests frame data validation with various edge cases
func testFrameDataValidation(t *testing.T) {
	config := GetConfig()

	// Test nil data
	err := ValidateFrameData(nil)
	assert.Error(t, err)
	assert.Contains(t, err.Error(), "frame data is nil")

	// Test empty data
	err = ValidateFrameData([]byte{})
	assert.Error(t, err)
	assert.Contains(t, err.Error(), "frame data is empty")

	// Test data below minimum size
	if config.MinFrameSize > 0 {
		smallData := make([]byte, config.MinFrameSize-1)
		err = ValidateFrameData(smallData)
		assert.Error(t, err)
		assert.Contains(t, err.Error(), "below minimum")
	}

	// Test data above maximum size
	largeData := make([]byte, config.MaxAudioFrameSize+1)
	err = ValidateFrameData(largeData)
	assert.Error(t, err)
	assert.Contains(t, err.Error(), "exceeds maximum")

	// Test unaligned data (odd number of bytes for 16-bit samples)
	oddData := make([]byte, 1001) // Odd number
	if len(oddData) >= config.MinFrameSize {
		err = ValidateFrameData(oddData)
		assert.Error(t, err)
		assert.Contains(t, err.Error(), "not aligned")
	}

	// Test valid aligned data
	validData := make([]byte, 1000) // Even number, within bounds
	if len(validData) >= config.MinFrameSize && len(validData) <= config.MaxAudioFrameSize {
		err = ValidateFrameData(validData)
		assert.NoError(t, err)
	}
}

// testBufferSizeValidation tests buffer size validation
func testBufferSizeValidation(t *testing.T) {
	config := GetConfig()

	// Test negative and zero sizes
	invalidSizes := []int{-1, -100, 0}
	for _, size := range invalidSizes {
		err := ValidateBufferSize(size)
		assert.Error(t, err, "Buffer size %d should be invalid", size)
		assert.Contains(t, err.Error(), "must be positive")
	}

	// Test size exceeding maximum
	err := ValidateBufferSize(config.SocketMaxBuffer + 1)
	assert.Error(t, err)
	assert.Contains(t, err.Error(), "exceeds maximum")

	// Test valid sizes
	validSizes := []int{1, 1024, 4096, config.SocketMaxBuffer}
	for _, size := range validSizes {
		err := ValidateBufferSize(size)
		assert.NoError(t, err, "Buffer size %d should be valid", size)
	}
}

// testThreadPriorityValidation tests thread priority validation
func testThreadPriorityValidation(t *testing.T) {
	// Test valid priorities
	validPriorities := []int{-20, -10, 0, 10, 19}
	for _, priority := range validPriorities {
		err := ValidateThreadPriority(priority)
		assert.NoError(t, err, "Priority %d should be valid", priority)
	}

	// Test invalid priorities
	invalidPriorities := []int{-21, -100, 20, 100}
	for _, priority := range invalidPriorities {
		err := ValidateThreadPriority(priority)
		assert.Error(t, err, "Priority %d should be invalid", priority)
		assert.Contains(t, err.Error(), "outside valid range")
	}
}

// testLatencyValidation tests latency validation
func testLatencyValidation(t *testing.T) {
	config := GetConfig()

	// Test negative latency
	err := ValidateLatency(-1 * time.Millisecond)
	assert.Error(t, err)
	assert.Contains(t, err.Error(), "cannot be negative")

	// Test zero latency (should be valid)
	err = ValidateLatency(0)
	assert.NoError(t, err)

	// Test very small positive latency
	err = ValidateLatency(500 * time.Microsecond)
	assert.Error(t, err)
	assert.Contains(t, err.Error(), "below minimum")

	// Test latency exceeding maximum
	err = ValidateLatency(config.MaxLatency + time.Second)
	assert.Error(t, err)
	assert.Contains(t, err.Error(), "exceeds maximum")

	// Test valid latencies
	validLatencies := []time.Duration{
		1 * time.Millisecond,
		10 * time.Millisecond,
		100 * time.Millisecond,
		config.MaxLatency,
	}
	for _, latency := range validLatencies {
		err := ValidateLatency(latency)
		assert.NoError(t, err, "Latency %v should be valid", latency)
	}
}

// testMetricsIntervalValidation tests metrics interval validation
func testMetricsIntervalValidation(t *testing.T) {
	config := GetConfig()

	// Test interval below minimum
	err := ValidateMetricsInterval(config.MinMetricsUpdateInterval - time.Millisecond)
	assert.Error(t, err)

	// Test interval above maximum
	err = ValidateMetricsInterval(config.MaxMetricsUpdateInterval + time.Second)
	assert.Error(t, err)

	// Test valid intervals
	validIntervals := []time.Duration{
		config.MinMetricsUpdateInterval,
		config.MaxMetricsUpdateInterval,
		(config.MinMetricsUpdateInterval + config.MaxMetricsUpdateInterval) / 2,
	}
	for _, interval := range validIntervals {
		err := ValidateMetricsInterval(interval)
		assert.NoError(t, err, "Interval %v should be valid", interval)
	}
}

// testSampleRateValidation tests sample rate validation
func testSampleRateValidation(t *testing.T) {
	config := GetConfig()

	// Test negative and zero sample rates
	invalidRates := []int{-1, -48000, 0}
	for _, rate := range invalidRates {
		err := ValidateSampleRate(rate)
		assert.Error(t, err, "Sample rate %d should be invalid", rate)
		assert.Contains(t, err.Error(), "must be positive")
	}

	// Test unsupported sample rates
	unsupportedRates := []int{1000, 12345, 96001}
	for _, rate := range unsupportedRates {
		err := ValidateSampleRate(rate)
		assert.Error(t, err, "Sample rate %d should be unsupported", rate)
		assert.Contains(t, err.Error(), "not in supported rates")
	}

	// Test valid sample rates
	for _, rate := range config.ValidSampleRates {
		err := ValidateSampleRate(rate)
		assert.NoError(t, err, "Sample rate %d should be valid", rate)
	}
}

// testChannelCountValidation tests channel count validation
func testChannelCountValidation(t *testing.T) {
	config := GetConfig()

	// Test invalid channel counts
	invalidCounts := []int{-1, -10, 0}
	for _, count := range invalidCounts {
		err := ValidateChannelCount(count)
		assert.Error(t, err, "Channel count %d should be invalid", count)
		assert.Contains(t, err.Error(), "must be positive")
	}

	// Test channel count exceeding maximum
	err := ValidateChannelCount(config.MaxChannels + 1)
	assert.Error(t, err)
	assert.Contains(t, err.Error(), "exceeds maximum")

	// Test valid channel counts
	validCounts := []int{1, 2, config.MaxChannels}
	for _, count := range validCounts {
		err := ValidateChannelCount(count)
		assert.NoError(t, err, "Channel count %d should be valid", count)
	}
}

// testBitrateValidation tests bitrate validation
func testBitrateValidation(t *testing.T) {
	// Test invalid bitrates
	invalidBitrates := []int{-1, -1000, 0}
	for _, bitrate := range invalidBitrates {
		err := ValidateBitrate(bitrate)
		assert.Error(t, err, "Bitrate %d should be invalid", bitrate)
		assert.Contains(t, err.Error(), "must be positive")
	}

	// Test bitrate below minimum (in kbps)
	err := ValidateBitrate(5) // 5 kbps = 5000 bps < 6000 bps minimum
	assert.Error(t, err)
	assert.Contains(t, err.Error(), "below minimum")

	// Test bitrate above maximum (in kbps)
	err = ValidateBitrate(511) // 511 kbps = 511000 bps > 510000 bps maximum
	assert.Error(t, err)
	assert.Contains(t, err.Error(), "exceeds maximum")

	// Test valid bitrates (in kbps)
	validBitrates := []int{
		6,   // 6 kbps = 6000 bps (minimum)
		64,  // Medium quality preset
		128, // High quality preset
		192, // Ultra quality preset
		510, // 510 kbps = 510000 bps (maximum)
	}
	for _, bitrate := range validBitrates {
		err := ValidateBitrate(bitrate)
		assert.NoError(t, err, "Bitrate %d kbps should be valid", bitrate)
	}
}

// testFrameDurationValidation tests frame duration validation
func testFrameDurationValidation(t *testing.T) {
	config := GetConfig()

	// Test invalid durations
	invalidDurations := []time.Duration{-1 * time.Millisecond, -1 * time.Second, 0}
	for _, duration := range invalidDurations {
		err := ValidateFrameDuration(duration)
		assert.Error(t, err, "Duration %v should be invalid", duration)
		assert.Contains(t, err.Error(), "must be positive")
	}

	// Test duration below minimum
	err := ValidateFrameDuration(config.MinFrameDuration - time.Microsecond)
	assert.Error(t, err)
	assert.Contains(t, err.Error(), "below minimum")

	// Test duration above maximum
	err = ValidateFrameDuration(config.MaxFrameDuration + time.Second)
	assert.Error(t, err)
	assert.Contains(t, err.Error(), "exceeds maximum")

	// Test valid durations
	validDurations := []time.Duration{
		config.MinFrameDuration,
		config.MaxFrameDuration,
		20 * time.Millisecond, // Common frame duration
	}
	for _, duration := range validDurations {
		err := ValidateFrameDuration(duration)
		assert.NoError(t, err, "Duration %v should be valid", duration)
	}
}

// testIPCConfigValidation tests IPC configuration validation
func testIPCConfigValidation(t *testing.T) {
	config := GetConfig()

	// Test invalid configurations for input IPC
	invalidConfigs := []struct {
		sampleRate, channels, frameSize int
		description                     string
	}{
		{0, 2, 960, "zero sample rate"},
		{48000, 0, 960, "zero channels"},
		{48000, 2, 0, "zero frame size"},
		{config.MinSampleRate - 1, 2, 960, "sample rate below minimum"},
		{config.MaxSampleRate + 1, 2, 960, "sample rate above maximum"},
		{48000, config.MaxChannels + 1, 960, "too many channels"},
		{48000, -1, 960, "negative channels"},
		{48000, 2, -1, "negative frame size"},
	}

	for _, tc := range invalidConfigs {
		// Test input IPC validation
		err := ValidateInputIPCConfig(tc.sampleRate, tc.channels, tc.frameSize)
		assert.Error(t, err, "Input IPC config should be invalid: %s", tc.description)

		// Test output IPC validation
		err = ValidateOutputIPCConfig(tc.sampleRate, tc.channels, tc.frameSize)
		assert.Error(t, err, "Output IPC config should be invalid: %s", tc.description)
	}

	// Test valid configuration
	err := ValidateInputIPCConfig(48000, 2, 960)
	assert.NoError(t, err)
	err = ValidateOutputIPCConfig(48000, 2, 960)
	assert.NoError(t, err)
}

// testAdaptiveBufferConfigValidation tests adaptive buffer configuration validation
func testAdaptiveBufferConfigValidation(t *testing.T) {
	config := GetConfig()

	// Test invalid configurations
	invalidConfigs := []struct {
		minSize, maxSize, defaultSize int
		description                   string
	}{
		{0, 1024, 512, "zero min size"},
		{-1, 1024, 512, "negative min size"},
		{512, 0, 256, "zero max size"},
		{512, -1, 256, "negative max size"},
		{512, 1024, 0, "zero default size"},
		{512, 1024, -1, "negative default size"},
		{1024, 512, 768, "min >= max"},
		{512, 1024, 256, "default < min"},
		{512, 1024, 2048, "default > max"},
		{512, config.SocketMaxBuffer + 1, 1024, "max exceeds global limit"},
	}

	for _, tc := range invalidConfigs {
		err := ValidateAdaptiveBufferConfig(tc.minSize, tc.maxSize, tc.defaultSize)
		assert.Error(t, err, "Config should be invalid: %s", tc.description)
	}

	// Test valid configuration
	err := ValidateAdaptiveBufferConfig(512, 4096, 1024)
	assert.NoError(t, err)
}

// testAudioConfigCompleteValidation tests complete audio configuration validation
func testAudioConfigCompleteValidation(t *testing.T) {
	// Test valid configuration using actual preset values
	validConfig := AudioConfig{
		Quality:    AudioQualityMedium,
		Bitrate:    64, // kbps - matches medium quality preset
		SampleRate: 48000,
		Channels:   2,
		FrameSize:  20 * time.Millisecond,
	}
	err := ValidateAudioConfigComplete(validConfig)
	assert.NoError(t, err)

	// Test invalid quality
	invalidQualityConfig := validConfig
	invalidQualityConfig.Quality = AudioQuality(99)
	err = ValidateAudioConfigComplete(invalidQualityConfig)
	assert.Error(t, err)
	assert.Contains(t, err.Error(), "quality validation failed")

	// Test invalid bitrate
	invalidBitrateConfig := validConfig
	invalidBitrateConfig.Bitrate = -1
	err = ValidateAudioConfigComplete(invalidBitrateConfig)
	assert.Error(t, err)
	assert.Contains(t, err.Error(), "bitrate validation failed")

	// Test invalid sample rate
	invalidSampleRateConfig := validConfig
	invalidSampleRateConfig.SampleRate = 12345
	err = ValidateAudioConfigComplete(invalidSampleRateConfig)
	assert.Error(t, err)
	assert.Contains(t, err.Error(), "sample rate validation failed")

	// Test invalid channels
	invalidChannelsConfig := validConfig
	invalidChannelsConfig.Channels = 0
	err = ValidateAudioConfigComplete(invalidChannelsConfig)
	assert.Error(t, err)
	assert.Contains(t, err.Error(), "channel count validation failed")

	// Test invalid frame duration
	invalidFrameDurationConfig := validConfig
	invalidFrameDurationConfig.FrameSize = -1 * time.Millisecond
	err = ValidateAudioConfigComplete(invalidFrameDurationConfig)
	assert.Error(t, err)
	assert.Contains(t, err.Error(), "frame duration validation failed")
}

// testZeroCopyFrameValidation tests zero-copy frame validation
func testZeroCopyFrameValidation(t *testing.T) {
	// Test nil frame
	err := ValidateZeroCopyFrame(nil)
	assert.Error(t, err)

	// Note: We can't easily test ZeroCopyAudioFrame without creating actual instances
	// This would require more complex setup, but the validation logic is tested
}

// testAudioFrameFastValidation tests fast audio frame validation
func testAudioFrameFastValidation(t *testing.T) {
	config := GetConfig()

	// Test empty data
	err := ValidateAudioFrameFast([]byte{})
	assert.Error(t, err)
	assert.Contains(t, err.Error(), "frame data is empty")

	// Test data exceeding maximum size
	largeData := make([]byte, config.MaxAudioFrameSize+1)
	err = ValidateAudioFrameFast(largeData)
	assert.Error(t, err)
	assert.Contains(t, err.Error(), "exceeds maximum")

	// Test valid data
	validData := make([]byte, 1000)
	err = ValidateAudioFrameFast(validData)
	assert.NoError(t, err)
}

// testErrorWrappingValidation tests error wrapping functionality
func testErrorWrappingValidation(t *testing.T) {
	// Test wrapping nil error
	wrapped := WrapWithMetadata(nil, "component", "operation", map[string]interface{}{"key": "value"})
	assert.Nil(t, wrapped)

	// Test wrapping actual error
	originalErr := assert.AnError
	metadata := map[string]interface{}{
		"frame_size": 1024,
		"quality":    "high",
	}
	wrapped = WrapWithMetadata(originalErr, "audio", "decode", metadata)
	require.NotNil(t, wrapped)
	assert.Contains(t, wrapped.Error(), "audio.decode")
	assert.Contains(t, wrapped.Error(), "assert.AnError")
	assert.Contains(t, wrapped.Error(), "metadata")
	assert.Contains(t, wrapped.Error(), "frame_size")
	assert.Contains(t, wrapped.Error(), "quality")
}

// TestValidationIntegration tests validation functions working together
func TestValidationIntegration(t *testing.T) {
	// Test that validation functions work correctly with actual audio configurations
	presets := GetAudioQualityPresets()
	require.NotEmpty(t, presets)

	for quality, config := range presets {
		t.Run(fmt.Sprintf("Quality_%d", quality), func(t *testing.T) {
			// Validate the preset configuration
			err := ValidateAudioConfigComplete(config)
			assert.NoError(t, err, "Preset configuration for quality %d should be valid", quality)

			// Validate individual components
			err = ValidateAudioQuality(config.Quality)
			assert.NoError(t, err, "Quality should be valid")

			err = ValidateBitrate(config.Bitrate)
			assert.NoError(t, err, "Bitrate should be valid")

			err = ValidateSampleRate(config.SampleRate)
			assert.NoError(t, err, "Sample rate should be valid")

			err = ValidateChannelCount(config.Channels)
			assert.NoError(t, err, "Channel count should be valid")

			err = ValidateFrameDuration(config.FrameSize)
			assert.NoError(t, err, "Frame duration should be valid")
		})
	}
}

// TestValidationPerformance ensures validation functions are efficient
func TestValidationPerformance(t *testing.T) {
	if testing.Short() {
		t.Skip("Skipping performance test in short mode")
	}

	// Test that validation functions complete quickly
	start := time.Now()
	iterations := 10000

	for i := 0; i < iterations; i++ {
		_ = ValidateAudioQuality(AudioQualityMedium)
		_ = ValidateBufferSize(1024)
		_ = ValidateChannelCount(2)
		_ = ValidateSampleRate(48000)
		_ = ValidateBitrate(96) // 96 kbps
	}

	elapsed := time.Since(start)
	perIteration := elapsed / time.Duration(iterations)

	// Performance expectations for JetKVM (ARM Cortex-A7 @ 1GHz, 256MB RAM)
	// Audio processing must not interfere with primary KVM functionality
	assert.Less(t, perIteration, 200*time.Microsecond, "Validation should not impact KVM performance")
	t.Logf("Validation performance: %v per iteration", perIteration)
}
