package middleware

import (
	"testing"
)

func TestPIIRedactor_RedactsEmail(t *testing.T) {
	redactor := NewDefaultPIIRedactor()

	text := "User test@example.com logged in"
	result := redactor.Redact(text)

	if result == text {
		t.Error("Email should have been redacted")
	}
	if result != "User [EMAIL_REDACTED] logged in" {
		t.Errorf("Unexpected result: %s", result)
	}
}

func TestPIIRedactor_RedactsIPv4(t *testing.T) {
	redactor := NewDefaultPIIRedactor()

	text := "Request from 192.168.1.100"
	result := redactor.Redact(text)

	if result == text {
		t.Error("IP should have been redacted")
	}
	if result != "Request from [IP_REDACTED]" {
		t.Errorf("Unexpected result: %s", result)
	}
}

func TestPIIRedactor_RedactsGermanPhone(t *testing.T) {
	redactor := NewDefaultPIIRedactor()

	tests := []struct {
		input    string
		expected string
	}{
		{"+49 30 12345678", "[PHONE_REDACTED]"},
		{"0049 30 12345678", "[PHONE_REDACTED]"},
		{"030 12345678", "[PHONE_REDACTED]"},
	}

	for _, tt := range tests {
		result := redactor.Redact(tt.input)
		if result != tt.expected {
			t.Errorf("For input %q: expected %q, got %q", tt.input, tt.expected, result)
		}
	}
}

func TestPIIRedactor_RedactsMultiplePII(t *testing.T) {
	redactor := NewDefaultPIIRedactor()

	text := "User test@example.com from 10.0.0.1"
	result := redactor.Redact(text)

	if result != "User [EMAIL_REDACTED] from [IP_REDACTED]" {
		t.Errorf("Unexpected result: %s", result)
	}
}

func TestPIIRedactor_PreservesNonPIIText(t *testing.T) {
	redactor := NewDefaultPIIRedactor()

	text := "User logged in successfully"
	result := redactor.Redact(text)

	if result != text {
		t.Errorf("Text should be unchanged: got %s", result)
	}
}

func TestPIIRedactor_EmptyString(t *testing.T) {
	redactor := NewDefaultPIIRedactor()

	result := redactor.Redact("")
	if result != "" {
		t.Error("Empty string should remain empty")
	}
}

func TestContainsPII(t *testing.T) {
	redactor := NewDefaultPIIRedactor()

	tests := []struct {
		input    string
		expected bool
	}{
		{"test@example.com", true},
		{"192.168.1.1", true},
		{"+49 30 12345678", true},
		{"Hello World", false},
		{"", false},
	}

	for _, tt := range tests {
		result := redactor.ContainsPII(tt.input)
		if result != tt.expected {
			t.Errorf("For input %q: expected %v, got %v", tt.input, tt.expected, result)
		}
	}
}

func TestFindPII(t *testing.T) {
	redactor := NewDefaultPIIRedactor()

	text := "Email: test@example.com, IP: 10.0.0.1"
	findings := redactor.FindPII(text)

	if len(findings) != 2 {
		t.Errorf("Expected 2 findings, got %d", len(findings))
	}

	hasEmail := false
	hasIP := false
	for _, f := range findings {
		if f.Type == "email" {
			hasEmail = true
		}
		if f.Type == "ip_v4" {
			hasIP = true
		}
	}

	if !hasEmail {
		t.Error("Should have found email")
	}
	if !hasIP {
		t.Error("Should have found IP")
	}
}

func TestRedactPII_GlobalFunction(t *testing.T) {
	text := "User test@example.com logged in"
	result := RedactPII(text)

	if result == text {
		t.Error("Email should have been redacted")
	}
}

func TestContainsPIIDefault(t *testing.T) {
	if !ContainsPIIDefault("test@example.com") {
		t.Error("Should detect email as PII")
	}
	if ContainsPIIDefault("Hello World") {
		t.Error("Should not detect non-PII text")
	}
}

func TestRedactMap(t *testing.T) {
	data := map[string]interface{}{
		"email":   "test@example.com",
		"message": "Hello World",
		"nested": map[string]interface{}{
			"ip": "192.168.1.1",
		},
	}

	result := RedactMap(data)

	if result["email"] != "[EMAIL_REDACTED]" {
		t.Errorf("Email should be redacted: %v", result["email"])
	}
	if result["message"] != "Hello World" {
		t.Errorf("Non-PII should be unchanged: %v", result["message"])
	}

	nested := result["nested"].(map[string]interface{})
	if nested["ip"] != "[IP_REDACTED]" {
		t.Errorf("Nested IP should be redacted: %v", nested["ip"])
	}
}

func TestAllPIIPatterns(t *testing.T) {
	patterns := AllPIIPatterns()

	if len(patterns) == 0 {
		t.Error("Should have PII patterns")
	}

	// Check that we have the expected patterns
	expectedNames := []string{"email", "ip_v4", "ip_v6", "phone", "iban", "uuid", "name"}
	nameMap := make(map[string]bool)
	for _, p := range patterns {
		nameMap[p.Name] = true
	}

	for _, name := range expectedNames {
		if !nameMap[name] {
			t.Errorf("Missing expected pattern: %s", name)
		}
	}
}

func TestDefaultPIIPatterns(t *testing.T) {
	patterns := DefaultPIIPatterns()

	if len(patterns) != 4 {
		t.Errorf("Expected 4 default patterns, got %d", len(patterns))
	}
}

func TestIBANRedaction(t *testing.T) {
	redactor := NewPIIRedactor(AllPIIPatterns())

	text := "IBAN: DE89 3704 0044 0532 0130 00"
	result := redactor.Redact(text)

	if result == text {
		t.Error("IBAN should have been redacted")
	}
}

func TestUUIDRedaction(t *testing.T) {
	redactor := NewPIIRedactor(AllPIIPatterns())

	text := "User ID: a0000000-0000-0000-0000-000000000001"
	result := redactor.Redact(text)

	if result == text {
		t.Error("UUID should have been redacted")
	}
}
