package skills

import (
	"fmt"
	"sync"
)

// Manager provides high-level management of the skills system
type Manager struct {
	masterSkillList *MasterSkillList
	mutex           sync.RWMutex

	// Statistics
	totalSkillUps     int64
	skillUpsByType    map[int32]int64 // Skill type -> count
	skillUpsBySkill   map[int32]int64 // Skill ID -> count
	playersWithSkills int64
}

// NewManager creates a new skills manager
func NewManager() *Manager {
	return &Manager{
		masterSkillList: NewMasterSkillList(),
		skillUpsByType:  make(map[int32]int64),
		skillUpsBySkill: make(map[int32]int64),
	}
}

// Initialize loads skills data (placeholder for database loading)
func (m *Manager) Initialize() error {
	// TODO: Load skills from database when database system is integrated
	// This would typically load all skills from a skills table
	return nil
}

// GetMasterSkillList returns the master skill list
func (m *Manager) GetMasterSkillList() *MasterSkillList {
	return m.masterSkillList
}

// AddSkillToMaster adds a skill to the master list
func (m *Manager) AddSkillToMaster(skill *Skill) {
	m.masterSkillList.AddSkill(skill)
}

// GetSkill returns a skill from the master list by ID
func (m *Manager) GetSkill(skillID int32) *Skill {
	return m.masterSkillList.GetSkill(skillID)
}

// GetSkillByName returns a skill from the master list by name
func (m *Manager) GetSkillByName(skillName string) *Skill {
	return m.masterSkillList.GetSkillByName(skillName)
}

// CreatePlayerSkillList creates a new player skill list
func (m *Manager) CreatePlayerSkillList() *PlayerSkillList {
	m.mutex.Lock()
	m.playersWithSkills++
	m.mutex.Unlock()

	return NewPlayerSkillList()
}

// RecordSkillUp records a skill increase for statistics
func (m *Manager) RecordSkillUp(skillID int32, skillType int32) {
	m.mutex.Lock()
	defer m.mutex.Unlock()

	m.totalSkillUps++
	m.skillUpsByType[skillType]++
	m.skillUpsBySkill[skillID]++
}

// GetStatistics returns skill system statistics
func (m *Manager) GetStatistics() map[string]interface{} {
	m.mutex.RLock()
	defer m.mutex.RUnlock()

	stats := make(map[string]interface{})
	stats["total_skill_ups"] = m.totalSkillUps
	stats["players_with_skills"] = m.playersWithSkills
	stats["total_skills_in_master"] = m.masterSkillList.GetSkillCount()

	// Copy skill type statistics
	typeStats := make(map[int32]int64)
	for skillType, count := range m.skillUpsByType {
		typeStats[skillType] = count
	}
	stats["skill_ups_by_type"] = typeStats

	// Copy individual skill statistics
	skillStats := make(map[int32]int64)
	for skillID, count := range m.skillUpsBySkill {
		skillStats[skillID] = count
	}
	stats["skill_ups_by_skill"] = skillStats

	return stats
}

// ResetStatistics resets all statistics
func (m *Manager) ResetStatistics() {
	m.mutex.Lock()
	defer m.mutex.Unlock()

	m.totalSkillUps = 0
	m.playersWithSkills = 0
	m.skillUpsByType = make(map[int32]int64)
	m.skillUpsBySkill = make(map[int32]int64)
}

// GetSkillsByType returns all skills of a specific type
func (m *Manager) GetSkillsByType(skillType int32) []*Skill {
	return m.masterSkillList.GetSkillsByType(skillType)
}

// GetSkillTypeCount returns the number of skills of a specific type
func (m *Manager) GetSkillTypeCount(skillType int32) int {
	skills := m.GetSkillsByType(skillType)
	return len(skills)
}

// GetSkillUpCount returns the total number of skill ups for a skill
func (m *Manager) GetSkillUpCount(skillID int32) int64 {
	m.mutex.RLock()
	defer m.mutex.RUnlock()

	return m.skillUpsBySkill[skillID]
}

// GetSkillTypeUpCount returns the total number of skill ups for a skill type
func (m *Manager) GetSkillTypeUpCount(skillType int32) int64 {
	m.mutex.RLock()
	defer m.mutex.RUnlock()

	return m.skillUpsByType[skillType]
}

