package utils

import (
	"testing"
)

func TestValidateShortID(t *testing.T) {
	tests := []struct {
		name      string
		id        string
		fieldName string
		wantErr   bool
	}{
		{"valid 12-char ID", "abc123XYZ789", "test_id", false},
		{"valid with underscore", "abc_123_XYZ_", "test_id", false},
		{"valid with dash", "abc-123-XYZ-", "test_id", false},
		{"empty string", "", "test_id", true},
		{"too short", "abc123", "test_id", true},
		{"too long", "abc123XYZ789toolong", "test_id", true},
		{"invalid chars", "abc@123#XYZ$", "test_id", true},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			err := ValidateShortID(tt.id, tt.fieldName)
			if (err != nil) != tt.wantErr {
				t.Errorf("ValidateShortID() error = %v, wantErr %v", err, tt.wantErr)
			}
		})
	}
}

func TestValidateStringLength(t *testing.T) {
	tests := []struct {
		name    string
		value   string
		field   string
		maxLen  int
		wantErr bool
	}{
		{"within limit", "hello", "test", 10, false},
		{"at limit", "1234567890", "test", 10, false},
		{"empty string", "", "test", 10, false},
		{"over limit", "12345678901", "test", 10, true},
		{"zero max", "a", "test", 0, true},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			err := ValidateStringLength(tt.value, tt.field, tt.maxLen)
			if (err != nil) != tt.wantErr {
				t.Errorf("ValidateStringLength() error = %v, wantErr %v", err, tt.wantErr)
			}
		})
	}
}

func TestValidateRange(t *testing.T) {
	t.Run("int range", func(t *testing.T) {
		tests := []struct {
			name    string
			value   int
			min     int
			max     int
			wantErr bool
		}{
			{"within range", 50, 0, 100, false},
			{"at min", 0, 0, 100, false},
			{"at max", 100, 0, 100, false},
			{"below min", -1, 0, 100, true},
			{"above max", 101, 0, 100, true},
		}

		for _, tt := range tests {
			t.Run(tt.name, func(t *testing.T) {
				err := ValidateRange(tt.value, "test", tt.min, tt.max)
				if (err != nil) != tt.wantErr {
					t.Errorf("ValidateRange() error = %v, wantErr %v", err, tt.wantErr)
				}
			})
		}
	})

	t.Run("float64 range", func(t *testing.T) {
		tests := []struct {
			name    string
			value   float64
			min     float64
			max     float64
			wantErr bool
		}{
			{"within range", 45.5, -90.0, 90.0, false},
			{"at min", -90.0, -90.0, 90.0, false},
			{"at max", 90.0, -90.0, 90.0, false},
			{"below min", -90.1, -90.0, 90.0, true},
			{"above max", 90.1, -90.0, 90.0, true},
		}

		for _, tt := range tests {
			t.Run(tt.name, func(t *testing.T) {
				err := ValidateRange(tt.value, "test", tt.min, tt.max)
				if (err != nil) != tt.wantErr {
					t.Errorf("ValidateRange() error = %v, wantErr %v", err, tt.wantErr)
				}
			})
		}
	})
}

func TestValidatePositive(t *testing.T) {
	tests := []struct {
		name    string
		value   int
		wantErr bool
	}{
		{"positive", 1, false},
		{"large positive", 1000000, false},
		{"zero", 0, true},
		{"negative", -1, true},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			err := ValidatePositive(tt.value, "test")
			if (err != nil) != tt.wantErr {
				t.Errorf("ValidatePositive() error = %v, wantErr %v", err, tt.wantErr)
			}
		})
	}
}

func TestValidateSampleRate(t *testing.T) {
	tests := []struct {
		name    string
		rate    int
		wantErr bool
	}{
		{"valid low", 1000, false},
		{"valid typical", 48000, false},
		{"valid high", 250000, false},
		{"valid max", 500000, false},
		{"too low", 999, true},
		{"too high", 500001, true},
		{"zero", 0, true},
		{"negative", -1000, true},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			err := ValidateSampleRate(tt.rate)
			if (err != nil) != tt.wantErr {
				t.Errorf("ValidateSampleRate() error = %v, wantErr %v", err, tt.wantErr)
			}
		})
	}
}

func TestValidateTimezone(t *testing.T) {
	tests := []struct {
		name    string
		tz      string
		wantErr bool
	}{
		{"valid Auckland", "Pacific/Auckland", false},
		{"valid UTC", "UTC", false},
		{"valid America/New_York", "America/New_York", false},
		{"valid Europe/London", "Europe/London", false},
		{"invalid", "Invalid/Timezone", true},
		{"garbage", "not-a-timezone", true},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			err := ValidateTimezone(tt.tz)
			if (err != nil) != tt.wantErr {
				t.Errorf("ValidateTimezone() error = %v, wantErr %v", err, tt.wantErr)
			}
		})
	}
}

func TestValidateNonNegative(t *testing.T) {
	tests := []struct {
		name    string
		value   int
		wantErr bool
	}{
		{"positive", 1, false},
		{"zero", 0, false},
		{"negative", -1, true},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			err := ValidateNonNegative(tt.value, "test")
			if (err != nil) != tt.wantErr {
				t.Errorf("ValidateNonNegative() error = %v, wantErr %v", err, tt.wantErr)
			}
		})
	}
}