package trade

import (
	"fmt"
	"sync"
	"time"
)

// TradeService provides high-level trade management functionality
// This integrates the trade system with the broader server architecture
type TradeService struct {
	tradeManager *TradeManager

	// Trade configuration
	maxTradeDuration time.Duration // Maximum time a trade can be active

	// TODO: Add references to other systems when available
	// entityManager *EntityManager
	// packetManager *PacketManager
	// logManager    *LogManager

	mutex sync.RWMutex
}

// NewTradeService creates a new trade service
func NewTradeService() *TradeService {
	return &TradeService{
		tradeManager:     NewTradeManager(),
		maxTradeDuration: 30 * time.Minute, // Default 30 minute timeout
	}
}

// InitiateTrade starts a trade between two entities
// This is the main entry point for starting trades
func (ts *TradeService) InitiateTrade(initiatorID, targetID int32) (*Trade, error) {
	ts.mutex.Lock()
	defer ts.mutex.Unlock()

	// Check if either entity is already in a trade
	if existingTrade := ts.tradeManager.GetTrade(initiatorID); existingTrade != nil {
		return nil, fmt.Errorf("initiator is already in a trade")
	}

	if existingTrade := ts.tradeManager.GetTrade(targetID); existingTrade != nil {
		return nil, fmt.Errorf("target is already in a trade")
	}

	// TODO: Get actual entities when entity system is available
	// For now, create placeholder entities
	initiator := &PlaceholderEntity{ID: initiatorID}
	target := &PlaceholderEntity{ID: targetID}

	// Create new trade
	trade := NewTrade(initiator, target)
	if trade == nil {
		return nil, fmt.Errorf("failed to create trade")
	}

	// Add to trade manager
	ts.tradeManager.AddTrade(trade)

	return trade, nil
}

// GetTrade retrieves an active trade for an entity
func (ts *TradeService) GetTrade(entityID int32) *Trade {
	return ts.tradeManager.GetTrade(entityID)
}

// AddItemToTrade adds an item to a player's trade offer
func (ts *TradeService) AddItemToTrade(entityID int32, item Item, quantity int32, slot int8) error {
	trade := ts.tradeManager.GetTrade(entityID)
	if trade == nil {
		return fmt.Errorf("entity is not in a trade")
	}

	return trade.AddItemToTrade(entityID, item, quantity, slot)
}

// RemoveItemFromTrade removes an item from a player's trade offer
func (ts *TradeService) RemoveItemFromTrade(entityID int32, slot int8) error {
	trade := ts.tradeManager.GetTrade(entityID)
	if trade == nil {
		return fmt.Errorf("entity is not in a trade")
	}

	return trade.RemoveItemFromTrade(entityID, slot)
}

// AddCoinsToTrade adds coins to a player's trade offer
func (ts *TradeService) AddCoinsToTrade(entityID int32, amount int64) error {
	trade := ts.tradeManager.GetTrade(entityID)
	if trade == nil {
		return fmt.Errorf("entity is not in a trade")
	}

	return trade.AddCoinsToTrade(entityID, amount)
}

// RemoveCoinsFromTrade removes coins from a player's trade offer
func (ts *TradeService) RemoveCoinsFromTrade(entityID int32, amount int64) error {
	trade := ts.tradeManager.GetTrade(entityID)
	if trade == nil {
		return fmt.Errorf("entity is not in a trade")
	}

	return trade.RemoveCoinsFromTrade(entityID, amount)
}

// AcceptTrade marks a player as having accepted their trade
func (ts *TradeService) AcceptTrade(entityID int32) (bool, error) {
	trade := ts.tradeManager.GetTrade(entityID)
	if trade == nil {
		return false, fmt.Errorf("entity is not in a trade")
	}

	completed, err := trade.SetTradeAccepted(entityID)
	if err != nil {
		return false, err
	}

	// If trade completed, remove from manager
	if completed {
		ts.tradeManager.RemoveTrade(trade.GetTrader1ID())
	}

	return completed, nil
}

// CancelTrade cancels an active trade
func (ts *TradeService) CancelTrade(entityID int32) error {
	trade := ts.tradeManager.GetTrade(entityID)
	if trade == nil {
		return fmt.Errorf("entity is not in a trade")
	}

	err := trade.CancelTrade(entityID)
	if err != nil {
		return err
	}

	// Remove from manager
	ts.tradeManager.RemoveTrade(trade.GetTrader1ID())

	return nil
}

// GetTradeInfo returns comprehensive information about a trade
func (ts *TradeService) GetTradeInfo(entityID int32) (map[string]interface{}, error) {
	trade := ts.tradeManager.GetTrade(entityID)
	if trade == nil {
		return nil, fmt.Errorf("entity is not in a trade")
	}

	return trade.GetTradeInfo(), nil
}

// GetActiveTradeCount returns the number of active trades
func (ts *TradeService) GetActiveTradeCount() int {
	return ts.tradeManager.GetActiveTradeCount()
}

// ProcessTrades handles periodic trade processing (timeouts, cleanup, etc.)
func (ts *TradeService) ProcessTrades() {
	ts.mutex.Lock()
	defer ts.mutex.Unlock()

	// TODO: Implement trade timeout processing
	// This would check for trades that have been active too long and auto-cancel them

	// Get all active trades
	// Check each trade's start time against maxTradeDuration
	// Cancel expired trades
}

