package tools

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

func TestShouldPrependFile(t *testing.T) {
	tests := []struct {
		name       string
		filename   string
		prefix     string
		wantRename bool
		wantReason string
	}{
		// WAV files with datestring
		{"wav with datestring", "20250920_011509.wav", "LOC", true, ""},
		{"WAV with datestring", "20250920_011509.WAV", "LOC", true, ""},
		{"wav.data with datestring", "20250920_011509.wav.data", "LOC", true, ""},
		{"WAV.data with datestring", "20250920_011509.WAV.data", "LOC", true, ""},

		// Already prefixed
		{"already prefixed wav", "LOC_20250920_011509.wav", "LOC", false, "already prefixed"},
		{"already prefixed log.txt", "LOC_log.txt", "LOC", false, "already prefixed"},

		// No datestring
		{"no datestring wav", "mok_nearcamp2_20250920.wav", "LOC", false, "no datestring prefix"},
		{"no datestring WAV", "recording.WAV", "LOC", false, "no datestring prefix"},

		// log.txt
		{"log.txt", "log.txt", "LOC", true, ""},

		// Non-target files (silently ignored)
		{"readme", "README.txt", "LOC", false, ""},
		{"random file", "something.mp3", "LOC", false, ""},
		{"LOG.TXT uppercase", "LOG.TXT", "LOC", false, ""}, // Only lowercase log.txt matches
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			gotRename, gotReason := shouldPrependFile(tt.filename, tt.prefix)
			if gotRename != tt.wantRename {
				t.Errorf("shouldPrependFile() gotRename = %v, want %v", gotRename, tt.wantRename)
			}
			if gotReason != tt.wantReason {
				t.Errorf("shouldPrependFile() gotReason = %v, want %v", gotReason, tt.wantReason)
			}
		})
	}
}

func TestPrepend(t *testing.T) {
	// Create temp folder
	tmpDir, err := os.MkdirTemp("", "prepend_test")
	if err != nil {
		t.Fatalf("Failed to create temp dir: %v", err)
	}
	defer os.RemoveAll(tmpDir)

	// Create test files
	testFiles := []string{
		"20250920_011509.wav",
		"20250920_011509.wav.data",
		"log.txt",
		"mok_nearcamp2_20250920.wav",
		"README.txt",
	}
	for _, f := range testFiles {
		if err := os.WriteFile(filepath.Join(tmpDir, f), []byte{}, 0644); err != nil {
			t.Fatalf("Failed to create test file: %v", err)
		}
	}

	// Run prepend
	output, err := Prepend(PrependInput{
		Folder:    tmpDir,
		Prefix:    "TEST",
		Recursive: false,
		DryRun:    false,
	})
	if err != nil {
		t.Fatalf("Prepend() error = %v", err)
	}

	// Verify renamed files
	if len(output.Renamed) != 3 {
		t.Errorf("Expected 3 renamed files, got %d", len(output.Renamed))
	}

	// Verify skipped files
	if len(output.Skipped) != 1 {
		t.Errorf("Expected 1 skipped file, got %d", len(output.Skipped))
	}

	// Verify files were actually renamed
	if _, err := os.Stat(filepath.Join(tmpDir, "TEST_20250920_011509.wav")); os.IsNotExist(err) {
		t.Error("Expected TEST_20250920_011509.wav to exist")
	}
	if _, err := os.Stat(filepath.Join(tmpDir, "TEST_log.txt")); os.IsNotExist(err) {
		t.Error("Expected TEST_log.txt to exist")
	}
	if _, err := os.Stat(filepath.Join(tmpDir, "mok_nearcamp2_20250920.wav")); os.IsNotExist(err) {
		t.Error("Expected mok_nearcamp2_20250920.wav to still exist (skipped)")
	}
}

func TestPrependRecursive(t *testing.T) {
	// Create temp folder with subfolder
	tmpDir, err := os.MkdirTemp("", "prepend_test")
	if err != nil {
		t.Fatalf("Failed to create temp dir: %v", err)
	}
	defer os.RemoveAll(tmpDir)

	subDir := filepath.Join(tmpDir, "subfolder")
	if err := os.Mkdir(subDir, 0755); err != nil {
		t.Fatalf("Failed to create subfolder: %v", err)
	}

	// Create test files
	files := map[string]string{
		filepath.Join(tmpDir, "20250920_011509.wav"): "",
		filepath.Join(subDir, "20250921_120000.wav"): "",
		filepath.Join(subDir, "log.txt"):             "",
	}
	for f := range files {
		if err := os.WriteFile(f, []byte{}, 0644); err != nil {
			t.Fatalf("Failed to create test file: %v", err)
		}
	}

	// Run prepend with recursive
	output, err := Prepend(PrependInput{
		Folder:    tmpDir,
		Prefix:    "TEST",
		Recursive: true,
		DryRun:    false,
	})
	if err != nil {
		t.Fatalf("Prepend() error = %v", err)
	}

	// Should rename files in both folders
	if len(output.Renamed) != 3 {
		t.Errorf("Expected 3 renamed files (recursive), got %d", len(output.Renamed))
	}

	// Verify subfolder file was renamed
	if _, err := os.Stat(filepath.Join(subDir, "TEST_20250921_120000.wav")); os.IsNotExist(err) {
		t.Error("Expected TEST_20250921_120000.wav in subfolder to exist")
	}
}

func TestPrependDryRun(t *testing.T) {
	tmpDir, err := os.MkdirTemp("", "prepend_test")
	if err != nil {
		t.Fatalf("Failed to create temp dir: %v", err)
	}
	defer os.RemoveAll(tmpDir)

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

	// Run prepend with dry-run
	output, err := Prepend(PrependInput{
		Folder:    tmpDir,
		Prefix:    "TEST",
		Recursive: false,
		DryRun:    true,
	})
	if err != nil {
		t.Fatalf("Prepend() error = %v", err)
	}

	// Should report renamed files
	if len(output.Renamed) != 1 {
		t.Errorf("Expected 1 renamed file in dry-run output, got %d", len(output.Renamed))
	}

	// But file should NOT be renamed
	if _, err := os.Stat(filepath.Join(tmpDir, "TEST_20250920_011509.wav")); !os.IsNotExist(err) {
		t.Error("Expected file NOT to be renamed in dry-run mode")
	}
}

func TestPrependIdempotent(t *testing.T) {
	tmpDir, err := os.MkdirTemp("", "prepend_test")
	if err != nil {
		t.Fatalf("Failed to create temp dir: %v", err)
	}
	defer os.RemoveAll(tmpDir)

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

	// Run prepend twice
	for i := range 2 {
		output, err := Prepend(PrependInput{
			Folder:    tmpDir,
			Prefix:    "TEST",
			Recursive: false,
			DryRun:    false,
		})
		if err != nil {
			t.Fatalf("Prepend() iteration %d error = %v", i, err)
		}

		if i == 0 {
			// First run should rename
			if len(output.Renamed) != 1 {
				t.Errorf("First run: expected 1 renamed file, got %d", len(output.Renamed))
			}
		} else {
			// Second run should skip (already prefixed)
			if len(output.Renamed) != 0 {
				t.Errorf("Second run: expected 0 renamed files, got %d", len(output.Renamed))
			}
			if len(output.Skipped) != 1 {
				t.Errorf("Second run: expected 1 skipped file, got %d", len(output.Skipped))
			}
		}
	}
}