package ucca

import (
	"encoding/json"
	"fmt"
	"strings"
)

// ObligationConditionEngine evaluates condition trees against UnifiedFacts
type ObligationConditionEngine struct {
	fieldMap map[string]func(*UnifiedFacts) interface{}
}

// NewObligationConditionEngine creates a new condition engine with all field mappings
func NewObligationConditionEngine() *ObligationConditionEngine {
	e := &ObligationConditionEngine{}
	e.fieldMap = e.buildFieldMap()
	return e
}

// Evaluate evaluates a condition node against facts
func (e *ObligationConditionEngine) Evaluate(node *ConditionNode, facts *UnifiedFacts) bool {
	if node == nil {
		return true // nil condition = always applies
	}

	// Composite: all_of (AND)
	if len(node.AllOf) > 0 {
		for _, child := range node.AllOf {
			if !e.Evaluate(&child, facts) {
				return false
			}
		}
		return true
	}

	// Composite: any_of (OR)
	if len(node.AnyOf) > 0 {
		for _, child := range node.AnyOf {
			if e.Evaluate(&child, facts) {
				return true
			}
		}
		return false
	}

	// Leaf node: field + operator + value
	if node.Field != "" {
		return e.evaluateLeaf(node, facts)
	}

	return true
}

func (e *ObligationConditionEngine) evaluateLeaf(node *ConditionNode, facts *UnifiedFacts) bool {
	getter, ok := e.fieldMap[node.Field]
	if !ok {
		fmt.Printf("Warning: unknown field in condition: %s\n", node.Field)
		return false
	}

	actual := getter(facts)
	return e.compare(actual, node.Operator, node.Value)
}

func (e *ObligationConditionEngine) compare(actual interface{}, operator string, expected interface{}) bool {
	switch strings.ToUpper(operator) {
	case "EQUALS":
		return e.equals(actual, expected)
	case "NOT_EQUALS":
		return !e.equals(actual, expected)
	case "GREATER_THAN":
		return e.toFloat(actual) > e.toFloat(expected)
	case "LESS_THAN":
		return e.toFloat(actual) < e.toFloat(expected)
	case "GREATER_OR_EQUAL":
		return e.toFloat(actual) >= e.toFloat(expected)
	case "LESS_OR_EQUAL":
		return e.toFloat(actual) <= e.toFloat(expected)
	case "IN":
		return e.inSlice(actual, expected)
	case "NOT_IN":
		return !e.inSlice(actual, expected)
	case "CONTAINS":
		return e.contains(actual, expected)
	case "EXISTS":
		return actual != nil && actual != "" && actual != false && actual != 0
	default:
		fmt.Printf("Warning: unknown operator: %s\n", operator)
		return false
	}
}

func (e *ObligationConditionEngine) equals(a, b interface{}) bool {
	// Handle bool comparisons
	aBool, aIsBool := e.toBool(a)
	bBool, bIsBool := e.toBool(b)
	if aIsBool && bIsBool {
		return aBool == bBool
	}

	// Handle numeric comparisons
	aFloat, aIsNum := e.toFloatOk(a)
	bFloat, bIsNum := e.toFloatOk(b)
	if aIsNum && bIsNum {
		return aFloat == bFloat
	}

	// String comparison
	return fmt.Sprintf("%v", a) == fmt.Sprintf("%v", b)
}

func (e *ObligationConditionEngine) toBool(v interface{}) (bool, bool) {
	switch b := v.(type) {
	case bool:
		return b, true
	}
	return false, false
}

func (e *ObligationConditionEngine) toFloat(v interface{}) float64 {
	f, _ := e.toFloatOk(v)
	return f
}

func (e *ObligationConditionEngine) toFloatOk(v interface{}) (float64, bool) {
	switch n := v.(type) {
	case int:
		return float64(n), true
	case int64:
		return float64(n), true
	case float64:
		return n, true
	case float32:
		return float64(n), true
	case json.Number:
		f, err := n.Float64()
		return f, err == nil
	}
	return 0, false
}

func (e *ObligationConditionEngine) inSlice(actual, expected interface{}) bool {
	actualStr := fmt.Sprintf("%v", actual)
	switch v := expected.(type) {
	case []interface{}:
		for _, item := range v {
			if fmt.Sprintf("%v", item) == actualStr {
				return true
			}
		}
	case []string:
		for _, item := range v {
			if item == actualStr {
				return true
			}
		}
	}
	return false
}

func (e *ObligationConditionEngine) contains(actual, expected interface{}) bool {
	// Check if actual (slice) contains expected
	switch v := actual.(type) {
	case []string:
		exp := fmt.Sprintf("%v", expected)
		for _, item := range v {
			if item == exp {
				return true
			}
		}
	case string:
		return strings.Contains(v, fmt.Sprintf("%v", expected))
	}
	return false
}

