package loot

import (
	"sync"
	"time"

	"eq2emu/internal/items"
)

// LootTable represents a complete loot table with its drops
type LootTable struct {
	ID                  int32       `json:"id"`
	Name                string      `json:"name"`
	MinCoin             int32       `json:"min_coin"`
	MaxCoin             int32       `json:"max_coin"`
	MaxLootItems        int16       `json:"max_loot_items"`
	LootDropProbability float32     `json:"loot_drop_probability"`
	CoinProbability     float32     `json:"coin_probability"`
	Drops               []*LootDrop `json:"drops"`
	mutex               sync.RWMutex
}

// LootDrop represents an individual item that can drop from a loot table
type LootDrop struct {
	LootTableID            int32   `json:"loot_table_id"`
	ItemID                 int32   `json:"item_id"`
	ItemCharges            int16   `json:"item_charges"`
	EquipItem              bool    `json:"equip_item"`
	Probability            float32 `json:"probability"`
	NoDropQuestCompletedID int32   `json:"no_drop_quest_completed_id"`
}

// GlobalLoot represents global loot configuration based on level, race, or zone
type GlobalLoot struct {
	Type     GlobalLootType `json:"type"`
	MinLevel int8           `json:"min_level"`
	MaxLevel int8           `json:"max_level"`
	Race     int16          `json:"race"`
	ZoneID   int32          `json:"zone_id"`
	TableID  int32          `json:"table_id"`
	LootTier int32          `json:"loot_tier"`
}

// GlobalLootType represents the type of global loot
type GlobalLootType int8

const (
	GlobalLootTypeLevel GlobalLootType = iota
	GlobalLootTypeRace
	GlobalLootTypeZone
)

// String returns the string representation of GlobalLootType
func (t GlobalLootType) String() string {
	switch t {
	case GlobalLootTypeLevel:
		return "level"
	case GlobalLootTypeRace:
		return "race"
	case GlobalLootTypeZone:
		return "zone"
	default:
		return "unknown"
	}
}

// LootResult represents the result of loot generation
type LootResult struct {
	Items []*items.Item `json:"items"`
	Coins int32         `json:"coins"`
	mutex sync.RWMutex
}

// AddItem adds an item to the loot result (thread-safe)
func (lr *LootResult) AddItem(item *items.Item) {
	lr.mutex.Lock()
	defer lr.mutex.Unlock()
	lr.Items = append(lr.Items, item)
}

// AddCoins adds coins to the loot result (thread-safe)
func (lr *LootResult) AddCoins(coins int32) {
	lr.mutex.Lock()
	defer lr.mutex.Unlock()
	lr.Coins += coins
}

// GetItems returns a copy of the items slice (thread-safe)
func (lr *LootResult) GetItems() []*items.Item {
	lr.mutex.RLock()
	defer lr.mutex.RUnlock()
	
	result := make([]*items.Item, len(lr.Items))
	copy(result, lr.Items)
	return result
}

// GetCoins returns the coin amount (thread-safe)
func (lr *LootResult) GetCoins() int32 {
	lr.mutex.RLock()
	defer lr.mutex.RUnlock()
	return lr.Coins
}

// IsEmpty returns true if the loot result has no items or coins
func (lr *LootResult) IsEmpty() bool {
	lr.mutex.RLock()
	defer lr.mutex.RUnlock()
	return len(lr.Items) == 0 && lr.Coins == 0
}

// TreasureChest represents a treasure chest spawn containing loot
type TreasureChest struct {
	ID                int32         `json:"id"`
	SpawnID           int32         `json:"spawn_id"`
	ZoneID            int32         `json:"zone_id"`
	X                 float32       `json:"x"`
	Y                 float32       `json:"y"`
	Z                 float32       `json:"z"`
	Heading           float32       `json:"heading"`
	AppearanceID      int32         `json:"appearance_id"`
	LootResult        *LootResult   `json:"loot_result"`
	Created           time.Time     `json:"created"`
	LootRights        []uint32      `json:"loot_rights"`        // Player IDs with loot rights
	IsDisarmable      bool          `json:"is_disarmable"`      // Can be disarmed
	IsLocked          bool          `json:"is_locked"`          // Requires key or lockpicking
	DisarmDifficulty  int16         `json:"disarm_difficulty"`  // Difficulty for disarming
	LockpickDifficulty int16        `json:"lockpick_difficulty"` // Difficulty for lockpicking
	mutex             sync.RWMutex
}

// HasLootRights checks if a player has rights to loot this chest
func (tc *TreasureChest) HasLootRights(playerID uint32) bool {
	tc.mutex.RLock()
	defer tc.mutex.RUnlock()
	
	// If no specific loot rights, anyone can loot
	if len(tc.LootRights) == 0 {
		return true
	}
	
	for _, id := range tc.LootRights {
		if id == playerID {
			return true
		}
	}
	return false
}

// AddLootRights adds a player to the loot rights list
func (tc *TreasureChest) AddLootRights(playerID uint32) {
	tc.mutex.Lock()
	defer tc.mutex.Unlock()
	
	// Check if already has rights
	for _, id := range tc.LootRights {
		if id == playerID {
			return
		}
	}
	
	tc.LootRights = append(tc.LootRights, playerID)
}

// ChestAppearance represents different chest appearances based on loot tier
type ChestAppearance struct {
	AppearanceID int32  `json:"appearance_id"`
	Name         string `json:"name"`
	MinTier      int8   `json:"min_tier"`
	MaxTier      int8   `json:"max_tier"`
}

