package ucca

import (
	"testing"
)

// ============================================================================
// Financial Policy Engine Tests
// ============================================================================

func TestFinancialPolicyEngine_NewEngine(t *testing.T) {
	// Try to load the financial policy engine
	engine, err := NewFinancialPolicyEngineFromPath("../../policies/financial_regulations_policy.yaml")
	if err != nil {
		t.Skipf("Skipping test - policy file not found: %v", err)
	}

	if engine == nil {
		t.Fatal("Engine should not be nil")
	}

	version := engine.GetPolicyVersion()
	if version == "" {
		t.Error("Policy version should not be empty")
	}
}

func TestFinancialPolicyEngine_IsApplicable(t *testing.T) {
	engine := createTestFinancialEngine(t)
	if engine == nil {
		return
	}

	tests := []struct {
		name     string
		domain   Domain
		expected bool
	}{
		{"Banking domain is applicable", DomainBanking, true},
		{"Finance domain is applicable", DomainFinance, true},
		{"Insurance domain is applicable", DomainInsurance, true},
		{"Investment domain is applicable", DomainInvestment, true},
		{"Healthcare is not applicable", DomainHealthcare, false},
		{"Retail is not applicable", DomainRetail, false},
		{"Education is not applicable", DomainEducation, false},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			intake := &UseCaseIntake{
				Domain: tt.domain,
			}
			result := engine.IsApplicable(intake)
			if result != tt.expected {
				t.Errorf("IsApplicable() = %v, want %v", result, tt.expected)
			}
		})
	}
}

func TestFinancialPolicyEngine_Evaluate_NonApplicableDomain(t *testing.T) {
	engine := createTestFinancialEngine(t)
	if engine == nil {
		return
	}

	intake := &UseCaseIntake{
		Domain: DomainHealthcare,
		FinancialContext: &FinancialContext{
			FinancialEntity: FinancialEntity{
				Type:      FinancialEntityCreditInstitution,
				Regulated: true,
			},
		},
	}

	result := engine.Evaluate(intake)

	if result.IsApplicable {
		t.Error("Should not be applicable for healthcare domain")
	}
	if len(result.TriggeredRules) > 0 {
		t.Error("No rules should trigger for non-applicable domain")
	}
}

func TestFinancialPolicyEngine_Evaluate_MissingContext(t *testing.T) {
	engine := createTestFinancialEngine(t)
	if engine == nil {
		return
	}

	intake := &UseCaseIntake{
		Domain:           DomainBanking,
		FinancialContext: nil, // No financial context provided
	}

	result := engine.Evaluate(intake)

	if !result.IsApplicable {
		t.Error("Should be applicable for banking domain")
	}
	if !result.MissingContext {
		t.Error("Should indicate missing financial context")
	}
}

func TestFinancialPolicyEngine_Evaluate_RegulatedBank(t *testing.T) {
	engine := createTestFinancialEngine(t)
	if engine == nil {
		return
	}

	intake := &UseCaseIntake{
		Domain: DomainBanking,
		FinancialContext: &FinancialContext{
			FinancialEntity: FinancialEntity{
				Type:         FinancialEntityCreditInstitution,
				Regulated:    true,
				SizeCategory: SizeCategoryLessSignificant,
			},
			ICTService: ICTService{
				IsCritical:       false,
				IsOutsourced:     false,
				ProviderLocation: ProviderLocationEU,
			},
			AIApplication: FinancialAIApplication{
				AffectsCustomerDecisions: false,
				RiskAssessment:           false,
			},
		},
	}

	result := engine.Evaluate(intake)

	if !result.IsApplicable {
		t.Error("Should be applicable for banking domain")
	}
	if result.MissingContext {
		t.Error("Context should not be missing")
	}

	// Should trigger basic DORA/BAIT rules for regulated banks
	if len(result.TriggeredRules) == 0 {
		t.Error("Should trigger at least basic regulatory rules")
	}

	// Check for DORA control requirements
	hasDORAControl := false
	for _, ctrl := range result.RequiredControls {
		if ctrl.Category == "DORA" || ctrl.Category == "BAIT" {
			hasDORAControl = true
			break
		}
	}
	if !hasDORAControl {
		t.Error("Should require DORA or BAIT controls for regulated bank")
	}
}

