package persona

import "fmt"

// ConsistencyIssue represents an internally inconsistent attribute combination.
// Unlike plausibility violations (which compare against ethnicity expectations),
// consistency issues catch impossible or contradictory combinations regardless
// of ethnicity.
type ConsistencyIssue struct {
	Field1      string      // First field involved (e.g., "identity.age")
	Value1      interface{} // Value of first field
	Field2      string      // Second field involved (e.g., "face.hair_color")
	Value2      interface{} // Value of second field
	Severity    string      // "warning" or "error"
	Description string      // Human-readable explanation
}

// ConsistencyResult contains cross-attribute validation results.
type ConsistencyResult struct {
	Valid  bool               // True if no errors (warnings are OK)
	Issues []ConsistencyIssue // All issues found
}

// ValidateConsistency checks for internally inconsistent attribute combinations
// that are implausible regardless of ethnicity.
//
// Examples of inconsistencies:
//   - Young age (< 25) with gray hair (without dye indication)
//   - Mature skin texture with young age
//   - Height category mismatched with height CM
//   - Muscle definition that contradicts build type
func ValidateConsistency(dna *DNA) *ConsistencyResult {
	if dna == nil {
		return &ConsistencyResult{Valid: true}
	}

	result := &ConsistencyResult{
		Valid:  true,
		Issues: []ConsistencyIssue{},
	}

	// Age vs Hair Color consistency
	if dna.Identity.Age > 0 && dna.Face.HairColor != "" {
		if dna.Identity.Age < 30 && dna.Face.HairColor == HairColorGray {
			result.Issues = append(result.Issues, ConsistencyIssue{
				Field1:      "identity.age",
				Value1:      dna.Identity.Age,
				Field2:      "face.hair_color",
				Value2:      dna.Face.HairColor,
				Severity:    "warning",
				Description: fmt.Sprintf("Gray hair at age %d is unusual without premature graying or dye", dna.Identity.Age),
			})
		}
	}

	// Age vs Skin Texture consistency
	if dna.Identity.Age > 0 && dna.Face.SkinTexture != "" {
		if dna.Identity.Age < 35 && dna.Face.SkinTexture == SkinTextureMature {
			result.Issues = append(result.Issues, ConsistencyIssue{
				Field1:      "identity.age",
				Value1:      dna.Identity.Age,
				Field2:      "face.skin_texture",
				Value2:      dna.Face.SkinTexture,
				Severity:    "warning",
				Description: fmt.Sprintf("Mature skin texture at age %d is inconsistent", dna.Identity.Age),
			})
		}
		if dna.Identity.Age > 55 && dna.Face.SkinTexture == SkinTextureSmooth {
			result.Issues = append(result.Issues, ConsistencyIssue{
				Field1:      "identity.age",
				Value1:      dna.Identity.Age,
				Field2:      "face.skin_texture",
				Value2:      dna.Face.SkinTexture,
				Severity:    "warning",
				Description: fmt.Sprintf("Smooth skin texture at age %d is unusual", dna.Identity.Age),
			})
		}
	}

	// Height Category vs Height CM consistency
	if dna.Body.HeightCM > 0 && dna.Body.Height != "" {
		if issue := validateHeightCMConsistency(dna.Body.HeightCM, dna.Body.Height); issue != nil {
			result.Issues = append(result.Issues, *issue)
			if issue.Severity == "error" {
				result.Valid = false
			}
		}
	}

	// Muscle Definition vs Build consistency
	if dna.Body.MuscleDefinition != "" && dna.Body.Build != "" {
		// High muscle definition with slender build is contradictory
		if dna.Body.MuscleDefinition == MuscleDefinitionDefined || dna.Body.MuscleDefinition == MuscleDefinitionRipped {
			if dna.Body.Build == BodyBuildSlender || dna.Body.Build == BodyBuildPetite {
				result.Issues = append(result.Issues, ConsistencyIssue{
					Field1:      "body.muscle_definition",
					Value1:      dna.Body.MuscleDefinition,
					Field2:      "body.build",
					Value2:      dna.Body.Build,
					Severity:    "warning",
					Description: fmt.Sprintf("High muscle definition (%s) is unusual with %s build", dna.Body.MuscleDefinition, dna.Body.Build),
				})
			}
		}
	}

	// Body Fat Percent vs Build consistency
	if dna.Body.BodyFatPercent > 0 && dna.Body.Build != "" {
		// Very low body fat (< 15%) with curvy/plus_curvy build is contradictory
		if dna.Body.BodyFatPercent < 15 {
			if dna.Body.Build == BodyBuildCurvy || dna.Body.Build == BodyBuildPlusCurvy {
				result.Issues = append(result.Issues, ConsistencyIssue{
					Field1:      "body.body_fat_percent",
					Value1:      dna.Body.BodyFatPercent,
					Field2:      "body.build",
					Value2:      dna.Body.Build,
					Severity:    "error",
					Description: fmt.Sprintf("Very low body fat (%d%%) is incompatible with %s build", dna.Body.BodyFatPercent, dna.Body.Build),
				})
				result.Valid = false
			}
		}
		// High body fat (> 30%) with athletic/muscular build is contradictory
		if dna.Body.BodyFatPercent > 30 {
			if dna.Body.Build == BodyBuildAthletic || dna.Body.Build == BodyBuildMuscular {
				result.Issues = append(result.Issues, ConsistencyIssue{
					Field1:      "body.body_fat_percent",
					Value1:      dna.Body.BodyFatPercent,
					Field2:      "body.build",
					Value2:      dna.Body.Build,
					Severity:    "error",
					Description: fmt.Sprintf("High body fat (%d%%) is incompatible with %s build", dna.Body.BodyFatPercent, dna.Body.Build),
				})
				result.Valid = false
			}
		}
	}

	return result
}

// validateHeightCMConsistency checks if height CM matches height category.
func validateHeightCMConsistency(heightCM int, heightCat HeightCategory) *ConsistencyIssue {
	expectedCat := HeightCategoryFromCM(heightCM)

	if heightCat != expectedCat {
		return &ConsistencyIssue{
			Field1:      "body.height_cm",
			Value1:      heightCM,
			Field2:      "body.height",
			Value2:      heightCat,
			Severity:    "error",
			Description: fmt.Sprintf("Height %dcm should be category %s, not %s", heightCM, expectedCat, heightCat),
		}
	}
	return nil
}

// HasErrors returns true if there are any error-level issues.
func (r *ConsistencyResult) HasErrors() bool {
	for _, issue := range r.Issues {
		if issue.Severity == "error" {
			return true
		}
	}
	return false
}

// HasWarnings returns true if there are any warning-level issues.
func (r *ConsistencyResult) HasWarnings() bool {
	for _, issue := range r.Issues {
		if issue.Severity == "warning" {
			return true
		}
	}
	return false
}
