package ucca

import (
	"testing"
)

// ============================================================================
// EscalationTrigger Tests
// ============================================================================

func TestDetermineEscalationLevel_E0_LowRiskInfoOnly(t *testing.T) {
	trigger := DefaultEscalationTrigger()

	result := &AssessmentResult{
		Feasibility: FeasibilityYES,
		RiskLevel:   RiskLevelMINIMAL,
		RiskScore:   10,
		TriggeredRules: []TriggeredRule{
			{Code: "R-INFO-001", Severity: "INFO", Description: "Informative Regel"},
		},
		DSFARecommended: false,
		Art22Risk:       false,
	}

	level, reason := trigger.DetermineEscalationLevel(result)

	if level != EscalationLevelE0 {
		t.Errorf("Expected E0 for low-risk case, got %s", level)
	}
	if reason == "" {
		t.Error("Expected non-empty reason")
	}
}

func TestDetermineEscalationLevel_E1_WarnRules(t *testing.T) {
	trigger := DefaultEscalationTrigger()

	result := &AssessmentResult{
		Feasibility: FeasibilityCONDITIONAL,
		RiskLevel:   RiskLevelLOW,
		RiskScore:   25,
		TriggeredRules: []TriggeredRule{
			{Code: "R-WARN-001", Severity: "WARN", Description: "Warnung"},
		},
		DSFARecommended: false,
		Art22Risk:       false,
	}

	level, reason := trigger.DetermineEscalationLevel(result)

	if level != EscalationLevelE1 {
		t.Errorf("Expected E1 for WARN rule, got %s", level)
	}
	if reason == "" {
		t.Error("Expected non-empty reason")
	}
}

func TestDetermineEscalationLevel_E1_RiskScore20to40(t *testing.T) {
	trigger := DefaultEscalationTrigger()

	result := &AssessmentResult{
		Feasibility:     FeasibilityCONDITIONAL,
		RiskLevel:       RiskLevelLOW,
		RiskScore:       35,
		TriggeredRules:  []TriggeredRule{},
		DSFARecommended: false,
		Art22Risk:       false,
	}

	level, _ := trigger.DetermineEscalationLevel(result)

	if level != EscalationLevelE1 {
		t.Errorf("Expected E1 for risk score 35, got %s", level)
	}
}

func TestDetermineEscalationLevel_E2_Article9Data(t *testing.T) {
	trigger := DefaultEscalationTrigger()

	result := &AssessmentResult{
		Feasibility: FeasibilityCONDITIONAL,
		RiskLevel:   RiskLevelMEDIUM,
		RiskScore:   45,
		TriggeredRules: []TriggeredRule{
			{Code: "R-002", Severity: "WARN", Description: "Art. 9 Daten"},
		},
		DSFARecommended: false,
		Art22Risk:       false,
	}

	level, reason := trigger.DetermineEscalationLevel(result)

	if level != EscalationLevelE2 {
		t.Errorf("Expected E2 for Art. 9 data, got %s", level)
	}
	if reason == "" {
		t.Error("Expected non-empty reason mentioning Art. 9")
	}
}

func TestDetermineEscalationLevel_E2_DSFARecommended(t *testing.T) {
	trigger := DefaultEscalationTrigger()

	result := &AssessmentResult{
		Feasibility:     FeasibilityCONDITIONAL,
		RiskLevel:       RiskLevelMEDIUM,
		RiskScore:       42,
		TriggeredRules:  []TriggeredRule{},
		DSFARecommended: true,
		Art22Risk:       false,
	}

	level, reason := trigger.DetermineEscalationLevel(result)

	if level != EscalationLevelE2 {
		t.Errorf("Expected E2 for DSFA recommended, got %s", level)
	}
	if reason == "" {
		t.Error("Expected reason to mention DSFA")
	}
}

func TestDetermineEscalationLevel_E3_BlockRule(t *testing.T) {
	trigger := DefaultEscalationTrigger()

	result := &AssessmentResult{
		Feasibility: FeasibilityNO,
		RiskLevel:   RiskLevelHIGH,
		RiskScore:   75,
		TriggeredRules: []TriggeredRule{
			{Code: "R-BLOCK-001", Severity: "BLOCK", Description: "Blockierung"},
		},
		DSFARecommended: true,
		Art22Risk:       false,
	}

	level, reason := trigger.DetermineEscalationLevel(result)

	if level != EscalationLevelE3 {
		t.Errorf("Expected E3 for BLOCK rule, got %s", level)
	}
	if reason == "" {
		t.Error("Expected reason to mention BLOCK")
	}
}