func TestFinancialPolicyEngine_Evaluate_CriticalICTOutsourcing(t *testing.T) {
	engine := createTestFinancialEngine(t)
	if engine == nil {
		return
	}

	intake := &UseCaseIntake{
		Domain: DomainBanking,
		FinancialContext: &FinancialContext{
			FinancialEntity: FinancialEntity{
				Type:      FinancialEntityCreditInstitution,
				Regulated: true,
			},
			ICTService: ICTService{
				IsCritical:       true,
				IsOutsourced:     true,
				ProviderLocation: ProviderLocationEU,
			},
		},
	}

	result := engine.Evaluate(intake)

	// Should have elevated risk for critical ICT outsourcing
	if result.RiskScore == 0 {
		t.Error("Risk score should be elevated for critical ICT outsourcing")
	}

	// Should require TPP risk management control
	hasTPPControl := false
	for _, ctrl := range result.RequiredControls {
		if ctrl.ID == "CTRL-DORA-TPP-RISK-MANAGEMENT" || ctrl.ID == "CTRL-MARISK-OUTSOURCING" {
			hasTPPControl = true
			break
		}
	}
	if !hasTPPControl {
		t.Error("Should require TPP risk management for critical outsourcing")
	}

	// Should trigger escalation
	if result.EscalationLevel == "" {
		t.Error("Should trigger escalation for critical ICT outsourcing")
	}
}

func TestFinancialPolicyEngine_Evaluate_UnvalidatedRiskModel(t *testing.T) {
	engine := createTestFinancialEngine(t)
	if engine == nil {
		return
	}

	intake := &UseCaseIntake{
		Domain: DomainBanking,
		FinancialContext: &FinancialContext{
			FinancialEntity: FinancialEntity{
				Type:      FinancialEntityCreditInstitution,
				Regulated: true,
			},
			ICTService: ICTService{
				IsCritical:   false,
				IsOutsourced: false,
			},
			AIApplication: FinancialAIApplication{
				RiskAssessment:      true,
				ModelValidationDone: false, // Not validated!
			},
		},
	}

	result := engine.Evaluate(intake)

	// Should block unvalidated risk models
	if result.Feasibility != FeasibilityNO {
		t.Error("Should block use case with unvalidated risk model")
	}

	// Should require model validation control
	hasValidationControl := false
	for _, ctrl := range result.RequiredControls {
		if ctrl.ID == "CTRL-MARISK-MODEL-VALIDATION" {
			hasValidationControl = true
			break
		}
	}
	if !hasValidationControl {
		t.Error("Should require MaRisk model validation control")
	}
}

func TestFinancialPolicyEngine_Evaluate_ValidatedRiskModel(t *testing.T) {
	engine := createTestFinancialEngine(t)
	if engine == nil {
		return
	}

	intake := &UseCaseIntake{
		Domain: DomainBanking,
		FinancialContext: &FinancialContext{
			FinancialEntity: FinancialEntity{
				Type:      FinancialEntityCreditInstitution,
				Regulated: true,
			},
			ICTService: ICTService{
				IsCritical:   false,
				IsOutsourced: false,
			},
			AIApplication: FinancialAIApplication{
				RiskAssessment:      true,
				ModelValidationDone: true, // Validated!
			},
		},
	}

	result := engine.Evaluate(intake)

	// Should not block validated risk models
	if result.Feasibility == FeasibilityNO {
		t.Error("Should not block use case with validated risk model")
	}
}

func TestFinancialPolicyEngine_Evaluate_AlgorithmicTrading(t *testing.T) {
	engine := createTestFinancialEngine(t)
	if engine == nil {
		return
	}

	intake := &UseCaseIntake{
		Domain: DomainInvestment,
		FinancialContext: &FinancialContext{
			FinancialEntity: FinancialEntity{
				Type:      FinancialEntityInvestmentFirm,
				Regulated: true,
			},
			AIApplication: FinancialAIApplication{
				AlgorithmicTrading: true,
			},
		},
	}

	result := engine.Evaluate(intake)

	// Should require algorithmic trading control
	hasAlgoControl := false
	for _, ctrl := range result.RequiredControls {
		if ctrl.ID == "CTRL-FIN-ALGO-TRADING" {
			hasAlgoControl = true
			break
		}
	}
	if !hasAlgoControl {
		t.Error("Should require algorithmic trading control")
	}

	// Should trigger highest escalation
	if result.EscalationLevel != "E3" {
		t.Errorf("Should trigger E3 escalation for algo trading, got %s", result.EscalationLevel)
	}
}

