package config

import (
	"os"
	"testing"
)

// TestGetEnv tests the getEnv helper function
func TestGetEnv(t *testing.T) {
	// Test with default value when env var not set
	result := getEnv("TEST_NONEXISTENT_VAR_12345", "default")
	if result != "default" {
		t.Errorf("Expected 'default', got '%s'", result)
	}

	// Test with set env var
	os.Setenv("TEST_ENV_VAR", "custom_value")
	defer os.Unsetenv("TEST_ENV_VAR")

	result = getEnv("TEST_ENV_VAR", "default")
	if result != "custom_value" {
		t.Errorf("Expected 'custom_value', got '%s'", result)
	}
}

// TestGetEnvInt tests the getEnvInt helper function
func TestGetEnvInt(t *testing.T) {
	tests := []struct {
		name         string
		envValue     string
		defaultValue int
		expected     int
	}{
		{"default when not set", "", 100, 100},
		{"parse valid int", "42", 0, 42},
		{"parse zero", "0", 100, 0},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if tt.envValue != "" {
				os.Setenv("TEST_INT_VAR", tt.envValue)
				defer os.Unsetenv("TEST_INT_VAR")
			} else {
				os.Unsetenv("TEST_INT_VAR")
			}

			result := getEnvInt("TEST_INT_VAR", tt.defaultValue)
			if result != tt.expected {
				t.Errorf("Expected %d, got %d", tt.expected, result)
			}
		})
	}
}

// TestGetEnvBool tests the getEnvBool helper function
func TestGetEnvBool(t *testing.T) {
	tests := []struct {
		name         string
		envValue     string
		defaultValue bool
		expected     bool
	}{
		{"default when not set", "", true, true},
		{"default false when not set", "", false, false},
		{"parse true", "true", false, true},
		{"parse 1", "1", false, true},
		{"parse yes", "yes", false, true},
		{"parse false", "false", true, false},
		{"parse 0", "0", true, false},
		{"parse no", "no", true, false},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if tt.envValue != "" {
				os.Setenv("TEST_BOOL_VAR", tt.envValue)
				defer os.Unsetenv("TEST_BOOL_VAR")
			} else {
				os.Unsetenv("TEST_BOOL_VAR")
			}

			result := getEnvBool("TEST_BOOL_VAR", tt.defaultValue)
			if result != tt.expected {
				t.Errorf("Expected %v, got %v", tt.expected, result)
			}
		})
	}
}

// TestParseCommaSeparated tests the parseCommaSeparated helper function
func TestParseCommaSeparated(t *testing.T) {
	tests := []struct {
		name     string
		input    string
		expected []string
	}{
		{"empty string", "", []string{}},
		{"single value", "value1", []string{"value1"}},
		{"multiple values", "value1,value2,value3", []string{"value1", "value2", "value3"}},
		{"with spaces", "value1, value2, value3", []string{"value1", "value2", "value3"}},
		{"with trailing comma", "value1,value2,", []string{"value1", "value2"}},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result := parseCommaSeparated(tt.input)
			if len(result) != len(tt.expected) {
				t.Errorf("Expected length %d, got %d", len(tt.expected), len(result))
				return
			}
			for i := range result {
				if result[i] != tt.expected[i] {
					t.Errorf("At index %d: expected '%s', got '%s'", i, tt.expected[i], result[i])
				}
			}
		})
	}
}

// TestConfigEnvironmentDefaults tests default environment values
func TestConfigEnvironmentDefaults(t *testing.T) {
	// Clear any existing env vars that might interfere
	varsToUnset := []string{
		"PORT", "ENVIRONMENT", "DATABASE_URL", "JWT_SECRET", "JWT_REFRESH_SECRET",
	}
	for _, v := range varsToUnset {
		os.Unsetenv(v)
	}

	// Set required vars
	os.Setenv("DATABASE_URL", "postgres://test:test@localhost:5432/test")
	os.Setenv("JWT_SECRET", "test-secret-32-chars-minimum-here")
	defer func() {
		os.Unsetenv("DATABASE_URL")
		os.Unsetenv("JWT_SECRET")
	}()

	cfg, err := Load()
	if err != nil {
		t.Fatalf("Failed to load config: %v", err)
	}

	// Test defaults
	if cfg.Port != "8080" {
		t.Errorf("Expected default port '8080', got '%s'", cfg.Port)
	}

	if cfg.Environment != "development" {
		t.Errorf("Expected default environment 'development', got '%s'", cfg.Environment)
	}
}

// TestConfigLoadWithEnvironment tests loading config with different environments
func TestConfigLoadWithEnvironment(t *testing.T) {
	// Set required vars
	os.Setenv("DATABASE_URL", "postgres://test:test@localhost:5432/test")
	os.Setenv("JWT_SECRET", "test-secret-32-chars-minimum-here")
	defer func() {
		os.Unsetenv("DATABASE_URL")
		os.Unsetenv("JWT_SECRET")
	}()

	tests := []struct {
		name        string
		environment string
	}{
		{"development", "development"},
		{"staging", "staging"},
		{"production", "production"},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			os.Setenv("ENVIRONMENT", tt.environment)
			defer os.Unsetenv("ENVIRONMENT")

			cfg, err := Load()
			if err != nil {
				t.Fatalf("Failed to load config: %v", err)
			}

			if cfg.Environment != tt.environment {
				t.Errorf("Expected environment '%s', got '%s'", tt.environment, cfg.Environment)
			}
		})
	}
}

