package ucca

import (
	"fmt"
	"strings"
)

// ============================================================================
// Rule Engine - Deterministic rule evaluation
// ============================================================================

// Rule represents a single evaluation rule
type Rule struct {
	Code        string
	Category    string
	Title       string
	TitleDE     string
	Description string
	DescriptionDE string
	Severity    Severity
	ScoreDelta  int      // Points added to risk score
	GDPRRef     string   // GDPR article reference
	Controls    []string // Required control IDs
	Patterns    []string // Recommended pattern IDs
	Condition   func(intake *UseCaseIntake) bool
	Rationale   func(intake *UseCaseIntake) string
}

// RuleEngine holds all rules and performs evaluation
type RuleEngine struct {
	rules []Rule
}

// NewRuleEngine creates a new rule engine with all rules
func NewRuleEngine() *RuleEngine {
	return &RuleEngine{
		rules: AllRules,
	}
}

// Evaluate runs all rules against the intake and returns the assessment result
func (e *RuleEngine) Evaluate(intake *UseCaseIntake) *AssessmentResult {
	result := &AssessmentResult{
		Feasibility:             FeasibilityYES,
		RiskLevel:               RiskLevelMINIMAL,
		Complexity:              ComplexityLOW,
		RiskScore:               0,
		TriggeredRules:          []TriggeredRule{},
		RequiredControls:        []RequiredControl{},
		RecommendedArchitecture: []PatternRecommendation{},
		ForbiddenPatterns:       []ForbiddenPattern{},
		ExampleMatches:          []ExampleMatch{},
		DSFARecommended:         false,
		Art22Risk:               false,
		TrainingAllowed:         TrainingYES,
	}

	// Track triggered severities
	hasBlock := false
	hasWarn := false
	controlMap := make(map[string]bool)
	patternMap := make(map[string]int) // pattern -> priority

	// Evaluate each rule
	for _, rule := range e.rules {
		if rule.Condition(intake) {
			// Add triggered rule
			triggered := TriggeredRule{
				Code:        rule.Code,
				Category:    rule.Category,
				Title:       rule.TitleDE,
				Description: rule.DescriptionDE,
				Severity:    rule.Severity,
				ScoreDelta:  rule.ScoreDelta,
				GDPRRef:     rule.GDPRRef,
				Rationale:   rule.Rationale(intake),
			}
			result.TriggeredRules = append(result.TriggeredRules, triggered)

			// Update risk score
			result.RiskScore += rule.ScoreDelta

			// Track severity
			switch rule.Severity {
			case SeverityBLOCK:
				hasBlock = true
			case SeverityWARN:
				hasWarn = true
			}

			// Collect required controls
			for _, controlID := range rule.Controls {
				if !controlMap[controlID] {
					controlMap[controlID] = true
					if ctrl := GetControlByID(controlID); ctrl != nil {
						result.RequiredControls = append(result.RequiredControls, *ctrl)
					}
				}
			}

			// Collect recommended patterns
			for i, patternID := range rule.Patterns {
				if _, exists := patternMap[patternID]; !exists {
					patternMap[patternID] = i + 1 // priority
				}
			}
		}
	}

	// Determine feasibility based on aggregation rules (R-090 to R-092)
	if hasBlock {
		result.Feasibility = FeasibilityNO
	} else if hasWarn {
		result.Feasibility = FeasibilityCONDITIONAL
	} else {
		result.Feasibility = FeasibilityYES
	}

	// Determine risk level based on score
	if result.RiskScore >= 80 {
		result.RiskLevel = RiskLevelUNACCEPTABLE
	} else if result.RiskScore >= 60 {
		result.RiskLevel = RiskLevelHIGH
	} else if result.RiskScore >= 40 {
		result.RiskLevel = RiskLevelMEDIUM
	} else if result.RiskScore >= 20 {
		result.RiskLevel = RiskLevelLOW
	} else {
		result.RiskLevel = RiskLevelMINIMAL
	}

	// Determine complexity
	if len(result.RequiredControls) >= 5 || result.RiskScore >= 50 {
		result.Complexity = ComplexityHIGH
	} else if len(result.RequiredControls) >= 3 || result.RiskScore >= 25 {
		result.Complexity = ComplexityMEDIUM
	} else {
		result.Complexity = ComplexityLOW
	}

	// Check DSFA recommendation
	if result.RiskLevel == RiskLevelHIGH || result.RiskLevel == RiskLevelUNACCEPTABLE ||
		intake.DataTypes.Article9Data || intake.DataTypes.BiometricData ||
		(intake.Purpose.Profiling && intake.DataTypes.PersonalData) {
		result.DSFARecommended = true
	}

	// Check Art. 22 risk
	if intake.Automation == AutomationFullyAutomated &&
		(intake.Outputs.LegalEffects || intake.Outputs.RankingsOrScores || intake.Purpose.EvaluationScoring) {
		result.Art22Risk = true
	}

	// Determine training allowed
	if intake.ModelUsage.Training && intake.DataTypes.PersonalData {
		result.TrainingAllowed = TrainingNO
	} else if intake.ModelUsage.Finetune && intake.DataTypes.PersonalData {
		result.TrainingAllowed = TrainingCONDITIONAL
	}

	// Add recommended architecture patterns
	for patternID, priority := range patternMap {
		if p := GetPatternByID(patternID); p != nil {
			result.RecommendedArchitecture = append(result.RecommendedArchitecture,
				PatternToRecommendation(*p, "Empfohlen basierend auf ausgelösten Regeln", priority))
		}
	}

	// Add applicable patterns not yet recommended
	applicable := GetApplicablePatterns(intake)
	for _, p := range applicable {
		found := false
		for _, rec := range result.RecommendedArchitecture {
			if rec.PatternID == p.ID {
				found = true
				break
			}
		}
		if !found {
			result.RecommendedArchitecture = append(result.RecommendedArchitecture,
				PatternToRecommendation(p, "Anwendbar für Ihren Use Case", len(result.RecommendedArchitecture)+1))
		}
	}

	// Add forbidden patterns
	result.ForbiddenPatterns = GetForbiddenPatterns(intake)

	// Add matching examples
	result.ExampleMatches = MatchExamples(intake)

	// Generate summary
	result.Summary = generateSummary(result, intake)
	result.Recommendation = generateRecommendation(result, intake)
	if result.Feasibility == FeasibilityNO {
		result.AlternativeApproach = generateAlternative(result, intake)
	}

	return result
}

