package utils

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"math"
	"os"
	"path/filepath"
	"testing"
	"time"
)

// createTestWAVFile creates a minimal valid WAV file for testing
func createTestWAVFile(t *testing.T, dir string, filename string, options struct {
	duration      float64
	sampleRate    int
	channels      int
	bitsPerSample int
	comment       string
	artist        string
}) string {
	t.Helper()

	path := filepath.Join(dir, filename)
	file, err := os.Create(path)
	if err != nil {
		t.Fatalf("Failed to create test file: %v", err)
	}
	defer file.Close()

	// Calculate data chunk size based on duration
	bytesPerSample := options.bitsPerSample / 8
	samplesPerSecond := options.sampleRate * options.channels
	dataSize := int(options.duration * float64(samplesPerSecond*bytesPerSample))

	// Calculate file size (excluding RIFF header)
	fileSize := 4 + 8 + 16 + 8 + dataSize // WAVE + fmt chunk + data chunk header

	// Add LIST INFO chunk size if metadata provided
	var infoChunk []byte
	if options.comment != "" || options.artist != "" {
		infoChunk = buildINFOChunk(options.comment, options.artist)
		fileSize += 8 + len(infoChunk) // LIST chunk header + content
	}

	buf := &bytes.Buffer{}

	// Write RIFF header
	buf.WriteString("RIFF")
	binary.Write(buf, binary.LittleEndian, uint32(fileSize))
	buf.WriteString("WAVE")

	// Write fmt chunk
	buf.WriteString("fmt ")
	binary.Write(buf, binary.LittleEndian, uint32(16)) // chunk size
	binary.Write(buf, binary.LittleEndian, uint16(1))  // audio format (PCM)
	binary.Write(buf, binary.LittleEndian, uint16(options.channels))
	binary.Write(buf, binary.LittleEndian, uint32(options.sampleRate))
	byteRate := options.sampleRate * options.channels * bytesPerSample
	binary.Write(buf, binary.LittleEndian, uint32(byteRate))
	blockAlign := options.channels * bytesPerSample
	binary.Write(buf, binary.LittleEndian, uint16(blockAlign))
	binary.Write(buf, binary.LittleEndian, uint16(options.bitsPerSample))

	// Write LIST INFO chunk if metadata provided
	if len(infoChunk) > 0 {
		buf.WriteString("LIST")
		binary.Write(buf, binary.LittleEndian, uint32(len(infoChunk)))
		buf.Write(infoChunk)
	}

	// Write data chunk
	buf.WriteString("data")
	binary.Write(buf, binary.LittleEndian, uint32(dataSize))
	// Write silence for data
	buf.Write(make([]byte, dataSize))

	// Write to file
	if _, err := file.Write(buf.Bytes()); err != nil {
		t.Fatalf("Failed to write test file: %v", err)
	}

	return path
}

// buildINFOChunk builds a LIST INFO chunk with optional comment and artist
func buildINFOChunk(comment, artist string) []byte {
	buf := &bytes.Buffer{}
	buf.WriteString("INFO")

	if comment != "" {
		buf.WriteString("ICMT")
		// Size includes null terminator
		size := len(comment) + 1
		binary.Write(buf, binary.LittleEndian, uint32(size))
		buf.WriteString(comment)
		buf.WriteByte(0) // null terminator
		// Add padding byte if needed for word alignment
		if size%2 != 0 {
			buf.WriteByte(0)
		}
	}

	if artist != "" {
		buf.WriteString("IART")
		size := len(artist) + 1
		binary.Write(buf, binary.LittleEndian, uint32(size))
		buf.WriteString(artist)
		buf.WriteByte(0) // null terminator
		if size%2 != 0 {
			buf.WriteByte(0)
		}
	}

	return buf.Bytes()
}