func TestDetermineEscalationLevel_E3_Art22Risk(t *testing.T) {
	trigger := DefaultEscalationTrigger()

	result := &AssessmentResult{
		Feasibility:     FeasibilityCONDITIONAL,
		RiskLevel:       RiskLevelHIGH,
		RiskScore:       55,
		TriggeredRules:  []TriggeredRule{},
		DSFARecommended: false,
		Art22Risk:       true,
	}

	level, reason := trigger.DetermineEscalationLevel(result)

	if level != EscalationLevelE3 {
		t.Errorf("Expected E3 for Art. 22 risk, got %s", level)
	}
	if reason == "" {
		t.Error("Expected reason to mention Art. 22")
	}
}

func TestDetermineEscalationLevel_E3_HighRiskScore(t *testing.T) {
	trigger := DefaultEscalationTrigger()

	result := &AssessmentResult{
		Feasibility:     FeasibilityCONDITIONAL,
		RiskLevel:       RiskLevelHIGH,
		RiskScore:       70, // Above E3 threshold
		TriggeredRules:  []TriggeredRule{},
		DSFARecommended: false,
		Art22Risk:       false,
	}

	level, _ := trigger.DetermineEscalationLevel(result)

	if level != EscalationLevelE3 {
		t.Errorf("Expected E3 for risk score 70, got %s", level)
	}
}

// ============================================================================
// SLA Tests
// ============================================================================

func TestGetDefaultSLA_E0(t *testing.T) {
	response, resolution := GetDefaultSLA(EscalationLevelE0)

	if response != 0 || resolution != 0 {
		t.Errorf("E0 should have no SLA, got response=%d, resolution=%d", response, resolution)
	}
}

func TestGetDefaultSLA_E1(t *testing.T) {
	response, resolution := GetDefaultSLA(EscalationLevelE1)

	if response != 24 {
		t.Errorf("E1 should have 24h response SLA, got %d", response)
	}
	if resolution != 72 {
		t.Errorf("E1 should have 72h resolution SLA, got %d", resolution)
	}
}

func TestGetDefaultSLA_E2(t *testing.T) {
	response, resolution := GetDefaultSLA(EscalationLevelE2)

	if response != 8 {
		t.Errorf("E2 should have 8h response SLA, got %d", response)
	}
	if resolution != 48 {
		t.Errorf("E2 should have 48h resolution SLA, got %d", resolution)
	}
}

func TestGetDefaultSLA_E3(t *testing.T) {
	response, resolution := GetDefaultSLA(EscalationLevelE3)

	if response != 4 {
		t.Errorf("E3 should have 4h response SLA, got %d", response)
	}
	if resolution != 24 {
		t.Errorf("E3 should have 24h resolution SLA, got %d", resolution)
	}
}

// ============================================================================
// Role Assignment Tests
// ============================================================================

func TestGetRoleForLevel_E0(t *testing.T) {
	role := GetRoleForLevel(EscalationLevelE0)
	if role != "" {
		t.Errorf("E0 should have no role, got %s", role)
	}
}

func TestGetRoleForLevel_E1(t *testing.T) {
	role := GetRoleForLevel(EscalationLevelE1)
	if role != "team_lead" {
		t.Errorf("E1 should require team_lead, got %s", role)
	}
}

func TestGetRoleForLevel_E2(t *testing.T) {
	role := GetRoleForLevel(EscalationLevelE2)
	if role != "dsb" {
		t.Errorf("E2 should require dsb, got %s", role)
	}
}

func TestGetRoleForLevel_E3(t *testing.T) {
	role := GetRoleForLevel(EscalationLevelE3)
	if role != "dsb" {
		t.Errorf("E3 should require dsb (primary), got %s", role)
	}
}

// ============================================================================
// Default Trigger Configuration Tests
// ============================================================================

func TestDefaultEscalationTrigger_Thresholds(t *testing.T) {
	trigger := DefaultEscalationTrigger()

	if trigger.E1RiskThreshold != 20 {
		t.Errorf("E1 threshold should be 20, got %d", trigger.E1RiskThreshold)
	}
	if trigger.E2RiskThreshold != 40 {
		t.Errorf("E2 threshold should be 40, got %d", trigger.E2RiskThreshold)
	}
	if trigger.E3RiskThreshold != 60 {
		t.Errorf("E3 threshold should be 60, got %d", trigger.E3RiskThreshold)
	}
}

// ============================================================================
// Edge Case Tests
// ============================================================================