// generateSummary creates a human-readable summary
func generateSummary(result *AssessmentResult, intake *UseCaseIntake) string {
	var parts []string

	switch result.Feasibility {
	case FeasibilityYES:
		parts = append(parts, "Der Use Case ist aus DSGVO-Sicht grundsätzlich umsetzbar.")
	case FeasibilityCONDITIONAL:
		parts = append(parts, "Der Use Case ist unter Auflagen umsetzbar.")
	case FeasibilityNO:
		parts = append(parts, "Der Use Case ist in der aktuellen Form nicht DSGVO-konform umsetzbar.")
	}

	if len(result.TriggeredRules) > 0 {
		blockCount := 0
		warnCount := 0
		for _, r := range result.TriggeredRules {
			if r.Severity == SeverityBLOCK {
				blockCount++
			} else if r.Severity == SeverityWARN {
				warnCount++
			}
		}
		if blockCount > 0 {
			parts = append(parts, fmt.Sprintf("%d kritische Regelverletzung(en) identifiziert.", blockCount))
		}
		if warnCount > 0 {
			parts = append(parts, fmt.Sprintf("%d Warnungen erfordern Aufmerksamkeit.", warnCount))
		}
	}

	if result.DSFARecommended {
		parts = append(parts, "Eine Datenschutz-Folgenabschätzung (DSFA) wird empfohlen.")
	}

	return strings.Join(parts, " ")
}

// generateRecommendation creates actionable recommendations
func generateRecommendation(result *AssessmentResult, intake *UseCaseIntake) string {
	if result.Feasibility == FeasibilityYES {
		return "Fahren Sie mit der Implementierung fort. Beachten Sie die empfohlenen Architektur-Patterns für optimale DSGVO-Konformität."
	}

	if result.Feasibility == FeasibilityCONDITIONAL {
		if len(result.RequiredControls) > 0 {
			return fmt.Sprintf("Implementieren Sie die %d erforderlichen Kontrollen vor dem Go-Live. Dokumentieren Sie alle Maßnahmen für den Nachweis der Rechenschaftspflicht (Art. 5 DSGVO).", len(result.RequiredControls))
		}
		return "Prüfen Sie die ausgelösten Warnungen und implementieren Sie entsprechende Schutzmaßnahmen."
	}

	// FeasibilityNO
	return "Der Use Case erfordert grundlegende Änderungen. Prüfen Sie die Alternative-Ansatz-Empfehlung."
}

// generateAlternative creates alternative approach suggestions
func generateAlternative(result *AssessmentResult, intake *UseCaseIntake) string {
	var suggestions []string

	// Check specific blocking reasons
	if intake.ModelUsage.Training && intake.DataTypes.PersonalData {
		suggestions = append(suggestions, "Nutzen Sie nur RAG statt Training mit personenbezogenen Daten")
	}

	if intake.Automation == AutomationFullyAutomated && intake.Outputs.LegalEffects {
		suggestions = append(suggestions, "Implementieren Sie Human-in-the-Loop für Entscheidungen mit rechtlichen Auswirkungen")
	}

	if intake.DataTypes.MinorData && intake.Purpose.EvaluationScoring {
		suggestions = append(suggestions, "Verzichten Sie auf automatisches Scoring von Minderjährigen - nutzen Sie KI nur zur Unterstützung menschlicher Entscheidungsträger")
	}

	if intake.Hosting.Region == "third_country" && intake.DataTypes.PersonalData {
		suggestions = append(suggestions, "Hosten Sie innerhalb der EU oder implementieren Sie Standardvertragsklauseln (SCCs)")
	}

	if len(suggestions) == 0 {
		return "Überarbeiten Sie den Use Case unter Berücksichtigung der ausgelösten Regeln."
	}

	return strings.Join(suggestions, ". ") + "."
}

// GetRules returns all rules
func (e *RuleEngine) GetRules() []Rule {
	return e.rules
}