func TestConvertToFloat64_16Bit(t *testing.T) {
	// 16-bit signed, little-endian: 0x0001 = 1 → 1/32768
	data := []byte{0x01, 0x00, 0xFF, 0x7F}
	samples := convertToFloat64(data, 16, 1)
	if len(samples) != 2 {
		t.Fatalf("expected 2 samples, got %d", len(samples))
	}
	if math.Abs(samples[0]-1.0/32768.0) > 1e-10 {
		t.Errorf("sample[0] = %v, want %v", samples[0], 1.0/32768.0)
	}
	// 0x7FFF = 32767 → 32767/32768 ≈ 0.99997
	if math.Abs(samples[1]-32767.0/32768.0) > 1e-10 {
		t.Errorf("sample[1] = %v, want %v", samples[1], 32767.0/32768.0)
	}
}

func TestConvertToFloat64_16BitNegative(t *testing.T) {
	// 0x8000 = -32768 → -32768/32768 = -1.0
	data := []byte{0x00, 0x80}
	samples := convertToFloat64(data, 16, 1)
	if len(samples) != 1 {
		t.Fatalf("expected 1 sample, got %d", len(samples))
	}
	if math.Abs(samples[0]-(-1.0)) > 1e-10 {
		t.Errorf("sample = %v, want -1.0", samples[0])
	}
}

func TestConvertToFloat64_16BitStereo(t *testing.T) {
	// Stereo: should extract only left channel
	// Left: 0x0001 = 1, Right: 0x0002 = 2
	data := []byte{0x01, 0x00, 0x02, 0x00}
	samples := convertToFloat64(data, 16, 2)
	if len(samples) != 1 {
		t.Fatalf("expected 1 sample (left only), got %d", len(samples))
	}
	if math.Abs(samples[0]-1.0/32768.0) > 1e-10 {
		t.Errorf("sample = %v, want %v", samples[0], 1.0/32768.0)
	}
}

func TestConvertToFloat64_24Bit(t *testing.T) {
	// 24-bit signed, little-endian: 0x000001 = 1 → 1/8388608
	data := []byte{0x01, 0x00, 0x00}
	samples := convertToFloat64(data, 24, 1)
	if len(samples) != 1 {
		t.Fatalf("expected 1 sample, got %d", len(samples))
	}
	if math.Abs(samples[0]-1.0/8388608.0) > 1e-12 {
		t.Errorf("sample = %v, want %v", samples[0], 1.0/8388608.0)
	}
}

func TestConvertToFloat64_24BitNegative(t *testing.T) {
	// 24-bit: 0xFFFFFF = -1 (sign extended) → -1/8388608
	data := []byte{0xFF, 0xFF, 0xFF}
	samples := convertToFloat64(data, 24, 1)
	if len(samples) != 1 {
		t.Fatalf("expected 1 sample, got %d", len(samples))
	}
	if math.Abs(samples[0]-(-1.0/8388608.0)) > 1e-12 {
		t.Errorf("sample = %v, want %v", samples[0], -1.0/8388608.0)
	}
}

func TestConvertToFloat64_24BitMaxPositive(t *testing.T) {
	// 24-bit max positive: 0x7FFFFF = 8388607 → ~0.9999999
	data := []byte{0xFF, 0xFF, 0x7F}
	samples := convertToFloat64(data, 24, 1)
	if len(samples) != 1 {
		t.Fatalf("expected 1 sample, got %d", len(samples))
	}
	if math.Abs(samples[0]-8388607.0/8388608.0) > 1e-12 {
		t.Errorf("sample = %v, want %v", samples[0], 8388607.0/8388608.0)
	}
}

func TestConvertToFloat64_24BitMinNegative(t *testing.T) {
	// 24-bit min negative: 0x800000 = -8388608 → -1.0
	data := []byte{0x00, 0x00, 0x80}
	samples := convertToFloat64(data, 24, 1)
	if len(samples) != 1 {
		t.Fatalf("expected 1 sample, got %d", len(samples))
	}
	if math.Abs(samples[0]-(-1.0)) > 1e-12 {
		t.Errorf("sample = %v, want -1.0", samples[0])
	}
}

