package persona

// Character is the aggregate root for a character definition.
// It combines all DNA, psychology, and background information.
type Character struct {
	// ID is the unique identifier for this character.
	ID string `json:"id" yaml:"id"`

	// Version is the schema version for forward compatibility.
	Version string `json:"version" yaml:"version"`

	// Species determines validation rules (human, humanoid, android).
	Species SpeciesType `json:"species" yaml:"species"`

	// DNA contains the biological characteristics.
	DNA *DNA `json:"dna" yaml:"dna"`

	// Name contains the character's name information.
	Name NameSpec `json:"name" yaml:"name"`

	// Psychology contains the psychological profile.
	Psychology Psychology `json:"psychology" yaml:"psychology"`

	// Background contains backstory and life history.
	Background *Background `json:"background,omitempty" yaml:"background,omitempty"`

	// MorphLevel controls creature transformation intensity (humanoid only).
	// 0 = human, 25 = subtle, 50 = demi-human, 75 = hybrid, 100 = creature
	MorphLevel int `json:"morph_level,omitempty" yaml:"morph_level,omitempty"`

	// Morphology contains non-human physical features (humanoid only).
	// Only applied when MorphLevel >= 25.
	Morphology *MorphologyHints `json:"morphology,omitempty" yaml:"morphology,omitempty"`
}

// DNA contains the complete biological DNA specification for a character.
// This is the single source of truth for all physical characteristics.
// Once generated during character creation, this is immutable.
type DNA struct {
	// Identity contains demographic and heritage information.
	Identity IdentityDNA `json:"identity" yaml:"identity"`

	// Face contains all facial feature specifications.
	Face FaceDNA `json:"face" yaml:"face"`

	// Body contains all body specifications.
	Body BodyDNA `json:"body" yaml:"body"`

	// Voice contains all voice specifications for TTS.
	Voice VoiceDNA `json:"voice" yaml:"voice"`
}

// NameSpec contains the character's name information.
type NameSpec struct {
	// First is the first/given name.
	First string `json:"first" yaml:"first"`

	// Last is the last/family name.
	Last string `json:"last,omitempty" yaml:"last,omitempty"`

	// Middle is the middle name (if any).
	Middle string `json:"middle,omitempty" yaml:"middle,omitempty"`

	// Nickname is a preferred nickname.
	Nickname string `json:"nickname,omitempty" yaml:"nickname,omitempty"`

	// DisplayName is the name to show in UIs.
	// If empty, defaults to First name.
	DisplayName string `json:"display_name,omitempty" yaml:"display_name,omitempty"`
}

// FullName returns the full name as "First Last".
func (n NameSpec) FullName() string {
	if n.Last == "" {
		return n.First
	}
	return n.First + " " + n.Last
}

// Display returns the display name, falling back to First name.
func (n NameSpec) Display() string {
	if n.DisplayName != "" {
		return n.DisplayName
	}
	if n.Nickname != "" {
		return n.Nickname
	}
	return n.First
}

// NewCharacter creates a new character with default values.
func NewCharacter(id string) *Character {
	return &Character{
		ID:      id,
		Version: "1.0",
		Species: SpeciesHuman,
		DNA:     &DNA{},
	}
}

// NewHumanCharacter creates a new human character.
func NewHumanCharacter(id string) *Character {
	c := NewCharacter(id)
	c.Species = SpeciesHuman
	return c
}

// NewHumanoidCharacter creates a new humanoid character.
func NewHumanoidCharacter(id string, morphLevel int) *Character {
	c := NewCharacter(id)
	c.Species = SpeciesHumanoid
	c.MorphLevel = morphLevel
	return c
}

// NewAndroidCharacter creates a new android character.
func NewAndroidCharacter(id string) *Character {
	c := NewCharacter(id)
	c.Species = SpeciesAndroid
	return c
}

// IsHuman returns true if this is a human character.
func (c *Character) IsHuman() bool {
	return c.Species == SpeciesHuman
}

// IsHumanoid returns true if this is a humanoid character.
func (c *Character) IsHumanoid() bool {
	return c.Species == SpeciesHumanoid
}

// IsAndroid returns true if this is an android character.
func (c *Character) IsAndroid() bool {
	return c.Species == SpeciesAndroid
}

// HasMorphology returns true if the character has non-human features.
func (c *Character) HasMorphology() bool {
	return c.Morphology != nil && c.Morphology.HasFeatures()
}

// MorphBand returns the morph level band name.
func (c *Character) MorphBand() string {
	return MorphLevelBand(c.MorphLevel)
}
