package skills

import "fmt"

// SkillAware interface for entities that have skills
type SkillAware interface {
	GetSkillList() *PlayerSkillList
	GetSkillByName(name string) *Skill
	GetSkill(skillID int32) *Skill
	HasSkill(skillID int32) bool
	IncreaseSkill(skillName string, amount int32) error
}

// PacketSender interface for sending skill packets to clients
type PacketSender interface {
	QueuePacket(packet []byte)
	GetVersion() int32
}

// Database interface for skill persistence
type Database interface {
	LoadPlayerSkills(characterID int32) ([]*Skill, error)
	SavePlayerSkill(characterID int32, skill *Skill) error
	LoadMasterSkills() ([]*Skill, error)
	SaveMasterSkill(skill *Skill) error
}

// Logger interface for skill system logging
type Logger interface {
	LogInfo(message string, args ...interface{})
	LogError(message string, args ...interface{})
	LogDebug(message string, args ...interface{})
}

// EntitySkillAdapter provides skill functionality for entities
type EntitySkillAdapter struct {
	skillList *PlayerSkillList
	entityID  int32
	logger    Logger
}

// NewEntitySkillAdapter creates a new entity skill adapter
func NewEntitySkillAdapter(entityID int32, logger Logger) *EntitySkillAdapter {
	return &EntitySkillAdapter{
		skillList: NewPlayerSkillList(),
		entityID:  entityID,
		logger:    logger,
	}
}

// GetSkillList returns the player's skill list
func (esa *EntitySkillAdapter) GetSkillList() *PlayerSkillList {
	return esa.skillList
}

// GetSkillByName returns a skill by name
func (esa *EntitySkillAdapter) GetSkillByName(name string) *Skill {
	return esa.skillList.GetSkillByName(name)
}

// GetSkill returns a skill by ID
func (esa *EntitySkillAdapter) GetSkill(skillID int32) *Skill {
	return esa.skillList.GetSkill(skillID)
}

// HasSkill checks if the entity has a skill
func (esa *EntitySkillAdapter) HasSkill(skillID int32) bool {
	return esa.skillList.HasSkill(skillID)
}

// IncreaseSkill increases a skill by name
func (esa *EntitySkillAdapter) IncreaseSkill(skillName string, amount int32) error {
	skill := esa.skillList.GetSkillByName(skillName)
	if skill == nil {
		if esa.logger != nil {
			esa.logger.LogError("Entity %d: Skill '%s' not found for increase", esa.entityID, skillName)
		}
		return fmt.Errorf("skill '%s' not found", skillName)
	}

	esa.skillList.IncreaseSkill(skill, int16(amount))

	if esa.logger != nil {
		esa.logger.LogDebug("Entity %d: Increased skill '%s' by %d (now %d/%d)",
			esa.entityID, skillName, amount, skill.CurrentVal, skill.MaxVal)
	}

	return nil
}

// AddSkill adds a new skill to the entity
func (esa *EntitySkillAdapter) AddSkill(skill *Skill) {
	if skill == nil {
		return
	}

	esa.skillList.AddSkill(skill)

	if esa.logger != nil {
		esa.logger.LogDebug("Entity %d: Added skill '%s' (ID: %d)", esa.entityID, skill.Name.Data, skill.SkillID)
	}
}

// RemoveSkill removes a skill from the entity
func (esa *EntitySkillAdapter) RemoveSkill(skill *Skill) {
	if skill == nil {
		return
	}

	esa.skillList.RemoveSkill(skill)

	if esa.logger != nil {
		esa.logger.LogDebug("Entity %d: Removed skill '%s' (ID: %d)", esa.entityID, skill.Name.Data, skill.SkillID)
	}
}

// GetSkillValue returns a skill's current value including bonuses
func (esa *EntitySkillAdapter) GetSkillValue(skillID int32) int16 {
	skill := esa.skillList.GetSkill(skillID)
	if skill == nil {
		return 0
	}

	return esa.skillList.CalculateSkillValue(skillID, skill.CurrentVal)
}

// GetSkillMaxValue returns a skill's max value including bonuses
func (esa *EntitySkillAdapter) GetSkillMaxValue(skillID int32) int16 {
	skill := esa.skillList.GetSkill(skillID)
	if skill == nil {
		return 0
	}

	return esa.skillList.CalculateSkillMaxValue(skillID, skill.MaxVal)
}