func TestConvertToFloat64_24BitStereo(t *testing.T) {
	// 24-bit stereo: left=0x000001=1, right=0x000002=2
	data := []byte{0x01, 0x00, 0x00, 0x02, 0x00, 0x00}
	samples := convertToFloat64(data, 24, 2)
	if len(samples) != 1 {
		t.Fatalf("expected 1 sample (left only), got %d", len(samples))
	}
	if math.Abs(samples[0]-1.0/8388608.0) > 1e-12 {
		t.Errorf("sample = %v, want %v", samples[0], 1.0/8388608.0)
	}
}

func TestConvertToFloat64_32Bit(t *testing.T) {
	// 32-bit signed, little-endian: 0x00000001 = 1 → 1/2147483648
	data := []byte{0x01, 0x00, 0x00, 0x00}
	samples := convertToFloat64(data, 32, 1)
	if len(samples) != 1 {
		t.Fatalf("expected 1 sample, got %d", len(samples))
	}
	if math.Abs(samples[0]-1.0/2147483648.0) > 1e-15 {
		t.Errorf("sample = %v, want %v", samples[0], 1.0/2147483648.0)
	}
}

func TestConvertToFloat64_32BitNegative(t *testing.T) {
	// 32-bit: 0x80000000 = -2147483648 → -1.0
	data := []byte{0x00, 0x00, 0x00, 0x80}
	samples := convertToFloat64(data, 32, 1)
	if len(samples) != 1 {
		t.Fatalf("expected 1 sample, got %d", len(samples))
	}
	if math.Abs(samples[0]-(-1.0)) > 1e-15 {
		t.Errorf("sample = %v, want -1.0", samples[0])
	}
}

func TestConvertToFloat64_32BitMaxPositive(t *testing.T) {
	// 32-bit max positive: 0x7FFFFFFF = 2147483647 → ~0.9999999995
	data := []byte{0xFF, 0xFF, 0xFF, 0x7F}
	samples := convertToFloat64(data, 32, 1)
	if len(samples) != 1 {
		t.Fatalf("expected 1 sample, got %d", len(samples))
	}
	if math.Abs(samples[0]-2147483647.0/2147483648.0) > 1e-15 {
		t.Errorf("sample = %v, want %v", samples[0], 2147483647.0/2147483648.0)
	}
}

func TestConvertToFloat64_32BitStereo(t *testing.T) {
	// 32-bit stereo: left=1, right=2
	data := []byte{0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00}
	samples := convertToFloat64(data, 32, 2)
	if len(samples) != 1 {
		t.Fatalf("expected 1 sample (left only), got %d", len(samples))
	}
	if math.Abs(samples[0]-1.0/2147483648.0) > 1e-15 {
		t.Errorf("sample = %v, want %v", samples[0], 1.0/2147483648.0)
	}
}

func TestConvertToFloat64_UnsupportedBitDepth(t *testing.T) {
	// Unsupported bit depth (8) falls back to 16-bit parsing.
	// blockAlign = (8/8)*1 = 1, so numSamples = len(data)/1 = 4.
	// But 16-bit reads 2 bytes per sample, which panics with only 1 byte per block.
	// This tests the fallback path exists; for valid 8-bit data, blockAlign
	// must be 2 (so 2 bytes per sample in the data layout).
	data := []byte{0x01, 0x00, 0x02, 0x00}  // 4 bytes, treated as 2x 16-bit samples
	samples := convertToFloat64(data, 8, 2) // 2 channels → blockAlign = 1*2 = 2
	if len(samples) != 2 {
		t.Fatalf("expected 2 samples (fallback 16-bit), got %d", len(samples))
	}
}

func TestConvertToFloat64_EmptyData(t *testing.T) {
	samples := convertToFloat64([]byte{}, 16, 1)
	if len(samples) != 0 {
		t.Errorf("expected 0 samples, got %d", len(samples))
	}
}