// TestConfigMissingRequiredVars tests that missing required vars return errors
func TestConfigMissingRequiredVars(t *testing.T) {
	// Clear all env vars
	os.Unsetenv("DATABASE_URL")
	os.Unsetenv("JWT_SECRET")

	_, err := Load()
	if err == nil {
		t.Error("Expected error when DATABASE_URL is missing")
	}

	// Set DATABASE_URL but not JWT_SECRET
	os.Setenv("DATABASE_URL", "postgres://test:test@localhost:5432/test")
	defer os.Unsetenv("DATABASE_URL")

	_, err = Load()
	if err == nil {
		t.Error("Expected error when JWT_SECRET is missing")
	}
}

// TestConfigAllowedOrigins tests that allowed origins are parsed correctly
func TestConfigAllowedOrigins(t *testing.T) {
	// Set required vars
	os.Setenv("DATABASE_URL", "postgres://test:test@localhost:5432/test")
	os.Setenv("JWT_SECRET", "test-secret-32-chars-minimum-here")
	os.Setenv("ALLOWED_ORIGINS", "http://localhost:3000,http://localhost:8000,http://localhost:8001")
	defer func() {
		os.Unsetenv("DATABASE_URL")
		os.Unsetenv("JWT_SECRET")
		os.Unsetenv("ALLOWED_ORIGINS")
	}()

	cfg, err := Load()
	if err != nil {
		t.Fatalf("Failed to load config: %v", err)
	}

	expected := []string{"http://localhost:3000", "http://localhost:8000", "http://localhost:8001"}
	if len(cfg.AllowedOrigins) != len(expected) {
		t.Errorf("Expected %d origins, got %d", len(expected), len(cfg.AllowedOrigins))
	}

	for i, origin := range cfg.AllowedOrigins {
		if origin != expected[i] {
			t.Errorf("At index %d: expected '%s', got '%s'", i, expected[i], origin)
		}
	}
}

// TestConfigDebugSettings tests debug-related settings for different environments
func TestConfigDebugSettings(t *testing.T) {
	// Set required vars
	os.Setenv("DATABASE_URL", "postgres://test:test@localhost:5432/test")
	os.Setenv("JWT_SECRET", "test-secret-32-chars-minimum-here")
	defer func() {
		os.Unsetenv("DATABASE_URL")
		os.Unsetenv("JWT_SECRET")
	}()

	// Test development environment
	t.Run("development", func(t *testing.T) {
		os.Setenv("ENVIRONMENT", "development")
		defer os.Unsetenv("ENVIRONMENT")

		cfg, err := Load()
		if err != nil {
			t.Fatalf("Failed to load config: %v", err)
		}

		if cfg.Environment != "development" {
			t.Errorf("Expected 'development', got '%s'", cfg.Environment)
		}
	})

	// Test staging environment
	t.Run("staging", func(t *testing.T) {
		os.Setenv("ENVIRONMENT", "staging")
		defer os.Unsetenv("ENVIRONMENT")

		cfg, err := Load()
		if err != nil {
			t.Fatalf("Failed to load config: %v", err)
		}

		if cfg.Environment != "staging" {
			t.Errorf("Expected 'staging', got '%s'", cfg.Environment)
		}
	})

	// Test production environment
	t.Run("production", func(t *testing.T) {
		os.Setenv("ENVIRONMENT", "production")
		defer os.Unsetenv("ENVIRONMENT")

		cfg, err := Load()
		if err != nil {
			t.Fatalf("Failed to load config: %v", err)
		}

		if cfg.Environment != "production" {
			t.Errorf("Expected 'production', got '%s'", cfg.Environment)
		}
	})
}

// TestConfigStagingPorts tests that staging uses different ports
func TestConfigStagingPorts(t *testing.T) {
	// Set required vars
	os.Setenv("DATABASE_URL", "postgres://test:test@localhost:5433/breakpilot_staging")
	os.Setenv("JWT_SECRET", "test-secret-32-chars-minimum-here")
	os.Setenv("ENVIRONMENT", "staging")
	os.Setenv("PORT", "8081")
	defer func() {
		os.Unsetenv("DATABASE_URL")
		os.Unsetenv("JWT_SECRET")
		os.Unsetenv("ENVIRONMENT")
		os.Unsetenv("PORT")
	}()

	cfg, err := Load()
	if err != nil {
		t.Fatalf("Failed to load config: %v", err)
	}

	if cfg.Port != "8081" {
		t.Errorf("Expected staging port '8081', got '%s'", cfg.Port)
	}

	if cfg.Environment != "staging" {
		t.Errorf("Expected 'staging', got '%s'", cfg.Environment)
	}
}
