package trade

import (
	"sync"
	"time"
)

// TradeItemInfo represents an item in a trade slot
// Converted from C++ TradeItemInfo struct
type TradeItemInfo struct {
	Item     *Item // TODO: Replace with actual Item type when available
	Quantity int32 // Quantity of the item being traded
}

// CoinAmounts represents the breakdown of coins in EQ2 currency
type CoinAmounts struct {
	Platinum int32 // Platinum coins
	Gold     int32 // Gold coins
	Silver   int32 // Silver coins
	Copper   int32 // Copper coins (base unit)
}

// TradeState represents the current state of a trade
type TradeState int32

const (
	TradeStateActive    TradeState = 0 // Trade is active and ongoing
	TradeStateAccepted  TradeState = 1 // Trade has been accepted by both parties
	TradeStateCanceled  TradeState = 2 // Trade was canceled
	TradeStateCompleted TradeState = 3 // Trade was completed successfully
)

// TradeValidationError represents validation errors during trade operations
type TradeValidationError struct {
	Code    int32  // Error code from trade constants
	Message string // Human readable error message
}

// Error implements the error interface
func (e *TradeValidationError) Error() string {
	return e.Message
}

// TradeParticipant represents one side of a trade
type TradeParticipant struct {
	EntityID      int32                  // Entity ID of the participant
	Items         map[int8]TradeItemInfo // Items being traded by slot
	Coins         int64                  // Total coins being offered (in copper)
	HasAccepted   bool                   // Whether participant has accepted the trade
	MaxSlots      int8                   // Maximum trade slots for this participant
	IsBot         bool                   // Whether this participant is a bot
	ClientVersion int32                  // Client version (affects slot count)
}

// NewTradeParticipant creates a new trade participant
func NewTradeParticipant(entityID int32, isBot bool, clientVersion int32) *TradeParticipant {
	maxSlots := TradeMaxSlotsDefault
	if clientVersion <= 561 {
		maxSlots = TradeMaxSlotsLegacy
	}

	return &TradeParticipant{
		EntityID:      entityID,
		Items:         make(map[int8]TradeItemInfo),
		Coins:         0,
		HasAccepted:   false,
		MaxSlots:      int8(maxSlots),
		IsBot:         isBot,
		ClientVersion: clientVersion,
	}
}

// GetNextFreeSlot finds the next available slot for items
func (tp *TradeParticipant) GetNextFreeSlot() int8 {
	for slot := int8(0); slot < tp.MaxSlots; slot++ {
		if _, exists := tp.Items[slot]; !exists {
			return slot
		}
	}
	return TradeSlotAutoFind // No free slots available
}

// HasItem checks if participant has a specific item in trade
func (tp *TradeParticipant) HasItem(itemID int32) bool {
	for _, itemInfo := range tp.Items {
		if itemInfo.Item != nil && itemInfo.Item.GetID() == itemID {
			return true
		}
	}
	return false
}

// GetItemCount returns the total number of items in trade
func (tp *TradeParticipant) GetItemCount() int {
	return len(tp.Items)
}

// ClearItems removes all items from the trade
func (tp *TradeParticipant) ClearItems() {
	tp.Items = make(map[int8]TradeItemInfo)
}

// GetCoinAmounts converts total copper to coin denominations
func (tp *TradeParticipant) GetCoinAmounts() CoinAmounts {
	return CalculateCoins(tp.Coins)
}

// Item represents a placeholder item interface
// TODO: Replace with actual Item implementation when available
type Item interface {
	GetID() int32
	GetName() string
	GetQuantity() int32
	GetIcon(version int32) int32
	IsNoTrade() bool
	IsHeirloom() bool
	IsAttuned() bool
	GetCreationTime() time.Time
	GetGroupCharacterIDs() []int32
}

// Entity represents a placeholder entity interface
// TODO: Replace with actual Entity implementation when available
type Entity interface {
	GetID() int32
	GetName() string
	IsPlayer() bool
	IsBot() bool
	HasCoins(amount int64) bool
	GetClientVersion() int32
}

// TradeManager handles multiple active trades
type TradeManager struct {
	trades map[int32]*Trade // Active trades by trader1 ID
	mutex  sync.RWMutex     // Thread safety
}

// NewTradeManager creates a new trade manager
func NewTradeManager() *TradeManager {
	return &TradeManager{
		trades: make(map[int32]*Trade),
	}
}

// GetTrade retrieves an active trade for an entity
func (tm *TradeManager) GetTrade(entityID int32) *Trade {
	tm.mutex.RLock()
	defer tm.mutex.RUnlock()

	// Check if entity is trader1
	if trade, exists := tm.trades[entityID]; exists {
		return trade
	}

	// Check if entity is trader2
	for _, trade := range tm.trades {
		if trade.GetTrader2ID() == entityID {
			return trade
		}
	}

	return nil
}

// AddTrade adds a new trade to management
func (tm *TradeManager) AddTrade(trade *Trade) {
	tm.mutex.Lock()
	defer tm.mutex.Unlock()

	tm.trades[trade.GetTrader1ID()] = trade
}

// RemoveTrade removes a trade from management
func (tm *TradeManager) RemoveTrade(trader1ID int32) {
	tm.mutex.Lock()
	defer tm.mutex.Unlock()

	delete(tm.trades, trader1ID)
}

// GetActiveTradeCount returns the number of active trades
func (tm *TradeManager) GetActiveTradeCount() int {
	tm.mutex.RLock()
	defer tm.mutex.RUnlock()

	return len(tm.trades)
}