func TestParseWAVHeader_BasicMetadata(t *testing.T) {
	tmpDir := t.TempDir()

	path := createTestWAVFile(t, tmpDir, "test_basic.wav", struct {
		duration      float64
		sampleRate    int
		channels      int
		bitsPerSample int
		comment       string
		artist        string
	}{
		duration:      60.0,
		sampleRate:    44100,
		channels:      2,
		bitsPerSample: 16,
		comment:       "",
		artist:        "",
	})

	metadata, err := ParseWAVHeader(path)
	if err != nil {
		t.Fatalf("Failed to parse WAV header: %v", err)
	}

	if metadata.SampleRate != 44100 {
		t.Errorf("SampleRate incorrect: got %d, want 44100", metadata.SampleRate)
	}
	if metadata.Channels != 2 {
		t.Errorf("Channels incorrect: got %d, want 2", metadata.Channels)
	}
	if metadata.BitsPerSample != 16 {
		t.Errorf("BitsPerSample incorrect: got %d, want 16", metadata.BitsPerSample)
	}
	if metadata.Duration < 59.9 || metadata.Duration > 60.1 {
		t.Errorf("Duration incorrect: got %f, want ~60.0", metadata.Duration)
	}
}

func TestParseWAVHeader_CommentMetadata(t *testing.T) {
	tmpDir := t.TempDir()

	expectedComment := "Recorded at 21:00:00 24/02/2025 (UTC+13) by AudioMoth 248AB50153AB0549"
	path := createTestWAVFile(t, tmpDir, "test_comment.wav", struct {
		duration      float64
		sampleRate    int
		channels      int
		bitsPerSample int
		comment       string
		artist        string
	}{
		duration:      10.0,
		sampleRate:    48000,
		channels:      1,
		bitsPerSample: 16,
		comment:       expectedComment,
		artist:        "",
	})

	metadata, err := ParseWAVHeader(path)
	if err != nil {
		t.Fatalf("Failed to parse WAV header: %v", err)
	}

	if metadata.Comment != expectedComment {
		t.Errorf("Comment incorrect: got %q, want %q", metadata.Comment, expectedComment)
	}
}

func TestParseWAVHeader_ArtistMetadata(t *testing.T) {
	tmpDir := t.TempDir()

	expectedArtist := "AudioMoth"
	path := createTestWAVFile(t, tmpDir, "test_artist.wav", struct {
		duration      float64
		sampleRate    int
		channels      int
		bitsPerSample int
		comment       string
		artist        string
	}{
		duration:      5.0,
		sampleRate:    48000,
		channels:      1,
		bitsPerSample: 16,
		comment:       "",
		artist:        expectedArtist,
	})

	metadata, err := ParseWAVHeader(path)
	if err != nil {
		t.Fatalf("Failed to parse WAV header: %v", err)
	}

	if metadata.Artist != expectedArtist {
		t.Errorf("Artist incorrect: got %q, want %q", metadata.Artist, expectedArtist)
	}
}

func TestParseWAVHeader_CommentAndArtist(t *testing.T) {
	tmpDir := t.TempDir()

	expectedComment := "Test recording comment"
	expectedArtist := "Test Artist"
	path := createTestWAVFile(t, tmpDir, "test_both.wav", struct {
		duration      float64
		sampleRate    int
		channels      int
		bitsPerSample int
		comment       string
		artist        string
	}{
		duration:      15.0,
		sampleRate:    44100,
		channels:      2,
		bitsPerSample: 16,
		comment:       expectedComment,
		artist:        expectedArtist,
	})

	metadata, err := ParseWAVHeader(path)
	if err != nil {
		t.Fatalf("Failed to parse WAV header: %v", err)
	}

	if metadata.Comment != expectedComment {
		t.Errorf("Comment incorrect: got %q, want %q", metadata.Comment, expectedComment)
	}
	if metadata.Artist != expectedArtist {
		t.Errorf("Artist incorrect: got %q, want %q", metadata.Artist, expectedArtist)
	}
}

