package configs

import (
	"strings"
	"testing"
)

// ─── normalizeOrigin ─────────────────────────────────────────────────────────

func TestNormalizeOrigin_ValidHTTP(t *testing.T) {
	if got := normalizeOrigin("http://localhost:3000"); got != "http://localhost:3000" {
		t.Fatalf("got %q", got)
	}
}

func TestNormalizeOrigin_ValidHTTPS(t *testing.T) {
	if got := normalizeOrigin("https://example.com"); got != "https://example.com" {
		t.Fatalf("got %q", got)
	}
}

func TestNormalizeOrigin_StripsTrailingSlash(t *testing.T) {
	got := normalizeOrigin("https://example.com/")
	// url.Parse keeps the trailing slash on host-only URLs, so we just check host is preserved
	if !strings.HasPrefix(got, "https://example.com") {
		t.Fatalf("unexpected result: %q", got)
	}
}

func TestNormalizeOrigin_UppercaseNormalized(t *testing.T) {
	got := normalizeOrigin("HTTP://EXAMPLE.COM")
	if got != "http://example.com" {
		t.Fatalf("expected lowercase, got %q", got)
	}
}

func TestNormalizeOrigin_Empty(t *testing.T) {
	if got := normalizeOrigin(""); got != "" {
		t.Fatalf("expected empty, got %q", got)
	}
}

func TestNormalizeOrigin_Whitespace(t *testing.T) {
	if got := normalizeOrigin("   "); got != "" {
		t.Fatalf("expected empty for whitespace, got %q", got)
	}
}

func TestNormalizeOrigin_NoScheme(t *testing.T) {
	if got := normalizeOrigin("example.com"); got != "" {
		t.Fatalf("expected empty for missing scheme, got %q", got)
	}
}

func TestNormalizeOrigin_QuotedValue(t *testing.T) {
	if got := normalizeOrigin(`'http://localhost:8080'`); got != "http://localhost:8080" {
		t.Fatalf("got %q", got)
	}
}

// ─── parseOriginList ─────────────────────────────────────────────────────────

func TestParseOriginList_MultipleEntries(t *testing.T) {
	list := parseOriginList("http://localhost:3000,https://example.com")
	if len(list) != 2 {
		t.Fatalf("expected 2 entries, got %d", len(list))
	}
}

func TestParseOriginList_EmptyString(t *testing.T) {
	list := parseOriginList("")
	if len(list) != 0 {
		t.Fatalf("expected 0 entries, got %d: %v", len(list), list)
	}
}

func TestParseOriginList_InvalidEntriesSkipped(t *testing.T) {
	list := parseOriginList("http://good.com,not-a-url,http://also-good.com")
	if len(list) != 2 {
		t.Fatalf("expected 2 valid entries, got %d: %v", len(list), list)
	}
}

func TestParseOriginList_DuplicatesPassThrough(t *testing.T) {
	// parseOriginList itself does NOT deduplicate; bootstrapWhitelistOrigins does.
	list := parseOriginList("http://dup.com,http://dup.com")
	if len(list) != 2 {
		t.Fatalf("parseOriginList should keep duplicates, got %d", len(list))
	}
}

// ─── envIntOr ────────────────────────────────────────────────────────────────

func TestEnvIntOr_MissingUsesDefault(t *testing.T) {
	t.Setenv("__TEST_INT_MISSING__", "")
	if got := envIntOr("__TEST_INT_MISSING__", 42); got != 42 {
		t.Fatalf("expected 42, got %d", got)
	}
}

func TestEnvIntOr_ValidValue(t *testing.T) {
	t.Setenv("__TEST_INT__", "99")
	if got := envIntOr("__TEST_INT__", 1); got != 99 {
		t.Fatalf("expected 99, got %d", got)
	}
}

func TestEnvIntOr_InvalidStringUsesDefault(t *testing.T) {
	t.Setenv("__TEST_INT_BAD__", "abc")
	if got := envIntOr("__TEST_INT_BAD__", 7); got != 7 {
		t.Fatalf("expected fallback 7, got %d", got)
	}
}

func TestEnvIntOr_ZeroUsesDefault(t *testing.T) {
	t.Setenv("__TEST_INT_ZERO__", "0")
	if got := envIntOr("__TEST_INT_ZERO__", 5); got != 5 {
		t.Fatalf("expected fallback for 0, got %d", got)
	}
}

func TestEnvIntOr_NegativeUsesDefault(t *testing.T) {
	t.Setenv("__TEST_INT_NEG__", "-1")
	if got := envIntOr("__TEST_INT_NEG__", 3); got != 3 {
		t.Fatalf("expected fallback for negative, got %d", got)
	}
}

// ─── envInt64Or ──────────────────────────────────────────────────────────────

