package skills

import (
	"sync"
)

// MasterSkillList manages the master list of all available skills
type MasterSkillList struct {
	skills          map[int32]*Skill // All skills by ID
	populatePackets map[int16][]byte // Cached packets by version
	mutex           sync.RWMutex     // Thread safety
}

// NewMasterSkillList creates a new master skill list
func NewMasterSkillList() *MasterSkillList {
	return &MasterSkillList{
		skills:          make(map[int32]*Skill),
		populatePackets: make(map[int16][]byte),
	}
}

// AddSkill adds a skill to the master list
func (msl *MasterSkillList) AddSkill(skill *Skill) {
	if skill == nil {
		return
	}

	msl.mutex.Lock()
	defer msl.mutex.Unlock()

	msl.skills[skill.SkillID] = skill

	// Clear cached packets when skills change
	msl.populatePackets = make(map[int16][]byte)
}

// GetSkillCount returns the total number of skills
func (msl *MasterSkillList) GetSkillCount() int16 {
	msl.mutex.RLock()
	defer msl.mutex.RUnlock()

	return int16(len(msl.skills))
}

// GetAllSkills returns a copy of all skills
func (msl *MasterSkillList) GetAllSkills() map[int32]*Skill {
	msl.mutex.RLock()
	defer msl.mutex.RUnlock()

	// Return a copy to prevent external modification
	skills := make(map[int32]*Skill)
	for id, skill := range msl.skills {
		skills[id] = skill
	}

	return skills
}

// GetSkill returns a skill by ID
func (msl *MasterSkillList) GetSkill(skillID int32) *Skill {
	msl.mutex.RLock()
	defer msl.mutex.RUnlock()

	if skill, exists := msl.skills[skillID]; exists {
		return skill
	}

	return nil
}

// GetSkillByName returns a skill by name (case-insensitive)
func (msl *MasterSkillList) GetSkillByName(skillName string) *Skill {
	msl.mutex.RLock()
	defer msl.mutex.RUnlock()

	// Convert to lowercase for comparison
	lowerName := toLower(skillName)

	for _, skill := range msl.skills {
		if toLower(skill.Name.Data) == lowerName {
			return skill
		}
	}

	return nil
}

// GetPopulateSkillsPacket builds a packet containing all skills for a client version
func (msl *MasterSkillList) GetPopulateSkillsPacket(version int16) ([]byte, error) {
	msl.mutex.Lock()
	defer msl.mutex.Unlock()

	// Check if we have a cached packet for this version
	if packet, exists := msl.populatePackets[version]; exists {
		// Return a copy of the cached packet
		result := make([]byte, len(packet))
		copy(result, packet)
		return result, nil
	}

	// Build the packet - this is a placeholder implementation
	// In the full implementation, this would use the PacketStruct system
	// to build a proper WS_SkillMap packet for the given version

	packet := msl.buildSkillMapPacket(version)

	// Cache the packet
	msl.populatePackets[version] = packet

	// Return a copy
	result := make([]byte, len(packet))
	copy(result, packet)
	return result, nil
}

// buildSkillMapPacket builds a WS_SkillMap packet
func (msl *MasterSkillList) buildSkillMapPacket(version int16) []byte {
	// This is a placeholder implementation
	// In a real implementation, this would use the PacketStruct system:
	// packet := configReader.getStruct("WS_SkillMap", version)
	// packet.setArrayLengthByName("skill_count", len(msl.skills))
	// for i, skill := range msl.skills {
	//     packet.setArrayDataByName("skill_id", skill.SkillID, i)
	//     packet.setArrayDataByName("short_name", &skill.ShortName, i)
	//     packet.setArrayDataByName("name", &skill.Name, i)
	//     packet.setArrayDataByName("description", &skill.Description, i)
	// }
	// return packet.serialize()

	// For now, return an empty packet
	return make([]byte, 0)
}

// RemoveSkill removes a skill from the master list
func (msl *MasterSkillList) RemoveSkill(skillID int32) {
	msl.mutex.Lock()
	defer msl.mutex.Unlock()

	delete(msl.skills, skillID)

	// Clear cached packets when skills change
	msl.populatePackets = make(map[int16][]byte)
}

// ClearSkills removes all skills from the master list
func (msl *MasterSkillList) ClearSkills() {
	msl.mutex.Lock()
	defer msl.mutex.Unlock()

	msl.skills = make(map[int32]*Skill)
	msl.populatePackets = make(map[int16][]byte)
}

// GetSkillsByType returns all skills of a specific type
func (msl *MasterSkillList) GetSkillsByType(skillType int32) []*Skill {
	msl.mutex.RLock()
	defer msl.mutex.RUnlock()

	var skills []*Skill
	for _, skill := range msl.skills {
		if skill.SkillType == skillType {
			skills = append(skills, skill)
		}
	}

	return skills
}

// HasSkill checks if a skill exists in the master list
func (msl *MasterSkillList) HasSkill(skillID int32) bool {
	msl.mutex.RLock()
	defer msl.mutex.RUnlock()

	_, exists := msl.skills[skillID]
	return exists
}

// GetSkillIDs returns all skill IDs
func (msl *MasterSkillList) GetSkillIDs() []int32 {
	msl.mutex.RLock()
	defer msl.mutex.RUnlock()

	ids := make([]int32, 0, len(msl.skills))
	for id := range msl.skills {
		ids = append(ids, id)
	}

	return ids
}

// toLower converts a string to lowercase (simple implementation)
func toLower(s string) string {
	result := make([]byte, len(s))
	for i, c := range []byte(s) {
		if c >= 'A' && c <= 'Z' {
			result[i] = c + 32
		} else {
			result[i] = c
		}
	}
	return string(result)
}