// GetTradeStatistics returns statistics about trade activity
func (ts *TradeService) GetTradeStatistics() map[string]interface{} {
	stats := make(map[string]interface{})

	stats["active_trades"] = ts.tradeManager.GetActiveTradeCount()
	stats["max_trade_duration_minutes"] = ts.maxTradeDuration.Minutes()

	// TODO: Add more statistics when logging/metrics system is available
	// - Total trades completed today
	// - Average trade completion time
	// - Most traded items
	// - Trade success/failure rates

	return stats
}

// ValidateTradeRequest checks if a trade request is valid
func (ts *TradeService) ValidateTradeRequest(initiatorID, targetID int32) error {
	if initiatorID == targetID {
		return fmt.Errorf("cannot trade with yourself")
	}

	if initiatorID <= 0 || targetID <= 0 {
		return fmt.Errorf("invalid entity IDs")
	}

	// Check if either entity is already in a trade
	if ts.tradeManager.GetTrade(initiatorID) != nil {
		return fmt.Errorf("initiator is already in a trade")
	}

	if ts.tradeManager.GetTrade(targetID) != nil {
		return fmt.Errorf("target is already in a trade")
	}

	// TODO: Add additional validation when entity system is available:
	// - Verify both entities exist and are online
	// - Check if entities are in the same zone
	// - Verify entities are within trade range
	// - Check for any trade restrictions or bans

	return nil
}

// ForceCompleteTrade completes a trade regardless of acceptance state (admin function)
func (ts *TradeService) ForceCompleteTrade(entityID int32) error {
	trade := ts.tradeManager.GetTrade(entityID)
	if trade == nil {
		return fmt.Errorf("entity is not in a trade")
	}

	// Force both participants to accepted state
	trade.trader1.HasAccepted = true
	trade.trader2.HasAccepted = true

	// Complete the trade
	completed, err := trade.SetTradeAccepted(entityID)
	if err != nil {
		return err
	}

	if completed {
		ts.tradeManager.RemoveTrade(trade.GetTrader1ID())
	}

	return nil
}

// ForceCancelTrade cancels a trade regardless of state (admin function)
func (ts *TradeService) ForceCancelTrade(entityID int32, reason string) error {
	trade := ts.tradeManager.GetTrade(entityID)
	if trade == nil {
		return fmt.Errorf("entity is not in a trade")
	}

	// TODO: Log the forced cancellation with reason when logging system is available

	err := trade.CancelTrade(entityID)
	if err != nil {
		return err
	}

	ts.tradeManager.RemoveTrade(trade.GetTrader1ID())

	return nil
}

// Shutdown gracefully shuts down the trade service
func (ts *TradeService) Shutdown() {
	ts.mutex.Lock()
	defer ts.mutex.Unlock()

	// TODO: Cancel all active trades with appropriate notifications
	// For now, just clear the trade manager
	ts.tradeManager = NewTradeManager()
}

// PlaceholderEntity is a temporary implementation until the entity system is available
type PlaceholderEntity struct {
	ID           int32
	Name         string
	IsPlayerFlag bool
	IsBotFlag    bool
	CoinsAmount  int64
	ClientVer    int32
}

// GetID returns the entity ID
func (pe *PlaceholderEntity) GetID() int32 {
	return pe.ID
}

// GetName returns the entity name
func (pe *PlaceholderEntity) GetName() string {
	if pe.Name == "" {
		return fmt.Sprintf("Entity_%d", pe.ID)
	}
	return pe.Name
}

// IsPlayer returns whether this is a player entity
func (pe *PlaceholderEntity) IsPlayer() bool {
	return pe.IsPlayerFlag
}

// IsBot returns whether this is a bot entity
func (pe *PlaceholderEntity) IsBot() bool {
	return pe.IsBotFlag
}

// HasCoins checks if the entity has sufficient coins
func (pe *PlaceholderEntity) HasCoins(amount int64) bool {
	return pe.CoinsAmount >= amount
}

// GetClientVersion returns the client version
func (pe *PlaceholderEntity) GetClientVersion() int32 {
	if pe.ClientVer == 0 {
		return 1000 // Default to newer client
	}
	return pe.ClientVer
}

// PlaceholderItem is a temporary implementation until the item system is available
type PlaceholderItem struct {
	ID           int32
	Name         string
	Quantity     int32
	IconID       int32
	NoTradeFlag  bool
	HeirloomFlag bool
	AttunedFlag  bool
	CreatedTime  time.Time
	GroupIDs     []int32
}

// GetID returns the item ID
func (pi *PlaceholderItem) GetID() int32 {
	return pi.ID
}

// GetName returns the item name
func (pi *PlaceholderItem) GetName() string {
	if pi.Name == "" {
		return fmt.Sprintf("Item_%d", pi.ID)
	}
	return pi.Name
}

// GetQuantity returns the item quantity
func (pi *PlaceholderItem) GetQuantity() int32 {
	return pi.Quantity
}

// GetIcon returns the item icon ID
func (pi *PlaceholderItem) GetIcon(version int32) int32 {
	return pi.IconID
}

// IsNoTrade returns whether the item is no-trade
func (pi *PlaceholderItem) IsNoTrade() bool {
	return pi.NoTradeFlag
}

// IsHeirloom returns whether the item is heirloom
func (pi *PlaceholderItem) IsHeirloom() bool {
	return pi.HeirloomFlag
}

// IsAttuned returns whether the item is attuned
func (pi *PlaceholderItem) IsAttuned() bool {
	return pi.AttunedFlag
}

// GetCreationTime returns when the item was created
func (pi *PlaceholderItem) GetCreationTime() time.Time {
	return pi.CreatedTime
}

// GetGroupCharacterIDs returns the group character IDs for heirloom sharing
func (pi *PlaceholderItem) GetGroupCharacterIDs() []int32 {
	return pi.GroupIDs
}
