package spectrogram

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

func TestExtractSegmentSamples(t *testing.T) {
	samples := []float64{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
	sampleRate := 2 // 2 samples per sec

	// sec 1.0 to 3.0 => indices 2 to 6 => [2, 3, 4, 5]
	seg := ExtractSegmentSamples(samples, sampleRate, 1.0, 3.0)
	if len(seg) != 4 || seg[0] != 2 || seg[len(seg)-1] != 5 {
		t.Errorf("unexpected segment extraction: %v", seg)
	}

	// out of bounds
	empty := ExtractSegmentSamples(samples, sampleRate, 5.0, 6.0)
	if len(empty) != 0 {
		t.Error("expected empty segment")
	}
}

func TestGenerateSpectrogram_Basic(t *testing.T) {
	samples := make([]float64, 1000) // Silent buffer
	cfg := DefaultSpectrogramConfig(16000)
	res := GenerateSpectrogram(samples, cfg)
	if len(res) == 0 {
		t.Error("expected spectrogram generation to succeed")
	}

	shortSamples := []float64{0.0, 0.1}
	resShort := GenerateSpectrogram(shortSamples, cfg)
	if resShort != nil {
		t.Error("expected nil for samples smaller than window size")
	}
}

func TestGetCachedHannWindow(t *testing.T) {
	w1 := getCachedHannWindow(256)
	w2 := getCachedHannWindow(256)

	if len(w1) != 256 {
		t.Errorf("expected length 256, got %d", len(w1))
	}

	// Ensure memory address is the same (cached)
	if &w1[0] != &w2[0] {
		t.Error("expected cached slice to have the same memory address")
	}
}

func TestClipBaseName(t *testing.T) {
	tests := []struct {
		prefix    string
		basename  string
		startTime float64
		endTime   float64
		want      string
	}{
		{"clip", "file", 1.0, 3.0, "clip_file_1_3"},
		{"test", "recording", 0.0, 5.5, "test_recording_0_6"}, // ceil(5.5) = 6
		{"a", "b", 2.7, 4.2, "a_b_2_5"},                       // floor(2.7)=2, ceil(4.2)=5
	}

	for _, tt := range tests {
		got := ClipBaseName(tt.prefix, tt.basename, tt.startTime, tt.endTime)
		if got != tt.want {
			t.Errorf("ClipBaseName(%q, %q, %.1f, %.1f) = %q, want %q",
				tt.prefix, tt.basename, tt.startTime, tt.endTime, got, tt.want)
		}
	}
}

func TestWAVBasename(t *testing.T) {
	tests := []struct {
		path string
		want string
	}{
		{"/path/to/file.wav.data", "file"},
		{"/audio/2024-01-15_recording.wav.data", "2024-01-15_recording"},
		{"simple.wav.data", "simple"},
	}

	for _, tt := range tests {
		got := WAVBasename(tt.path)
		if got != tt.want {
			t.Errorf("WAVBasename(%q) = %q, want %q", tt.path, got, tt.want)
		}
	}
}

func TestClipPaths(t *testing.T) {
	tmp := t.TempDir()

	// Normal case
	pngPath, wavPath, err := ClipPaths(tmp, "clip", "file", 1.0, 3.0)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	expectedPng := filepath.Join(tmp, "clip_file_1_3.png")
	expectedWav := filepath.Join(tmp, "clip_file_1_3.wav")
	if pngPath != expectedPng {
		t.Errorf("pngPath = %q, want %q", pngPath, expectedPng)
	}
	if wavPath != expectedWav {
		t.Errorf("wavPath = %q, want %q", wavPath, expectedWav)
	}

	// Collision detection
	os.Create(expectedPng)
	_, _, err = ClipPaths(tmp, "clip", "file", 1.0, 3.0)
	if err == nil {
		t.Error("expected error for existing file")
	}
}

func TestWritePNGFile(t *testing.T) {
	tmp := t.TempDir()

	// Create a simple test image (grayscale 2x2)
	gray := [][]uint8{{128, 64}, {32, 16}}
	img := CreateGrayscaleImage(gray)
	if img == nil {
		t.Fatal("failed to create test image")
	}

	path := filepath.Join(tmp, "test.png")
	if err := WritePNGFile(path, img); err != nil {
		t.Fatalf("WritePNGFile failed: %v", err)
	}

	// Verify file exists
	if _, err := os.Stat(path); err != nil {
		t.Errorf("file not created: %v", err)
	}

	// Collision detection
	err := WritePNGFile(path, img)
	if err == nil {
		t.Error("expected error for existing file")
	}
}

func TestSpectrogramImageFromSamples(t *testing.T) {
	// Create a simple sine wave
	const sampleRate = 16000
	const duration = 0.1 // 100ms
	samples := make([]float64, int(sampleRate*duration))
	for i := range samples {
		samples[i] = 0.5 // DC signal
	}

	img := SpectrogramImageFromSamples(samples, sampleRate, true, 224)
	if img == nil {
		t.Fatal("expected non-nil image")
	}

	bounds := img.Bounds()
	if bounds.Dx() != 224 || bounds.Dy() != 224 {
		t.Errorf("expected 224x224, got %dx%d", bounds.Dx(), bounds.Dy())
	}

	// Grayscale variant
	imgGray := SpectrogramImageFromSamples(samples, sampleRate, false, 224)
	if imgGray == nil {
		t.Error("expected non-nil grayscale image")
	}

	// Empty samples
	imgEmpty := SpectrogramImageFromSamples(nil, sampleRate, true, 224)
	if imgEmpty != nil {
		t.Error("expected nil for empty samples")
	}
}