// ApplySkillBonus applies a skill bonus from a spell
func (esa *EntitySkillAdapter) ApplySkillBonus(spellID int32, skillID int32, value float32) {
	esa.skillList.AddSkillBonus(spellID, skillID, value)

	if esa.logger != nil {
		esa.logger.LogDebug("Entity %d: Applied skill bonus from spell %d to skill %d: %f",
			esa.entityID, spellID, skillID, value)
	}
}

// RemoveSkillBonus removes skill bonuses from a spell
func (esa *EntitySkillAdapter) RemoveSkillBonus(spellID int32) {
	esa.skillList.RemoveSkillBonus(spellID)

	if esa.logger != nil {
		esa.logger.LogDebug("Entity %d: Removed skill bonuses from spell %d", esa.entityID, spellID)
	}
}

// CheckSkillIncrease attempts to increase a skill
func (esa *EntitySkillAdapter) CheckSkillIncrease(skillID int32) bool {
	skill := esa.skillList.GetSkill(skillID)
	if skill == nil {
		return false
	}

	increased := esa.skillList.CheckSkillIncrease(skill)

	if increased && esa.logger != nil {
		esa.logger.LogInfo("Entity %d: Skill '%s' increased to %d/%d",
			esa.entityID, skill.Name.Data, skill.CurrentVal, skill.MaxVal)
	}

	return increased
}

// GetSaveNeededSkills returns skills that need database saving
func (esa *EntitySkillAdapter) GetSaveNeededSkills() []*Skill {
	return esa.skillList.GetSaveNeededSkills()
}

// GetSkillUpdates returns skills that need client updates
func (esa *EntitySkillAdapter) GetSkillUpdates() []*Skill {
	return esa.skillList.GetSkillUpdates()
}

// HasSkillUpdates returns whether there are pending skill updates
func (esa *EntitySkillAdapter) HasSkillUpdates() bool {
	return esa.skillList.HasSkillUpdates()
}

// SendSkillPacket sends skill updates to a client
func (esa *EntitySkillAdapter) SendSkillPacket(sender PacketSender) error {
	if sender == nil {
		return fmt.Errorf("packet sender is nil")
	}

	packet, err := esa.skillList.GetSkillPacket(int16(sender.GetVersion()))
	if err != nil {
		return fmt.Errorf("failed to build skill packet: %w", err)
	}

	sender.QueuePacket(packet)

	if esa.logger != nil {
		esa.logger.LogDebug("Entity %d: Sent skill packet to client (version %d)",
			esa.entityID, sender.GetVersion())
	}

	return nil
}

// LoadSkillsFromDatabase loads skills from database (placeholder)
func (esa *EntitySkillAdapter) LoadSkillsFromDatabase(db Database, characterID int32) error {
	if db == nil {
		return fmt.Errorf("database is nil")
	}

	skills, err := db.LoadPlayerSkills(characterID)
	if err != nil {
		return fmt.Errorf("failed to load player skills: %w", err)
	}

	for _, skill := range skills {
		esa.skillList.AddSkill(skill)
	}

	if esa.logger != nil {
		esa.logger.LogInfo("Entity %d: Loaded %d skills from database", esa.entityID, len(skills))
	}

	return nil
}

// SaveSkillsToDatabase saves skills to database (placeholder)
func (esa *EntitySkillAdapter) SaveSkillsToDatabase(db Database, characterID int32) error {
	if db == nil {
		return fmt.Errorf("database is nil")
	}

	saveSkills := esa.GetSaveNeededSkills()

	for _, skill := range saveSkills {
		if err := db.SavePlayerSkill(characterID, skill); err != nil {
			if esa.logger != nil {
				esa.logger.LogError("Entity %d: Failed to save skill %s: %v", esa.entityID, skill.Name.Data, err)
			}
			return fmt.Errorf("failed to save skill %s: %w", skill.Name.Data, err)
		}
	}

	if len(saveSkills) > 0 && esa.logger != nil {
		esa.logger.LogInfo("Entity %d: Saved %d skills to database", esa.entityID, len(saveSkills))
	}

	return nil
}
