package persona

import "fmt"

// Validate performs comprehensive validation on a character.
// Validation is species-aware and applies appropriate rules:
//   - Human: Ethnicity plausibility + consistency checks
//   - Humanoid: Morphology validation + consistency checks
//   - Android: Minimal validation (synthetic beings)
func Validate(c *Character, opts ...ValidateOption) error {
	if c == nil {
		return ErrNilCharacter
	}

	cfg := defaultValidateConfig()
	for _, opt := range opts {
		opt(cfg)
	}

	var errs ValidationErrors

	// Basic validation
	if err := validateBasics(c); err != nil {
		errs = append(errs, ValidationError{
			Message: err.Error(),
			Err:     err,
		})
	}

	// Species-specific validation
	switch c.Species {
	case SpeciesHuman:
		if !cfg.skipPlausibility {
			if violations := ValidateHumanPlausibility(c.DNA); violations != nil && !violations.Valid {
				for _, v := range violations.Violations {
					if v.Level == PlausibilityImplausible && !cfg.allowRareFeatures {
						errs.AddValue(v.Field, v.Value, v.Message, ErrImplausibleFeature)
					} else if cfg.strictMode && v.Level == PlausibilityRare {
						errs.AddValue(v.Field, v.Value, v.Message, ErrImplausibleFeature)
					}
				}
			}
		}

	case SpeciesHumanoid:
		if !cfg.skipMorphology {
			if morphErrs := ValidateHumanoidMorphology(c); morphErrs.HasErrors() {
				errs = append(errs, morphErrs...)
			}
		}

	case SpeciesAndroid:
		// Minimal validation for synthetic beings
		// Just ensure basic structure is valid

	default:
		errs.Add("species", fmt.Sprintf("unknown species type: %s", c.Species), ErrInvalidSpecies)
	}

	// Cross-attribute consistency checks
	if !cfg.skipConsistency && c.DNA != nil {
		if result := ValidateConsistency(c.DNA); !result.Valid {
			for _, issue := range result.Issues {
				if issue.Severity == "error" || cfg.strictMode {
					errs.Add(issue.Field1, issue.Description, ErrInconsistentAttributes)
				}
			}
		}
	}

	if errs.HasErrors() {
		return errs
	}
	return nil
}

// validateBasics performs basic structural validation.
func validateBasics(c *Character) error {
	if c.ID == "" {
		return fmt.Errorf("character ID is required")
	}

	if !c.Species.IsValid() {
		return ErrInvalidSpecies
	}

	if c.DNA == nil {
		return ErrNilDNA
	}

	// Validate identity
	if c.DNA.Identity.Age < 0 || c.DNA.Identity.Age > 150 {
		return ErrInvalidAge
	}

	if c.DNA.Identity.Ethnicity != "" && !c.DNA.Identity.Ethnicity.IsValid() {
		return ErrInvalidEthnicity
	}

	if c.DNA.Identity.Gender != "" && !c.DNA.Identity.Gender.IsValid() {
		return ErrInvalidGender
	}

	return nil
}

// ValidateHuman is a convenience function for validating human characters.
func ValidateHuman(c *Character, opts ...ValidateOption) error {
	if c == nil {
		return ErrNilCharacter
	}
	if c.Species != SpeciesHuman {
		return fmt.Errorf("expected human species, got %s", c.Species)
	}
	return Validate(c, opts...)
}

// ValidateHumanoid is a convenience function for validating humanoid characters.
func ValidateHumanoid(c *Character, opts ...ValidateOption) error {
	if c == nil {
		return ErrNilCharacter
	}
	if c.Species != SpeciesHumanoid {
		return fmt.Errorf("expected humanoid species, got %s", c.Species)
	}
	return Validate(c, opts...)
}

// ValidateAndroid is a convenience function for validating android characters.
func ValidateAndroid(c *Character, opts ...ValidateOption) error {
	if c == nil {
		return ErrNilCharacter
	}
	if c.Species != SpeciesAndroid {
		return fmt.Errorf("expected android species, got %s", c.Species)
	}
	return Validate(c, opts...)
}
