package maximizer

// DimensionConfig is the normalized representation of an AI use case
// as a point in a 13-dimensional regulatory constraint space.
// Each dimension maps to regulatory obligations from DSGVO, AI Act, etc.
type DimensionConfig struct {
	AutomationLevel      AutomationLevel     `json:"automation_level"`
	DecisionBinding      DecisionBinding     `json:"decision_binding"`
	DecisionImpact       DecisionImpact      `json:"decision_impact"`
	Domain               DomainCategory      `json:"domain"`
	DataType             DataTypeSensitivity `json:"data_type"`
	HumanInLoop          HumanInLoopLevel    `json:"human_in_loop"`
	Explainability       ExplainabilityLevel `json:"explainability"`
	RiskClassification   RiskClass           `json:"risk_classification"`
	LegalBasis           LegalBasisType      `json:"legal_basis"`
	TransparencyRequired bool                `json:"transparency_required"`
	LoggingRequired      bool                `json:"logging_required"`
	ModelType            ModelType           `json:"model_type"`
	DeploymentScope      DeploymentScope     `json:"deployment_scope"`
}

// --- Dimension Enums ---

type AutomationLevel string

const (
	AutoNone      AutomationLevel = "none"
	AutoAssistive AutomationLevel = "assistive"
	AutoPartial   AutomationLevel = "partial"
	AutoFull      AutomationLevel = "full"
)

type DecisionBinding string

const (
	BindingNonBinding    DecisionBinding = "non_binding"
	BindingHumanReview   DecisionBinding = "human_review_required"
	BindingFullyBinding  DecisionBinding = "fully_binding"
)

type DecisionImpact string

const (
	ImpactLow    DecisionImpact = "low"
	ImpactMedium DecisionImpact = "medium"
	ImpactHigh   DecisionImpact = "high"
)

type DomainCategory string

const (
	DomainHR        DomainCategory = "hr"
	DomainFinance   DomainCategory = "finance"
	DomainEducation DomainCategory = "education"
	DomainHealth    DomainCategory = "health"
	DomainMarketing DomainCategory = "marketing"
	DomainGeneral   DomainCategory = "general"
)

type DataTypeSensitivity string

const (
	DataNonPersonal DataTypeSensitivity = "non_personal"
	DataPersonal    DataTypeSensitivity = "personal"
	DataSensitive   DataTypeSensitivity = "sensitive"
	DataBiometric   DataTypeSensitivity = "biometric"
)

type HumanInLoopLevel string

const (
	HILNone     HumanInLoopLevel = "none"
	HILOptional HumanInLoopLevel = "optional"
	HILRequired HumanInLoopLevel = "required"
)

type ExplainabilityLevel string

const (
	ExplainNone  ExplainabilityLevel = "none"
	ExplainBasic ExplainabilityLevel = "basic"
	ExplainHigh  ExplainabilityLevel = "high"
)

type RiskClass string

const (
	RiskMinimal    RiskClass = "minimal"
	RiskLimited    RiskClass = "limited"
	RiskHigh       RiskClass = "high"
	RiskProhibited RiskClass = "prohibited"
)

type LegalBasisType string

const (
	LegalConsent             LegalBasisType = "consent"
	LegalContract            LegalBasisType = "contract"
	LegalLegalObligation     LegalBasisType = "legal_obligation"
	LegalLegitimateInterest  LegalBasisType = "legitimate_interest"
	LegalPublicInterest      LegalBasisType = "public_interest"
)

type ModelType string

const (
	ModelRuleBased   ModelType = "rule_based"
	ModelStatistical ModelType = "statistical"
	ModelBlackboxLLM ModelType = "blackbox_llm"
)

type DeploymentScope string

const (
	ScopeInternal DeploymentScope = "internal"
	ScopeExternal DeploymentScope = "external"
	ScopePublic   DeploymentScope = "public"
)

// --- Ordinal Orderings (higher = more regulatory risk) ---

var automationOrder = map[AutomationLevel]int{
	AutoNone: 0, AutoAssistive: 1, AutoPartial: 2, AutoFull: 3,
}

var bindingOrder = map[DecisionBinding]int{
	BindingNonBinding: 0, BindingHumanReview: 1, BindingFullyBinding: 2,
}

var impactOrder = map[DecisionImpact]int{
	ImpactLow: 0, ImpactMedium: 1, ImpactHigh: 2,
}

var dataTypeOrder = map[DataTypeSensitivity]int{
	DataNonPersonal: 0, DataPersonal: 1, DataSensitive: 2, DataBiometric: 3,
}

var hilOrder = map[HumanInLoopLevel]int{
	HILRequired: 0, HILOptional: 1, HILNone: 2,
}

var explainOrder = map[ExplainabilityLevel]int{
	ExplainHigh: 0, ExplainBasic: 1, ExplainNone: 2,
}

var riskOrder = map[RiskClass]int{
	RiskMinimal: 0, RiskLimited: 1, RiskHigh: 2, RiskProhibited: 3,
}

var modelTypeOrder = map[ModelType]int{
	ModelRuleBased: 0, ModelStatistical: 1, ModelBlackboxLLM: 2,
}