// ValidateSkillData validates that all skills in the master list are properly configured
func (m *Manager) ValidateSkillData() []string {
	skills := m.masterSkillList.GetAllSkills()
	issues := make([]string, 0)

	if len(skills) == 0 {
		issues = append(issues, "No skills configured in master list")
		return issues
	}

	for skillID, skill := range skills {
		if skill == nil {
			issues = append(issues, fmt.Sprintf("Skill ID %d is nil", skillID))
			continue
		}

		if skill.SkillID != skillID {
			issues = append(issues, fmt.Sprintf("Skill %d has mismatched ID: %d", skillID, skill.SkillID))
		}

		if skill.Name.Data == "" {
			issues = append(issues, fmt.Sprintf("Skill %d has empty name", skillID))
		}

		if skill.SkillType == 0 {
			issues = append(issues, fmt.Sprintf("Skill %d (%s) has no skill type", skillID, skill.Name.Data))
		}

		if skill.MaxVal < 0 {
			issues = append(issues, fmt.Sprintf("Skill %d (%s) has negative max value: %d", skillID, skill.Name.Data, skill.MaxVal))
		}

		if skill.CurrentVal < 0 {
			issues = append(issues, fmt.Sprintf("Skill %d (%s) has negative current value: %d", skillID, skill.Name.Data, skill.CurrentVal))
		}

		if skill.CurrentVal > skill.MaxVal {
			issues = append(issues, fmt.Sprintf("Skill %d (%s) has current value (%d) greater than max value (%d)",
				skillID, skill.Name.Data, skill.CurrentVal, skill.MaxVal))
		}
	}

	return issues
}

// ProcessCommand handles skill-related commands
func (m *Manager) ProcessCommand(command string, args []string) (string, error) {
	switch command {
	case "stats":
		return m.handleStatsCommand(args)
	case "validate":
		return m.handleValidateCommand(args)
	case "list":
		return m.handleListCommand(args)
	case "info":
		return m.handleInfoCommand(args)
	default:
		return "", fmt.Errorf("unknown skills command: %s", command)
	}
}

// handleStatsCommand shows skill system statistics
func (m *Manager) handleStatsCommand(args []string) (string, error) {
	stats := m.GetStatistics()

	result := "Skills System Statistics:\n"
	result += fmt.Sprintf("Total Skills in Master List: %d\n", stats["total_skills_in_master"])
	result += fmt.Sprintf("Players with Skills: %d\n", stats["players_with_skills"])
	result += fmt.Sprintf("Total Skill Ups: %d\n", stats["total_skill_ups"])

	return result, nil
}

// handleValidateCommand validates skill data
func (m *Manager) handleValidateCommand(args []string) (string, error) {
	issues := m.ValidateSkillData()

	if len(issues) == 0 {
		return "All skill data is valid.", nil
	}

	result := fmt.Sprintf("Found %d issues with skill data:\n", len(issues))
	for i, issue := range issues {
		result += fmt.Sprintf("%d. %s\n", i+1, issue)
	}

	return result, nil
}

// handleListCommand lists skills
func (m *Manager) handleListCommand(args []string) (string, error) {
	skills := m.masterSkillList.GetAllSkills()

	if len(skills) == 0 {
		return "No skills configured.", nil
	}

	result := fmt.Sprintf("Skills (%d):\n", len(skills))
	count := 0
	for _, skill := range skills {
		if count >= 20 { // Limit output
			result += "... (and more)\n"
			break
		}
		result += fmt.Sprintf("  %d: %s (Type: %d)\n", skill.SkillID, skill.Name.Data, skill.SkillType)
		count++
	}

	return result, nil
}

// handleInfoCommand shows information about a specific skill
func (m *Manager) handleInfoCommand(args []string) (string, error) {
	if len(args) == 0 {
		return "", fmt.Errorf("skill name or ID required")
	}

	skillName := args[0]
	skill := m.GetSkillByName(skillName)

	if skill == nil {
		return fmt.Sprintf("Skill '%s' not found.", skillName), nil
	}

	result := fmt.Sprintf("Skill Information:\n")
	result += fmt.Sprintf("ID: %d\n", skill.SkillID)
	result += fmt.Sprintf("Name: %s\n", skill.Name.Data)
	result += fmt.Sprintf("Short Name: %s\n", skill.ShortName.Data)
	result += fmt.Sprintf("Type: %d\n", skill.SkillType)
	result += fmt.Sprintf("Description: %s\n", skill.Description.Data)
	result += fmt.Sprintf("Max Value: %d\n", skill.MaxVal)
	result += fmt.Sprintf("Current Value: %d\n", skill.CurrentVal)
	result += fmt.Sprintf("Active: %t\n", skill.ActiveSkill)

	upCount := m.GetSkillUpCount(skill.SkillID)
	result += fmt.Sprintf("Total Skill Ups Recorded: %d\n", upCount)

	return result, nil
}

// Shutdown gracefully shuts down the manager
func (m *Manager) Shutdown() {
	// Nothing to clean up currently, but placeholder for future cleanup
}