func TestParseWAVHeader_SampleRates(t *testing.T) {
	tmpDir := t.TempDir()

	testCases := []int{8000, 16000, 22050, 44100, 48000, 96000}
	for _, sr := range testCases {
		t.Run(fmt.Sprintf("%dHz", sr), func(t *testing.T) {
			path := createTestWAVFile(t, tmpDir, fmt.Sprintf("test_sr_%d.wav", sr), struct {
				duration      float64
				sampleRate    int
				channels      int
				bitsPerSample int
				comment       string
				artist        string
			}{
				duration:      1.0,
				sampleRate:    sr,
				channels:      1,
				bitsPerSample: 16,
				comment:       "",
				artist:        "",
			})

			metadata, err := ParseWAVHeader(path)
			if err != nil {
				t.Fatalf("Failed to parse WAV header: %v", err)
			}

			if metadata.SampleRate != sr {
				t.Errorf("SampleRate incorrect: got %d, want %d", metadata.SampleRate, sr)
			}
		})
	}
}

func TestParseWAVHeader_ChannelCounts(t *testing.T) {
	tmpDir := t.TempDir()

	testCases := []int{1, 2}
	for _, ch := range testCases {
		t.Run(fmt.Sprintf("%dch", ch), func(t *testing.T) {
			path := createTestWAVFile(t, tmpDir, fmt.Sprintf("test_ch_%d.wav", ch), struct {
				duration      float64
				sampleRate    int
				channels      int
				bitsPerSample int
				comment       string
				artist        string
			}{
				duration:      1.0,
				sampleRate:    44100,
				channels:      ch,
				bitsPerSample: 16,
				comment:       "",
				artist:        "",
			})

			metadata, err := ParseWAVHeader(path)
			if err != nil {
				t.Fatalf("Failed to parse WAV header: %v", err)
			}

			if metadata.Channels != ch {
				t.Errorf("Channels incorrect: got %d, want %d", metadata.Channels, ch)
			}
		})
	}
}

func TestParseWAVHeader_BitDepths(t *testing.T) {
	tmpDir := t.TempDir()

	testCases := []int{8, 16, 24, 32}
	for _, bits := range testCases {
		t.Run(fmt.Sprintf("%dbit", bits), func(t *testing.T) {
			path := createTestWAVFile(t, tmpDir, fmt.Sprintf("test_bits_%d.wav", bits), struct {
				duration      float64
				sampleRate    int
				channels      int
				bitsPerSample int
				comment       string
				artist        string
			}{
				duration:      1.0,
				sampleRate:    44100,
				channels:      1,
				bitsPerSample: bits,
				comment:       "",
				artist:        "",
			})

			metadata, err := ParseWAVHeader(path)
			if err != nil {
				t.Fatalf("Failed to parse WAV header: %v", err)
			}

			if metadata.BitsPerSample != bits {
				t.Errorf("BitsPerSample incorrect: got %d, want %d", metadata.BitsPerSample, bits)
			}
		})
	}
}

func TestParseWAVHeader_ShortDuration(t *testing.T) {
	tmpDir := t.TempDir()

	path := createTestWAVFile(t, tmpDir, "test_short.wav", struct {
		duration      float64
		sampleRate    int
		channels      int
		bitsPerSample int
		comment       string
		artist        string
	}{
		duration:      0.1, // 100ms
		sampleRate:    44100,
		channels:      1,
		bitsPerSample: 16,
		comment:       "",
		artist:        "",
	})

	metadata, err := ParseWAVHeader(path)
	if err != nil {
		t.Fatalf("Failed to parse WAV header: %v", err)
	}

	if metadata.Duration < 0.09 || metadata.Duration > 0.11 {
		t.Errorf("Duration incorrect: got %f, want ~0.1", metadata.Duration)
	}
}

func TestParseWAVHeader_LongDuration(t *testing.T) {
	tmpDir := t.TempDir()

	path := createTestWAVFile(t, tmpDir, "test_long.wav", struct {
		duration      float64
		sampleRate    int
		channels      int
		bitsPerSample int
		comment       string
		artist        string
	}{
		duration:      600.0, // 10 minutes
		sampleRate:    44100,
		channels:      1,
		bitsPerSample: 16,
		comment:       "",
		artist:        "",
	})

	metadata, err := ParseWAVHeader(path)
	if err != nil {
		t.Fatalf("Failed to parse WAV header: %v", err)
	}

	if metadata.Duration < 599.0 || metadata.Duration > 601.0 {
		t.Errorf("Duration incorrect: got %f, want ~600.0", metadata.Duration)
	}
}