// Predefined chest appearances based on C++ implementation
var (
	SmallChest     = &ChestAppearance{AppearanceID: 4034, Name: "Small Chest", MinTier: 1, MaxTier: 2}
	TreasureChest  = &ChestAppearance{AppearanceID: 5864, Name: "Treasure Chest", MinTier: 3, MaxTier: 4}
	OrnateChest    = &ChestAppearance{AppearanceID: 5865, Name: "Ornate Chest", MinTier: 5, MaxTier: 6}
	ExquisiteChest = &ChestAppearance{AppearanceID: 4015, Name: "Exquisite Chest", MinTier: 7, MaxTier: 10}
)

// GetChestAppearance returns the appropriate chest appearance based on loot tier
func GetChestAppearance(highestTier int8) *ChestAppearance {
	if highestTier >= ExquisiteChest.MinTier {
		return ExquisiteChest
	}
	if highestTier >= OrnateChest.MinTier {
		return OrnateChest
	}
	if highestTier >= TreasureChest.MinTier {
		return TreasureChest
	}
	return SmallChest
}

// LootContext provides context for loot generation
type LootContext struct {
	PlayerLevel    int16             `json:"player_level"`
	PlayerRace     int16             `json:"player_race"`
	ZoneID         int32             `json:"zone_id"`
	KillerID       uint32            `json:"killer_id"`
	GroupMembers   []uint32          `json:"group_members"`
	CompletedQuests map[int32]bool    `json:"completed_quests"`
	LootMethod     GroupLootMethod   `json:"loot_method"`
}

// GroupLootMethod represents different group loot distribution methods
type GroupLootMethod int8

const (
	GroupLootMethodFreeForAll GroupLootMethod = iota
	GroupLootMethodRoundRobin
	GroupLootMethodMasterLooter
	GroupLootMethodNeed
	GroupLootMethodLotto
)

// String returns the string representation of GroupLootMethod
func (glm GroupLootMethod) String() string {
	switch glm {
	case GroupLootMethodFreeForAll:
		return "free_for_all"
	case GroupLootMethodRoundRobin:
		return "round_robin"
	case GroupLootMethodMasterLooter:
		return "master_looter"
	case GroupLootMethodNeed:
		return "need_greed"
	case GroupLootMethodLotto:
		return "lotto"
	default:
		return "unknown"
	}
}

// LootEntry represents a complete loot entry with all associated data
type LootEntry struct {
	SpawnID     int32   `json:"spawn_id"`
	LootTableID int32   `json:"loot_table_id"`
	TableName   string  `json:"table_name"`
	Priority    int16   `json:"priority"`
}

// LootStatistics tracks loot generation statistics
type LootStatistics struct {
	TotalLoots          int64                    `json:"total_loots"`
	TotalItems          int64                    `json:"total_items"`
	TotalCoins          int64                    `json:"total_coins"`
	TreasureChests      int64                    `json:"treasure_chests"`
	ItemsByTier         map[int8]int64           `json:"items_by_tier"`
	LootsByTable        map[int32]int64          `json:"loots_by_table"`
	AverageItemsPerLoot float32                  `json:"average_items_per_loot"`
	AverageCoinsPerLoot float32                  `json:"average_coins_per_loot"`
	mutex               sync.RWMutex
}

// NewLootStatistics creates a new loot statistics tracker
func NewLootStatistics() *LootStatistics {
	return &LootStatistics{
		ItemsByTier:  make(map[int8]int64),
		LootsByTable: make(map[int32]int64),
	}
}

// RecordLoot records statistics for a loot generation
func (ls *LootStatistics) RecordLoot(tableID int32, result *LootResult) {
	ls.mutex.Lock()
	defer ls.mutex.Unlock()
	
	ls.TotalLoots++
	ls.LootsByTable[tableID]++
	
	items := result.GetItems()
	ls.TotalItems += int64(len(items))
	ls.TotalCoins += int64(result.GetCoins())
	
	// Track items by tier
	for _, item := range items {
		ls.ItemsByTier[item.Details.Tier]++
	}
	
	// Update averages
	if ls.TotalLoots > 0 {
		ls.AverageItemsPerLoot = float32(ls.TotalItems) / float32(ls.TotalLoots)
		ls.AverageCoinsPerLoot = float32(ls.TotalCoins) / float32(ls.TotalLoots)
	}
}

// RecordChest records a treasure chest creation
func (ls *LootStatistics) RecordChest() {
	ls.mutex.Lock()
	defer ls.mutex.Unlock()
	ls.TreasureChests++
}

// GetStatistics returns a copy of the current statistics
func (ls *LootStatistics) GetStatistics() LootStatistics {
	ls.mutex.RLock()
	defer ls.mutex.RUnlock()
	
	// Create deep copy
	copy := LootStatistics{
		TotalLoots:          ls.TotalLoots,
		TotalItems:          ls.TotalItems,
		TotalCoins:          ls.TotalCoins,
		TreasureChests:      ls.TreasureChests,
		AverageItemsPerLoot: ls.AverageItemsPerLoot,
		AverageCoinsPerLoot: ls.AverageCoinsPerLoot,
		ItemsByTier:         make(map[int8]int64),
		LootsByTable:        make(map[int32]int64),
	}
	
	for tier, count := range ls.ItemsByTier {
		copy.ItemsByTier[tier] = count
	}
	
	for tableID, count := range ls.LootsByTable {
		copy.LootsByTable[tableID] = count
	}
	
	return copy
}