func TestEnvInt64Or_MissingUsesDefault(t *testing.T) {
	t.Setenv("__TEST_I64_MISSING__", "")
	if got := envInt64Or("__TEST_I64_MISSING__", 100); got != 100 {
		t.Fatalf("expected 100, got %d", got)
	}
}

func TestEnvInt64Or_ValidValue(t *testing.T) {
	t.Setenv("__TEST_I64__", "999")
	if got := envInt64Or("__TEST_I64__", 1); got != 999 {
		t.Fatalf("expected 999, got %d", got)
	}
}

func TestEnvInt64Or_InvalidUsesDefault(t *testing.T) {
	t.Setenv("__TEST_I64_BAD__", "not-a-number")
	if got := envInt64Or("__TEST_I64_BAD__", 50); got != 50 {
		t.Fatalf("expected fallback 50, got %d", got)
	}
}

// ─── bootstrapRateLimitRules ─────────────────────────────────────────────────

func TestBootstrapRateLimitRules_ContainsThreeRules(t *testing.T) {
	rules := bootstrapRateLimitRules()
	if len(rules) != 3 {
		t.Fatalf("expected 3 rules, got %d", len(rules))
	}
}

func TestBootstrapRateLimitRules_DefaultFallbacks(t *testing.T) {
	// Env vars temizlenerek varsayılan değerler test edilir.
	t.Setenv("RL_BOOTSTRAP_LOGIN_MAX_REQUESTS", "")
	t.Setenv("RL_BOOTSTRAP_LOGIN_WINDOW_SECONDS", "")

	rules := bootstrapRateLimitRules()
	loginRule := rules[0]

	if loginRule.MaxRequests != 10 {
		t.Fatalf("expected default MaxRequests=10, got %d", loginRule.MaxRequests)
	}
	if loginRule.WindowSeconds != 60 {
		t.Fatalf("expected default WindowSeconds=60, got %d", loginRule.WindowSeconds)
	}
}

func TestBootstrapRateLimitRules_EnvOverride(t *testing.T) {
	t.Setenv("RL_BOOTSTRAP_LOGIN_MAX_REQUESTS", "25")
	t.Setenv("RL_BOOTSTRAP_LOGIN_WINDOW_SECONDS", "120")

	rules := bootstrapRateLimitRules()
	loginRule := rules[0]

	if loginRule.MaxRequests != 25 {
		t.Fatalf("expected MaxRequests=25, got %d", loginRule.MaxRequests)
	}
	if loginRule.WindowSeconds != 120 {
		t.Fatalf("expected WindowSeconds=120, got %d", loginRule.WindowSeconds)
	}
}

func TestBootstrapRateLimitRules_AllNamesNonEmpty(t *testing.T) {
	for _, r := range bootstrapRateLimitRules() {
		if r.Name == "" {
			t.Errorf("rate limit rule has empty Name: %+v", r)
		}
		if r.Description == "" {
			t.Errorf("rate limit rule has empty Description: %+v", r)
		}
	}
}

// ─── bootstrapWhitelistOrigins ───────────────────────────────────────────────

func TestBootstrapWhitelistOrigins_ContainsLocalDefaults(t *testing.T) {
	t.Setenv("CORS_BOOTSTRAP_WHITELIST_ORIGINS", "")
	t.Setenv("APP_BASE_URL", "")

	origins := bootstrapWhitelistOrigins()
	required := []string{
		"http://localhost:8080",
		"http://localhost:3000",
		"http://localhost:5173",
	}

	originSet := make(map[string]struct{}, len(origins))
	for _, o := range origins {
		originSet[o] = struct{}{}
	}

	for _, want := range required {
		if _, ok := originSet[want]; !ok {
			t.Errorf("expected default origin %q to be present", want)
		}
	}
}

func TestBootstrapWhitelistOrigins_NoDuplicates(t *testing.T) {
	t.Setenv("CORS_BOOTSTRAP_WHITELIST_ORIGINS", "http://localhost:3000,http://localhost:3000")

	origins := bootstrapWhitelistOrigins()
	seen := map[string]int{}
	for _, o := range origins {
		seen[o]++
	}
	for origin, count := range seen {
		if count > 1 {
			t.Errorf("duplicate origin in whitelist: %q (x%d)", origin, count)
		}
	}
}

func TestBootstrapWhitelistOrigins_AppBaseURLIncluded(t *testing.T) {
	t.Setenv("APP_BASE_URL", "https://myapp.example.com")
	defer t.Setenv("APP_BASE_URL", "")

	origins := bootstrapWhitelistOrigins()
	for _, o := range origins {
		if o == "https://myapp.example.com" {
			return
		}
	}
	t.Fatal("APP_BASE_URL origin not found in whitelist")
}
