package utils

import (
	"os"
	"path/filepath"
	"testing"
)

func TestComputeXXH64_WAVFile(t *testing.T) {
	wavFile := filepath.Join("..", "audio", "N14-2025-02-25-20241116_054500-685-703.wav")

	hash, err := ComputeXXH64(wavFile)
	if err != nil {
		t.Fatalf("ComputeXXH64() error = %v", err)
	}

	expectedHash := "48dc1684324621de"
	if hash != expectedHash {
		t.Errorf("ComputeXXH64() = %v, want %v", hash, expectedHash)
	}
}

func TestComputeXXH64_Format(t *testing.T) {
	wavFile := filepath.Join("..", "audio", "N14-2025-02-25-20241116_054500-685-703.wav")

	hash, err := ComputeXXH64(wavFile)
	if err != nil {
		t.Fatalf("ComputeXXH64() error = %v", err)
	}

	if len(hash) != 16 {
		t.Errorf("hash length = %d, want 16", len(hash))
	}

	for _, c := range hash {
		if (c < '0' || c > '9') && (c < 'a' || c > 'f') {
			t.Errorf("invalid hex character '%c' in hash %s", c, hash)
		}
	}
}

func TestComputeXXH64_FileNotFound(t *testing.T) {
	_, err := ComputeXXH64("nonexistent-file.wav")
	if err == nil {
		t.Error("expected error for nonexistent file, got nil")
	}
}

func TestComputeXXH64_EmptyFile(t *testing.T) {
	tmpDir := t.TempDir()
	emptyFile := filepath.Join(tmpDir, "empty.wav")

	if err := createEmptyFile(emptyFile); err != nil {
		t.Fatalf("Failed to create empty file: %v", err)
	}

	hash, err := ComputeXXH64(emptyFile)
	if err != nil {
		t.Fatalf("ComputeXXH64() error = %v", err)
	}

	expectedEmpty := "ef46db3751d8e999"
	if hash != expectedEmpty {
		t.Errorf("ComputeXXH64(empty file) = %v, want %v", hash, expectedEmpty)
	}
}

func TestComputeXXH64_Deterministic(t *testing.T) {
	wavFile := filepath.Join("..", "audio", "N14-2025-02-25-20241116_054500-685-703.wav")

	hash1, err := ComputeXXH64(wavFile)
	if err != nil {
		t.Fatalf("first call error = %v", err)
	}
	hash2, err := ComputeXXH64(wavFile)
	if err != nil {
		t.Fatalf("second call error = %v", err)
	}
	hash3, err := ComputeXXH64(wavFile)
	if err != nil {
		t.Fatalf("third call error = %v", err)
	}

	if hash1 != hash2 || hash2 != hash3 {
		t.Errorf("hashes not deterministic: %s, %s, %s", hash1, hash2, hash3)
	}
}

func TestComputeXXH64_LeadingZeros(t *testing.T) {
	tmpDir := t.TempDir()
	smallFile := filepath.Join(tmpDir, "small.dat")

	if err := createSmallFile(smallFile); err != nil {
		t.Fatalf("Failed to create small file: %v", err)
	}

	hash, err := ComputeXXH64(smallFile)
	if err != nil {
		t.Fatalf("ComputeXXH64() error = %v", err)
	}

	if len(hash) != 16 {
		t.Errorf("hash length = %d, want 16 (leading zeros should be preserved)", len(hash))
	}
}

func BenchmarkComputeXXH64_Small(b *testing.B) {
	f := filepath.Join("..", "audio", "N14-2025-02-25-20241116_054500-685-703.wav") // 547K
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		ComputeXXH64(f)
	}
}

func BenchmarkComputeXXH64_Medium(b *testing.B) {
	f := filepath.Join("..", "audio", "20250518_210000.WAV") // 14M
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		ComputeXXH64(f)
	}
}

func BenchmarkComputeXXH64_Large(b *testing.B) {
	f := filepath.Join("..", "audio", "E166_BIRD_111211_042726.wav") // 55M
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		ComputeXXH64(f)
	}
}

func createEmptyFile(path string) error {
	file, err := os.Create(path)
	if err != nil {
		return err
	}
	return file.Close()
}

func createSmallFile(path string) error {
	file, err := os.Create(path)
	if err != nil {
		return err
	}
	defer file.Close()
	_, err = file.Write([]byte{0x42})
	return err
}