var scopeOrder = map[DeploymentScope]int{
	ScopeInternal: 0, ScopeExternal: 1, ScopePublic: 2,
}

// AllValues returns the ordered list of allowed values for each dimension.
var AllValues = map[string][]string{
	"automation_level":      {"none", "assistive", "partial", "full"},
	"decision_binding":      {"non_binding", "human_review_required", "fully_binding"},
	"decision_impact":       {"low", "medium", "high"},
	"domain":                {"hr", "finance", "education", "health", "marketing", "general"},
	"data_type":             {"non_personal", "personal", "sensitive", "biometric"},
	"human_in_loop":         {"required", "optional", "none"},
	"explainability":        {"high", "basic", "none"},
	"risk_classification":   {"minimal", "limited", "high", "prohibited"},
	"legal_basis":           {"consent", "contract", "legal_obligation", "legitimate_interest", "public_interest"},
	"transparency_required": {"true", "false"},
	"logging_required":      {"true", "false"},
	"model_type":            {"rule_based", "statistical", "blackbox_llm"},
	"deployment_scope":      {"internal", "external", "public"},
}

// DimensionDelta represents a single change between two configs.
type DimensionDelta struct {
	Dimension string `json:"dimension"`
	From      string `json:"from"`
	To        string `json:"to"`
	Impact    string `json:"impact"` // human-readable impact description
}

// GetValue returns the string value of a dimension by name.
func (d *DimensionConfig) GetValue(dimension string) string {
	switch dimension {
	case "automation_level":
		return string(d.AutomationLevel)
	case "decision_binding":
		return string(d.DecisionBinding)
	case "decision_impact":
		return string(d.DecisionImpact)
	case "domain":
		return string(d.Domain)
	case "data_type":
		return string(d.DataType)
	case "human_in_loop":
		return string(d.HumanInLoop)
	case "explainability":
		return string(d.Explainability)
	case "risk_classification":
		return string(d.RiskClassification)
	case "legal_basis":
		return string(d.LegalBasis)
	case "transparency_required":
		if d.TransparencyRequired {
			return "true"
		}
		return "false"
	case "logging_required":
		if d.LoggingRequired {
			return "true"
		}
		return "false"
	case "model_type":
		return string(d.ModelType)
	case "deployment_scope":
		return string(d.DeploymentScope)
	default:
		return ""
	}
}

// SetValue sets a dimension value by name. Returns false if the dimension is unknown.
func (d *DimensionConfig) SetValue(dimension, value string) bool {
	switch dimension {
	case "automation_level":
		d.AutomationLevel = AutomationLevel(value)
	case "decision_binding":
		d.DecisionBinding = DecisionBinding(value)
	case "decision_impact":
		d.DecisionImpact = DecisionImpact(value)
	case "domain":
		d.Domain = DomainCategory(value)
	case "data_type":
		d.DataType = DataTypeSensitivity(value)
	case "human_in_loop":
		d.HumanInLoop = HumanInLoopLevel(value)
	case "explainability":
		d.Explainability = ExplainabilityLevel(value)
	case "risk_classification":
		d.RiskClassification = RiskClass(value)
	case "legal_basis":
		d.LegalBasis = LegalBasisType(value)
	case "transparency_required":
		d.TransparencyRequired = value == "true"
	case "logging_required":
		d.LoggingRequired = value == "true"
	case "model_type":
		d.ModelType = ModelType(value)
	case "deployment_scope":
		d.DeploymentScope = DeploymentScope(value)
	default:
		return false
	}
	return true
}

// Diff computes the changes between two configs.
func (d *DimensionConfig) Diff(other *DimensionConfig) []DimensionDelta {
	dimensions := []string{
		"automation_level", "decision_binding", "decision_impact", "domain",
		"data_type", "human_in_loop", "explainability", "risk_classification",
		"legal_basis", "transparency_required", "logging_required",
		"model_type", "deployment_scope",
	}
	var deltas []DimensionDelta
	for _, dim := range dimensions {
		from := d.GetValue(dim)
		to := other.GetValue(dim)
		if from != to {
			deltas = append(deltas, DimensionDelta{
				Dimension: dim,
				From:      from,
				To:        to,
				Impact:    describeDeltaImpact(dim, from, to),
			})
		}
	}
	return deltas
}

// Clone returns a deep copy of the config.
func (d *DimensionConfig) Clone() DimensionConfig {
	return *d
}

func describeDeltaImpact(dimension, from, to string) string {
	switch dimension {
	case "automation_level":
		return "Automatisierungsgrad: " + from + " → " + to
	case "decision_binding":
		return "Entscheidungsbindung: " + from + " → " + to
	case "human_in_loop":
		return "Menschliche Kontrolle: " + from + " → " + to
	case "explainability":
		return "Erklaerbarkeit: " + from + " → " + to
	case "data_type":
		return "Datensensitivitaet: " + from + " → " + to
	case "transparency_required":
		return "Transparenzpflicht: " + from + " → " + to
	case "logging_required":
		return "Protokollierungspflicht: " + from + " → " + to
	default:
		return dimension + ": " + from + " → " + to
	}
}