// buildFieldMap creates the mapping from JSON field paths to Go struct accessors
func (e *ObligationConditionEngine) buildFieldMap() map[string]func(*UnifiedFacts) interface{} {
	return map[string]func(*UnifiedFacts) interface{}{
		// Organization
		"organization.employee_count":      func(f *UnifiedFacts) interface{} { return f.Organization.EmployeeCount },
		"organization.annual_revenue":      func(f *UnifiedFacts) interface{} { return f.Organization.AnnualRevenue },
		"organization.country":             func(f *UnifiedFacts) interface{} { return f.Organization.Country },
		"organization.eu_member":           func(f *UnifiedFacts) interface{} { return f.Organization.EUMember },
		"organization.is_public_authority": func(f *UnifiedFacts) interface{} { return f.Organization.IsPublicAuthority },
		"organization.legal_form":          func(f *UnifiedFacts) interface{} { return f.Organization.LegalForm },
		"organization.size_category":       func(f *UnifiedFacts) interface{} { return f.Organization.CalculateSizeCategory() },
		"organization.is_part_of_group":    func(f *UnifiedFacts) interface{} { return f.Organization.IsPartOfGroup },

		// Data Protection
		"data_protection.processes_personal_data":       func(f *UnifiedFacts) interface{} { return f.DataProtection.ProcessesPersonalData },
		"data_protection.is_controller":                 func(f *UnifiedFacts) interface{} { return f.DataProtection.IsController },
		"data_protection.is_processor":                  func(f *UnifiedFacts) interface{} { return f.DataProtection.IsProcessor },
		"data_protection.processes_special_categories":  func(f *UnifiedFacts) interface{} { return f.DataProtection.ProcessesSpecialCategories },
		"data_protection.processes_children_data":       func(f *UnifiedFacts) interface{} { return f.DataProtection.ProcessesMinorData },
		"data_protection.processes_minor_data":          func(f *UnifiedFacts) interface{} { return f.DataProtection.ProcessesMinorData },
		"data_protection.processes_criminal_data":       func(f *UnifiedFacts) interface{} { return f.DataProtection.ProcessesCriminalData },
		"data_protection.large_scale":                   func(f *UnifiedFacts) interface{} { return f.DataProtection.LargeScaleProcessing },
		"data_protection.large_scale_processing":        func(f *UnifiedFacts) interface{} { return f.DataProtection.LargeScaleProcessing },
		"data_protection.systematic_monitoring":         func(f *UnifiedFacts) interface{} { return f.DataProtection.SystematicMonitoring },
		"data_protection.uses_automated_decisions":      func(f *UnifiedFacts) interface{} { return f.DataProtection.AutomatedDecisionMaking },
		"data_protection.automated_decision_making":     func(f *UnifiedFacts) interface{} { return f.DataProtection.AutomatedDecisionMaking },
		"data_protection.cross_border_transfer":         func(f *UnifiedFacts) interface{} { return f.DataProtection.TransfersToThirdCountries },
		"data_protection.transfers_to_third_countries":  func(f *UnifiedFacts) interface{} { return f.DataProtection.TransfersToThirdCountries },
		"data_protection.cross_border_processing":       func(f *UnifiedFacts) interface{} { return f.DataProtection.CrossBorderProcessing },
		"data_protection.uses_processors":               func(f *UnifiedFacts) interface{} { return f.DataProtection.UsesExternalProcessor },
		"data_protection.uses_external_processor":       func(f *UnifiedFacts) interface{} { return f.DataProtection.UsesExternalProcessor },
		"data_protection.high_risk":                     func(f *UnifiedFacts) interface{} { return f.DataProtection.LargeScaleProcessing || f.DataProtection.SystematicMonitoring || f.DataProtection.ProcessesSpecialCategories },
		"data_protection.uses_profiling":                func(f *UnifiedFacts) interface{} { return f.DataProtection.Profiling },
		"data_protection.profiling":                     func(f *UnifiedFacts) interface{} { return f.DataProtection.Profiling },
		"data_protection.requires_dsb":                  func(f *UnifiedFacts) interface{} { return f.DataProtection.RequiresDSBByLaw },
		"data_protection.needs_dpo":                     func(f *UnifiedFacts) interface{} { return f.DataProtection.RequiresDSBByLaw },
		"data_protection.has_appointed_dsb":             func(f *UnifiedFacts) interface{} { return f.DataProtection.HasAppointedDSB },
		"data_protection.data_subject_count":            func(f *UnifiedFacts) interface{} { return f.DataProtection.DataSubjectCount },
		"data_protection.sccs_in_place":                 func(f *UnifiedFacts) interface{} { return f.DataProtection.SCCsInPlace },
		"data_protection.binding_corporate_rules":       func(f *UnifiedFacts) interface{} { return f.DataProtection.BindingCorporateRules },
		"data_protection.special_categories":            func(f *UnifiedFacts) interface{} { return f.DataProtection.SpecialCategories },
		"data_protection.processes_employee_data":       func(f *UnifiedFacts) interface{} { return f.DataProtection.ProcessesEmployeeData },
		"data_protection.processes_health_data":         func(f *UnifiedFacts) interface{} { return f.DataProtection.ProcessesHealthData },
		"data_protection.processes_financial_data":      func(f *UnifiedFacts) interface{} { return f.DataProtection.ProcessesFinancialData },
		"data_protection.uses_cookies":                  func(f *UnifiedFacts) interface{} { return f.DataProtection.UsesCookies },
		"data_protection.uses_tracking":                 func(f *UnifiedFacts) interface{} { return f.DataProtection.UsesTracking },
		"data_protection.uses_video_surveillance":       func(f *UnifiedFacts) interface{} { return f.DataProtection.UsesVideoSurveillance },
		"data_protection.processes_biometric_data":      func(f *UnifiedFacts) interface{} { return f.DataProtection.ProcessesBiometricData },
		"data_protection.operates_platform":             func(f *UnifiedFacts) interface{} { return f.DataProtection.OperatesPlatform },
		"data_protection.platform_user_count":           func(f *UnifiedFacts) interface{} { return f.DataProtection.PlatformUserCount },

		// AI Usage
		"ai_usage.uses_ai":                     func(f *UnifiedFacts) interface{} { return f.AIUsage.UsesAI },
		"ai_usage.is_ai_provider":              func(f *UnifiedFacts) interface{} { return f.AIUsage.IsAIProvider },
		"ai_usage.is_ai_deployer":              func(f *UnifiedFacts) interface{} { return f.AIUsage.IsAIDeployer },
		"ai_usage.is_ai_distributor":           func(f *UnifiedFacts) interface{} { return f.AIUsage.IsAIDistributor },
		"ai_usage.is_ai_importer":              func(f *UnifiedFacts) interface{} { return f.AIUsage.IsAIImporter },
		"ai_usage.high_risk_ai":                func(f *UnifiedFacts) interface{} { return f.AIUsage.HasHighRiskAI },
		"ai_usage.has_high_risk_ai":            func(f *UnifiedFacts) interface{} { return f.AIUsage.HasHighRiskAI },
		"ai_usage.limited_risk_ai":             func(f *UnifiedFacts) interface{} { return f.AIUsage.HasLimitedRiskAI },
		"ai_usage.has_limited_risk_ai":         func(f *UnifiedFacts) interface{} { return f.AIUsage.HasLimitedRiskAI },
		"ai_usage.minimal_risk_ai":             func(f *UnifiedFacts) interface{} { return f.AIUsage.HasMinimalRiskAI },
		"ai_usage.is_gpai_provider":            func(f *UnifiedFacts) interface{} { return f.AIUsage.UsesGPAI },
		"ai_usage.gpai_systemic_risk":          func(f *UnifiedFacts) interface{} { return f.AIUsage.GPAIWithSystemicRisk },
		"ai_usage.uses_biometric_ai":           func(f *UnifiedFacts) interface{} { return f.AIUsage.BiometricIdentification },
		"ai_usage.biometric_identification":    func(f *UnifiedFacts) interface{} { return f.AIUsage.BiometricIdentification },
		"ai_usage.uses_emotion_recognition":    func(f *UnifiedFacts) interface{} { return f.AIUsage.EmotionRecognition },
		"ai_usage.ai_in_education":             func(f *UnifiedFacts) interface{} { return f.AIUsage.EducationAccess },
		"ai_usage.ai_in_employment":            func(f *UnifiedFacts) interface{} { return f.AIUsage.EmploymentDecisions },
		"ai_usage.ai_in_critical_infrastructure": func(f *UnifiedFacts) interface{} { return f.AIUsage.CriticalInfrastructure },
		"ai_usage.ai_in_law_enforcement":       func(f *UnifiedFacts) interface{} { return f.AIUsage.LawEnforcement },
		"ai_usage.ai_in_justice":               func(f *UnifiedFacts) interface{} { return f.AIUsage.JusticeAdministration },
		"ai_usage.uses_generative_ai":          func(f *UnifiedFacts) interface{} { return f.AIUsage.AIInteractsWithNaturalPersons },
		"ai_usage.uses_deepfakes":              func(f *UnifiedFacts) interface{} { return f.AIUsage.GeneratesDeepfakes },
		"ai_usage.ai_makes_decisions":          func(f *UnifiedFacts) interface{} { return f.DataProtection.AutomatedDecisionMaking },
		"ai_usage.ai_interacts_with_persons":   func(f *UnifiedFacts) interface{} { return f.AIUsage.AIInteractsWithNaturalPersons },

		// Sector
		"sector.primary_sector":           func(f *UnifiedFacts) interface{} { return f.Sector.PrimarySector },
		"sector.is_kritis":                func(f *UnifiedFacts) interface{} { return f.Sector.IsKRITIS },
		"sector.nis2_applicable":          func(f *UnifiedFacts) interface{} { return f.Sector.PrimarySector != "" && f.Sector.PrimarySector != "other" },
		"sector.nis2_classification":      func(f *UnifiedFacts) interface{} { return f.Sector.NIS2Classification },
		"sector.is_annex_i":               func(f *UnifiedFacts) interface{} { return f.Sector.IsAnnexI },
		"sector.is_annex_ii":              func(f *UnifiedFacts) interface{} { return f.Sector.IsAnnexII },
		"sector.provides_dns":             func(f *UnifiedFacts) interface{} { return containsString(f.Sector.SpecialServices, "dns") },
		"sector.provides_cloud":           func(f *UnifiedFacts) interface{} { return containsString(f.Sector.SpecialServices, "cloud") },
		"sector.provides_cdn":             func(f *UnifiedFacts) interface{} { return containsString(f.Sector.SpecialServices, "cdn") },
		"sector.provides_data_center":     func(f *UnifiedFacts) interface{} { return containsString(f.Sector.SpecialServices, "datacenter") },
		"sector.provides_managed_services": func(f *UnifiedFacts) interface{} { return containsString(f.Sector.SpecialServices, "msp") || containsString(f.Sector.SpecialServices, "mssp") },
		"sector.is_financial_institution": func(f *UnifiedFacts) interface{} { return f.Sector.IsFinancialInstitution },
		"sector.is_healthcare_provider":   func(f *UnifiedFacts) interface{} { return f.Sector.IsHealthcareProvider },

		// IT Security
		"it_security.has_isms":                func(f *UnifiedFacts) interface{} { return f.ITSecurity.HasISMS },
		"it_security.iso27001_certified":      func(f *UnifiedFacts) interface{} { return f.ITSecurity.ISO27001Certified },
		"it_security.has_incident_process":    func(f *UnifiedFacts) interface{} { return f.ITSecurity.HasIncidentProcess },
		"it_security.has_mfa":                 func(f *UnifiedFacts) interface{} { return f.ITSecurity.HasMFA },
		"it_security.has_encryption":          func(f *UnifiedFacts) interface{} { return f.ITSecurity.HasEncryption },
		"it_security.has_backup":              func(f *UnifiedFacts) interface{} { return f.ITSecurity.HasBackup },
		"it_security.has_bcm":                 func(f *UnifiedFacts) interface{} { return f.ITSecurity.HasBCM },
		"it_security.has_siem":                func(f *UnifiedFacts) interface{} { return f.ITSecurity.HasSecurityMonitoring },
		"it_security.has_network_segmentation": func(f *UnifiedFacts) interface{} { return f.ITSecurity.HasNetworkSegmentation },
		"it_security.has_vulnerability_mgmt":  func(f *UnifiedFacts) interface{} { return f.ITSecurity.HasVulnerabilityMgmt },

		// Financial
		"financial.dora_applies":       func(f *UnifiedFacts) interface{} { return f.Financial.DORAApplies },
		"financial.is_regulated":       func(f *UnifiedFacts) interface{} { return f.Financial.IsRegulated },
		"financial.has_critical_ict":   func(f *UnifiedFacts) interface{} { return f.Financial.HasCriticalICT },
		"financial.ict_outsourced":     func(f *UnifiedFacts) interface{} { return f.Financial.ICTOutsourced },
		"financial.concentration_risk": func(f *UnifiedFacts) interface{} { return f.Financial.ConcentrationRisk },

		// Supply Chain
		"supply_chain.has_risk_management": func(f *UnifiedFacts) interface{} { return f.SupplyChain.HasSupplyChainRiskMgmt },
		"supply_chain.supplier_count":      func(f *UnifiedFacts) interface{} { return f.SupplyChain.SupplierCount },

		// Personnel
		"personnel.has_ciso":              func(f *UnifiedFacts) interface{} { return f.Personnel.HasCISO },
		"personnel.has_dpo":               func(f *UnifiedFacts) interface{} { return f.Personnel.HasDPO },
		"personnel.has_ai_competence":     func(f *UnifiedFacts) interface{} { return f.Personnel.HasAICompetence },
		"personnel.has_ai_governance":     func(f *UnifiedFacts) interface{} { return f.Personnel.HasAIGovernance },
		"personnel.has_compliance_officer": func(f *UnifiedFacts) interface{} { return f.Personnel.HasComplianceOfficer },
	}
}