func TestFinancialPolicyEngine_Evaluate_CustomerDecisions(t *testing.T) {
	engine := createTestFinancialEngine(t)
	if engine == nil {
		return
	}

	intake := &UseCaseIntake{
		Domain: DomainBanking,
		FinancialContext: &FinancialContext{
			FinancialEntity: FinancialEntity{
				Type:      FinancialEntityCreditInstitution,
				Regulated: true,
			},
			AIApplication: FinancialAIApplication{
				AffectsCustomerDecisions: true,
			},
		},
	}

	result := engine.Evaluate(intake)

	// Should require explainability control
	hasExplainControl := false
	for _, ctrl := range result.RequiredControls {
		if ctrl.ID == "CTRL-FIN-AI-EXPLAINABILITY" {
			hasExplainControl = true
			break
		}
	}
	if !hasExplainControl {
		t.Error("Should require AI explainability control for customer decisions")
	}

	// Should trigger E2 escalation
	if result.EscalationLevel != "E2" {
		t.Errorf("Should trigger E2 escalation for customer decisions, got %s", result.EscalationLevel)
	}
}

func TestFinancialPolicyEngine_Evaluate_AMLKYC(t *testing.T) {
	engine := createTestFinancialEngine(t)
	if engine == nil {
		return
	}

	intake := &UseCaseIntake{
		Domain: DomainBanking,
		FinancialContext: &FinancialContext{
			FinancialEntity: FinancialEntity{
				Type:      FinancialEntityCreditInstitution,
				Regulated: true,
			},
			AIApplication: FinancialAIApplication{
				AMLKYC: true,
			},
		},
	}

	result := engine.Evaluate(intake)

	// Should require AML control
	hasAMLControl := false
	for _, ctrl := range result.RequiredControls {
		if ctrl.ID == "CTRL-FIN-AML-AI" {
			hasAMLControl = true
			break
		}
	}
	if !hasAMLControl {
		t.Error("Should require AML AI control for KYC/AML use cases")
	}
}

func TestFinancialPolicyEngine_Evaluate_ThirdCountryCritical(t *testing.T) {
	engine := createTestFinancialEngine(t)
	if engine == nil {
		return
	}

	intake := &UseCaseIntake{
		Domain: DomainBanking,
		FinancialContext: &FinancialContext{
			FinancialEntity: FinancialEntity{
				Type:      FinancialEntityCreditInstitution,
				Regulated: true,
			},
			ICTService: ICTService{
				IsCritical:       true,
				IsOutsourced:     true,
				ProviderLocation: ProviderLocationThirdCountry,
			},
		},
	}

	result := engine.Evaluate(intake)

	// Should be conditional at minimum
	if result.Feasibility == FeasibilityYES {
		t.Error("Should not allow critical ICT in third country without conditions")
	}

	// Should have elevated risk
	if result.RiskScore < 30 {
		t.Error("Should have elevated risk score for third country critical ICT")
	}
}

func TestFinancialPolicyEngine_Evaluate_ConcentrationRisk(t *testing.T) {
	engine := createTestFinancialEngine(t)
	if engine == nil {
		return
	}

	intake := &UseCaseIntake{
		Domain: DomainBanking,
		FinancialContext: &FinancialContext{
			FinancialEntity: FinancialEntity{
				Type:      FinancialEntityCreditInstitution,
				Regulated: true,
			},
			ICTService: ICTService{
				IsOutsourced:      true,
				ConcentrationRisk: true,
			},
		},
	}

	result := engine.Evaluate(intake)

	// Should trigger escalation for concentration risk
	if result.EscalationLevel == "" {
		t.Error("Should trigger escalation for concentration risk")
	}

	// Should add risk
	if result.RiskScore == 0 {
		t.Error("Should add risk for concentration risk")
	}
}