func TestParseWAVHeader_NonExistentFile(t *testing.T) {
	_, err := ParseWAVHeader("/nonexistent/file.wav")
	if err == nil {
		t.Error("Expected error for non-existent file")
	}
}

func TestParseWAVHeader_NonWAVFile(t *testing.T) {
	tmpDir := t.TempDir()

	path := filepath.Join(tmpDir, "not_a_wav.txt")
	if err := os.WriteFile(path, []byte("This is not a WAV file"), 0644); err != nil {
		t.Fatalf("Failed to create test file: %v", err)
	}

	_, err := ParseWAVHeader(path)
	if err == nil {
		t.Error("Expected error for non-WAV file")
	}
}

func TestParseWAVHeader_TruncatedFile(t *testing.T) {
	tmpDir := t.TempDir()

	path := filepath.Join(tmpDir, "truncated.wav")
	if err := os.WriteFile(path, []byte("RIFF"), 0644); err != nil {
		t.Fatalf("Failed to create test file: %v", err)
	}

	_, err := ParseWAVHeader(path)
	if err == nil {
		t.Error("Expected error for truncated file")
	}
}

func TestParseWAVHeader_EmptyMetadataStrings(t *testing.T) {
	tmpDir := t.TempDir()

	path := createTestWAVFile(t, tmpDir, "test_empty.wav", struct {
		duration      float64
		sampleRate    int
		channels      int
		bitsPerSample int
		comment       string
		artist        string
	}{
		duration:      10.0,
		sampleRate:    44100,
		channels:      1,
		bitsPerSample: 16,
		comment:       "",
		artist:        "",
	})

	metadata, err := ParseWAVHeader(path)
	if err != nil {
		t.Fatalf("Failed to parse WAV header: %v", err)
	}

	if metadata.Comment != "" {
		t.Errorf("Comment should be empty, got %q", metadata.Comment)
	}
	if metadata.Artist != "" {
		t.Errorf("Artist should be empty, got %q", metadata.Artist)
	}
}

func TestParseWAVHeader_LongCommentString(t *testing.T) {
	tmpDir := t.TempDir()

	longComment := "Recorded at 21:00:00 24/02/2025 (UTC+13) by AudioMoth 248AB50153AB0549 at medium gain while battery was 4.3V and temperature was 15.8C. This is a very long comment with additional information about the recording session."

	path := createTestWAVFile(t, tmpDir, "test_long_comment.wav", struct {
		duration      float64
		sampleRate    int
		channels      int
		bitsPerSample int
		comment       string
		artist        string
	}{
		duration:      10.0,
		sampleRate:    44100,
		channels:      1,
		bitsPerSample: 16,
		comment:       longComment,
		artist:        "",
	})

	metadata, err := ParseWAVHeader(path)
	if err != nil {
		t.Fatalf("Failed to parse WAV header: %v", err)
	}

	if metadata.Comment != longComment {
		t.Errorf("Comment incorrect: got %q, want %q", metadata.Comment, longComment)
	}
}

func TestParseWAVHeader_FileModTime(t *testing.T) {
	tmpDir := t.TempDir()

	path := createTestWAVFile(t, tmpDir, "test_modtime.wav", struct {
		duration      float64
		sampleRate    int
		channels      int
		bitsPerSample int
		comment       string
		artist        string
	}{
		duration:      5.0,
		sampleRate:    44100,
		channels:      1,
		bitsPerSample: 16,
		comment:       "",
		artist:        "",
	})

	info, err := os.Stat(path)
	if err != nil {
		t.Fatalf("Failed to stat file: %v", err)
	}
	expectedModTime := info.ModTime()

	metadata, err := ParseWAVHeader(path)
	if err != nil {
		t.Fatalf("Failed to parse WAV header: %v", err)
	}

	// Allow 1 second tolerance for filesystem granularity
	diff := metadata.FileModTime.Sub(expectedModTime)
	if diff < -1*time.Second || diff > 1*time.Second {
		t.Errorf("FileModTime incorrect: got %v, want %v (diff: %v)",
			metadata.FileModTime, expectedModTime, diff)
	}
	if metadata.FileModTime.IsZero() {
		t.Error("FileModTime should not be zero")
	}
}

