package achievements

import (
	"fmt"
	"sync"
)

// MasterList manages the global list of all achievements
type MasterList struct {
	achievements map[uint32]*Achievement
	mutex        sync.RWMutex
}

// NewMasterList creates a new master achievement list
func NewMasterList() *MasterList {
	return &MasterList{
		achievements: make(map[uint32]*Achievement),
	}
}

// AddAchievement adds an achievement to the master list
// Returns false if achievement with same ID already exists
func (m *MasterList) AddAchievement(achievement *Achievement) bool {
	if achievement == nil {
		return false
	}

	m.mutex.Lock()
	defer m.mutex.Unlock()

	if _, exists := m.achievements[achievement.ID]; exists {
		return false
	}

	m.achievements[achievement.ID] = achievement
	return true
}

// GetAchievement retrieves an achievement by ID
// Returns nil if not found
func (m *MasterList) GetAchievement(id uint32) *Achievement {
	m.mutex.RLock()
	defer m.mutex.RUnlock()

	return m.achievements[id]
}

// GetAchievementClone retrieves a cloned copy of an achievement by ID
// Returns nil if not found. Safe for modification without affecting master list
func (m *MasterList) GetAchievementClone(id uint32) *Achievement {
	m.mutex.RLock()
	achievement := m.achievements[id]
	m.mutex.RUnlock()

	if achievement == nil {
		return nil
	}

	return achievement.Clone()
}

// GetAllAchievements returns a map of all achievements (read-only access)
// The returned map should not be modified
func (m *MasterList) GetAllAchievements() map[uint32]*Achievement {
	m.mutex.RLock()
	defer m.mutex.RUnlock()

	// Return copy of map to prevent external modification
	result := make(map[uint32]*Achievement, len(m.achievements))
	for id, achievement := range m.achievements {
		result[id] = achievement
	}
	return result
}

// GetAchievementsByCategory returns achievements filtered by category
func (m *MasterList) GetAchievementsByCategory(category string) []*Achievement {
	m.mutex.RLock()
	defer m.mutex.RUnlock()

	var result []*Achievement
	for _, achievement := range m.achievements {
		if achievement.Category == category {
			result = append(result, achievement)
		}
	}
	return result
}

// GetAchievementsByExpansion returns achievements filtered by expansion
func (m *MasterList) GetAchievementsByExpansion(expansion string) []*Achievement {
	m.mutex.RLock()
	defer m.mutex.RUnlock()

	var result []*Achievement
	for _, achievement := range m.achievements {
		if achievement.Expansion == expansion {
			result = append(result, achievement)
		}
	}
	return result
}

// RemoveAchievement removes an achievement from the master list
// Returns true if achievement was found and removed
func (m *MasterList) RemoveAchievement(id uint32) bool {
	m.mutex.Lock()
	defer m.mutex.Unlock()

	if _, exists := m.achievements[id]; !exists {
		return false
	}

	delete(m.achievements, id)
	return true
}

// UpdateAchievement updates an existing achievement
// Returns error if achievement doesn't exist
func (m *MasterList) UpdateAchievement(achievement *Achievement) error {
	if achievement == nil {
		return fmt.Errorf("achievement cannot be nil")
	}

	m.mutex.Lock()
	defer m.mutex.Unlock()

	if _, exists := m.achievements[achievement.ID]; !exists {
		return fmt.Errorf("achievement with ID %d does not exist", achievement.ID)
	}

	m.achievements[achievement.ID] = achievement
	return nil
}

// Clear removes all achievements from the master list
func (m *MasterList) Clear() {
	m.mutex.Lock()
	defer m.mutex.Unlock()

	m.achievements = make(map[uint32]*Achievement)
}

// Size returns the number of achievements in the master list
func (m *MasterList) Size() int {
	m.mutex.RLock()
	defer m.mutex.RUnlock()

	return len(m.achievements)
}

// Exists checks if an achievement with given ID exists
func (m *MasterList) Exists(id uint32) bool {
	m.mutex.RLock()
	defer m.mutex.RUnlock()

	_, exists := m.achievements[id]
	return exists
}

// GetCategories returns all unique categories
func (m *MasterList) GetCategories() []string {
	m.mutex.RLock()
	defer m.mutex.RUnlock()

	categories := make(map[string]bool)
	for _, achievement := range m.achievements {
		if achievement.Category != "" {
			categories[achievement.Category] = true
		}
	}

	result := make([]string, 0, len(categories))
	for category := range categories {
		result = append(result, category)
	}
	return result
}

// GetExpansions returns all unique expansions
func (m *MasterList) GetExpansions() []string {
	m.mutex.RLock()
	defer m.mutex.RUnlock()

	expansions := make(map[string]bool)
	for _, achievement := range m.achievements {
		if achievement.Expansion != "" {
			expansions[achievement.Expansion] = true
		}
	}

	result := make([]string, 0, len(expansions))
	for expansion := range expansions {
		result = append(result, expansion)
	}
	return result
}