func TestFinancialPolicyEngine_Evaluate_InsuranceCompany(t *testing.T) {
	engine := createTestFinancialEngine(t)
	if engine == nil {
		return
	}

	intake := &UseCaseIntake{
		Domain: DomainInsurance,
		FinancialContext: &FinancialContext{
			FinancialEntity: FinancialEntity{
				Type:      FinancialEntityInsuranceCompany,
				Regulated: true,
			},
		},
	}

	result := engine.Evaluate(intake)

	if !result.IsApplicable {
		t.Error("Should be applicable for insurance domain")
	}
}

func TestFinancialPolicyEngine_GetAllControls(t *testing.T) {
	engine := createTestFinancialEngine(t)
	if engine == nil {
		return
	}

	controls := engine.GetAllControls()
	if len(controls) == 0 {
		t.Error("Should have controls defined")
	}

	// Check for key DORA controls
	keyControls := []string{
		"CTRL-DORA-ICT-RISK-FRAMEWORK",
		"CTRL-DORA-ICT-INCIDENT-MANAGEMENT",
		"CTRL-DORA-TPP-RISK-MANAGEMENT",
		"CTRL-MARISK-MODEL-VALIDATION",
		"CTRL-BAIT-SDLC",
	}

	for _, key := range keyControls {
		if _, ok := controls[key]; !ok {
			t.Errorf("Should have control %s", key)
		}
	}
}

func TestFinancialPolicyEngine_GetAllGaps(t *testing.T) {
	engine := createTestFinancialEngine(t)
	if engine == nil {
		return
	}

	gaps := engine.GetAllGaps()
	if len(gaps) == 0 {
		t.Error("Should have gaps defined")
	}

	// Check for key gaps
	keyGaps := []string{
		"GAP_DORA_NOT_IMPLEMENTED",
		"GAP_MARISK_MODEL_NOT_VALIDATED",
	}

	for _, key := range keyGaps {
		if _, ok := gaps[key]; !ok {
			t.Errorf("Should have gap %s", key)
		}
	}
}

func TestFinancialPolicyEngine_GetAllStopLines(t *testing.T) {
	engine := createTestFinancialEngine(t)
	if engine == nil {
		return
	}

	stopLines := engine.GetAllStopLines()
	if len(stopLines) == 0 {
		t.Error("Should have stop lines defined")
	}

	// Check for key stop lines
	keyStopLines := []string{
		"STOP_MARISK_UNVALIDATED_RISK_MODEL",
		"STOP_ALGO_TRADING_WITHOUT_APPROVAL",
	}

	for _, key := range keyStopLines {
		if _, ok := stopLines[key]; !ok {
			t.Errorf("Should have stop line %s", key)
		}
	}
}

func TestFinancialPolicyEngine_Determinism(t *testing.T) {
	engine := createTestFinancialEngine(t)
	if engine == nil {
		return
	}

	intake := &UseCaseIntake{
		Domain: DomainBanking,
		FinancialContext: &FinancialContext{
			FinancialEntity: FinancialEntity{
				Type:      FinancialEntityCreditInstitution,
				Regulated: true,
			},
			ICTService: ICTService{
				IsCritical:   true,
				IsOutsourced: true,
			},
			AIApplication: FinancialAIApplication{
				AffectsCustomerDecisions: true,
				RiskAssessment:           true,
				ModelValidationDone:      true,
			},
		},
	}

	// Run evaluation multiple times
	var lastResult *FinancialAssessmentResult
	for i := 0; i < 10; i++ {
		result := engine.Evaluate(intake)
		if lastResult != nil {
			if result.Feasibility != lastResult.Feasibility {
				t.Error("Feasibility should be deterministic")
			}
			if result.RiskScore != lastResult.RiskScore {
				t.Error("Risk score should be deterministic")
			}
			if len(result.TriggeredRules) != len(lastResult.TriggeredRules) {
				t.Error("Triggered rules should be deterministic")
			}
			if len(result.RequiredControls) != len(lastResult.RequiredControls) {
				t.Error("Required controls should be deterministic")
			}
		}
		lastResult = result
	}
}

// ============================================================================
// Helper Functions
// ============================================================================

func createTestFinancialEngine(t *testing.T) *FinancialPolicyEngine {
	engine, err := NewFinancialPolicyEngineFromPath("../../policies/financial_regulations_policy.yaml")
	if err != nil {
		t.Skipf("Skipping test - policy file not found: %v", err)
		return nil
	}
	return engine
}