func TestExtractNullTerminatedString(t *testing.T) {
	testCases := []struct {
		name     string
		input    []byte
		expected string
	}{
		{
			name:     "string with null terminator",
			input:    []byte{'h', 'e', 'l', 'l', 'o', 0, 'w', 'o', 'r', 'l', 'd'},
			expected: "hello",
		},
		{
			name:     "string without null terminator",
			input:    []byte{'h', 'e', 'l', 'l', 'o'},
			expected: "hello",
		},
		{
			name:     "empty string",
			input:    []byte{},
			expected: "",
		},
		{
			name:     "only null terminator",
			input:    []byte{0},
			expected: "",
		},
	}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			result := extractNullTerminatedString(tc.input)
			if result != tc.expected {
				t.Errorf("Result incorrect: got %q, want %q", result, tc.expected)
			}
		})
	}
}

// assertWAVHeader creates a WAV file and verifies ParseWAVHeaderMinimal returns expected values.
func assertWAVHeader(t *testing.T, tmpDir, filename string, wantSR int, wantDur float64, opts struct {
	duration      float64
	sampleRate    int
	channels      int
	bitsPerSample int
	comment       string
	artist        string
}) {
	t.Helper()
	path := createTestWAVFile(t, tmpDir, filename, opts)
	sr, dur, err := ParseWAVHeaderMinimal(path)
	if err != nil {
		t.Fatalf("Failed to parse WAV header: %v", err)
	}
	if sr != wantSR {
		t.Errorf("SampleRate: got %d, want %d", sr, wantSR)
	}
	if dur < wantDur-0.1 || dur > wantDur+0.1 {
		t.Errorf("Duration: got %f, want ~%f", dur, wantDur)
	}
}

func TestParseWAVHeaderMinimal(t *testing.T) {
	tmpDir := t.TempDir()

	t.Run("basic", func(t *testing.T) {
		assertWAVHeader(t, tmpDir, "test_minimal.wav", 44100, 10.0, struct {
			duration      float64
			sampleRate    int
			channels      int
			bitsPerSample int
			comment       string
			artist        string
		}{10.0, 44100, 1, 16, "", ""})
	})

	t.Run("sample_rates", func(t *testing.T) {
		for _, sr := range []int{8000, 22050, 44100, 48000, 96000} {
			t.Run(fmt.Sprintf("%dHz", sr), func(t *testing.T) {
				assertWAVHeader(t, tmpDir, fmt.Sprintf("test_sr_%d.wav", sr), sr, 5.0, struct {
					duration      float64
					sampleRate    int
					channels      int
					bitsPerSample int
					comment       string
					artist        string
				}{5.0, sr, 1, 16, "", ""})
			})
		}
	})

	t.Run("stereo", func(t *testing.T) {
		assertWAVHeader(t, tmpDir, "test_stereo.wav", 44100, 3.0, struct {
			duration      float64
			sampleRate    int
			channels      int
			bitsPerSample int
			comment       string
			artist        string
		}{3.0, 44100, 2, 16, "", ""})
	})

	t.Run("nonexistent", func(t *testing.T) {
		_, _, err := ParseWAVHeaderMinimal("/nonexistent/file.wav")
		if err == nil {
			t.Error("Expected error for non-existent file")
		}
	})

	t.Run("non_wav", func(t *testing.T) {
		path := filepath.Join(tmpDir, "notawav.wav")
		if err := os.WriteFile(path, []byte("Not a WAV file"), 0644); err != nil {
			t.Fatalf("Failed to create test file: %v", err)
		}
		_, _, err := ParseWAVHeaderMinimal(path)
		if err == nil {
			t.Error("Expected error for non-WAV file")
		}
	})
}