func TestDetermineEscalationLevel_BoundaryRiskScores(t *testing.T) {
	trigger := DefaultEscalationTrigger()

	tests := []struct {
		name          string
		riskScore     int
		expectedLevel EscalationLevel
	}{
		{"Risk 0 → E0", 0, EscalationLevelE0},
		{"Risk 19 → E0", 19, EscalationLevelE0},
		{"Risk 20 → E0 (boundary)", 20, EscalationLevelE0},
		{"Risk 21 → E1", 21, EscalationLevelE1},
		{"Risk 39 → E1", 39, EscalationLevelE1},
		{"Risk 40 → E1 (boundary)", 40, EscalationLevelE1},
		{"Risk 41 → E2", 41, EscalationLevelE2},
		{"Risk 59 → E2", 59, EscalationLevelE2},
		{"Risk 60 → E2 (boundary)", 60, EscalationLevelE2},
		{"Risk 61 → E3", 61, EscalationLevelE3},
		{"Risk 100 → E3", 100, EscalationLevelE3},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result := &AssessmentResult{
				RiskScore:       tt.riskScore,
				TriggeredRules:  []TriggeredRule{},
				DSFARecommended: false,
				Art22Risk:       false,
			}

			level, _ := trigger.DetermineEscalationLevel(result)
			if level != tt.expectedLevel {
				t.Errorf("Expected %s for risk score %d, got %s", tt.expectedLevel, tt.riskScore, level)
			}
		})
	}
}

func TestDetermineEscalationLevel_CombinedFactors(t *testing.T) {
	trigger := DefaultEscalationTrigger()

	// Multiple E3 factors should still result in E3
	result := &AssessmentResult{
		RiskScore: 80,
		TriggeredRules: []TriggeredRule{
			{Code: "R-BLOCK-001", Severity: "BLOCK", Description: "Block 1"},
			{Code: "R-BLOCK-002", Severity: "BLOCK", Description: "Block 2"},
		},
		DSFARecommended: true,
		Art22Risk:       true,
	}

	level, reason := trigger.DetermineEscalationLevel(result)

	if level != EscalationLevelE3 {
		t.Errorf("Expected E3 for multiple high-risk factors, got %s", level)
	}

	// Reason should mention multiple factors
	if reason == "" {
		t.Error("Expected comprehensive reason for multiple factors")
	}
}

func TestDetermineEscalationLevel_EmptyRules(t *testing.T) {
	trigger := DefaultEscalationTrigger()

	result := &AssessmentResult{
		RiskScore:       5,
		TriggeredRules:  []TriggeredRule{},
		DSFARecommended: false,
		Art22Risk:       false,
	}

	level, _ := trigger.DetermineEscalationLevel(result)

	if level != EscalationLevelE0 {
		t.Errorf("Expected E0 for empty rules and low risk, got %s", level)
	}
}

// ============================================================================
// Constants Validation Tests
// ============================================================================

func TestEscalationLevelConstants(t *testing.T) {
	levels := []EscalationLevel{
		EscalationLevelE0,
		EscalationLevelE1,
		EscalationLevelE2,
		EscalationLevelE3,
	}

	expected := []string{"E0", "E1", "E2", "E3"}

	for i, level := range levels {
		if string(level) != expected[i] {
			t.Errorf("Expected %s, got %s", expected[i], level)
		}
	}
}

func TestEscalationStatusConstants(t *testing.T) {
	statuses := map[EscalationStatus]string{
		EscalationStatusPending:   "pending",
		EscalationStatusAssigned:  "assigned",
		EscalationStatusInReview:  "in_review",
		EscalationStatusApproved:  "approved",
		EscalationStatusRejected:  "rejected",
		EscalationStatusReturned:  "returned",
	}

	for status, expected := range statuses {
		if string(status) != expected {
			t.Errorf("Expected status %s, got %s", expected, status)
		}
	}
}

func TestEscalationDecisionConstants(t *testing.T) {
	decisions := map[EscalationDecision]string{
		EscalationDecisionApprove:  "approve",
		EscalationDecisionReject:   "reject",
		EscalationDecisionModify:   "modify",
		EscalationDecisionEscalate: "escalate",
	}

	for decision, expected := range decisions {
		if string(decision) != expected {
			t.Errorf("Expected decision %s, got %s", expected, decision)
		}
	}
}

// ============================================================================
// Helper Function Tests
// ============================================================================

func TestJoinReasons_Empty(t *testing.T) {
	result := joinReasons([]string{}, "Prefix: ")
	if result != "Prefix: " {
		t.Errorf("Expected 'Prefix: ', got '%s'", result)
	}
}

func TestJoinReasons_Single(t *testing.T) {
	result := joinReasons([]string{"Reason 1"}, "Test: ")
	if result != "Test: Reason 1" {
		t.Errorf("Expected 'Test: Reason 1', got '%s'", result)
	}
}

func TestJoinReasons_Multiple(t *testing.T) {
	result := joinReasons([]string{"Reason 1", "Reason 2", "Reason 3"}, "Test: ")
	expected := "Test: Reason 1; Reason 2; Reason 3"
	if result != expected {
		t.Errorf("Expected '%s', got '%s'", expected, result)
	}
}
