package trade

import (
	"fmt"
	"strings"
)

// CalculateCoins converts a total copper amount to coin denominations
// Converted from C++ Trade::CalculateCoins
func CalculateCoins(totalCopper int64) CoinAmounts {
	coins := CoinAmounts{}
	remaining := totalCopper

	// Calculate platinum (1,000,000 copper = 1 platinum)
	if remaining >= CoinsPlatinumThreshold {
		coins.Platinum = int32(remaining / CoinsPlatinumThreshold)
		remaining -= int64(coins.Platinum) * CoinsPlatinumThreshold
	}

	// Calculate gold (10,000 copper = 1 gold)
	if remaining >= CoinsGoldThreshold {
		coins.Gold = int32(remaining / CoinsGoldThreshold)
		remaining -= int64(coins.Gold) * CoinsGoldThreshold
	}

	// Calculate silver (100 copper = 1 silver)
	if remaining >= CoinsSilverThreshold {
		coins.Silver = int32(remaining / CoinsSilverThreshold)
		remaining -= int64(coins.Silver) * CoinsSilverThreshold
	}

	// Remaining is copper
	if remaining > 0 {
		coins.Copper = int32(remaining)
	}

	return coins
}

// CoinsToCopper converts coin denominations to total copper
func CoinsToCopper(coins CoinAmounts) int64 {
	total := int64(coins.Copper)
	total += int64(coins.Silver) * CoinsSilverThreshold
	total += int64(coins.Gold) * CoinsGoldThreshold
	total += int64(coins.Platinum) * CoinsPlatinumThreshold
	return total
}

// FormatCoins returns a human-readable string representation of coins
func FormatCoins(totalCopper int64) string {
	if totalCopper == 0 {
		return "0 copper"
	}

	coins := CalculateCoins(totalCopper)
	parts := make([]string, 0, 4)

	if coins.Platinum > 0 {
		parts = append(parts, fmt.Sprintf("%d platinum", coins.Platinum))
	}
	if coins.Gold > 0 {
		parts = append(parts, fmt.Sprintf("%d gold", coins.Gold))
	}
	if coins.Silver > 0 {
		parts = append(parts, fmt.Sprintf("%d silver", coins.Silver))
	}
	if coins.Copper > 0 {
		parts = append(parts, fmt.Sprintf("%d copper", coins.Copper))
	}

	return strings.Join(parts, ", ")
}

// ValidateTradeSlot checks if a slot number is valid for a participant
func ValidateTradeSlot(slot int8, maxSlots int8) bool {
	return slot >= 0 && slot < maxSlots
}

// ValidateTradeQuantity checks if a quantity is valid for trading
func ValidateTradeQuantity(quantity, available int32) bool {
	return quantity > 0 && quantity <= available
}

// FormatTradeError returns a formatted error message for trade operations
func FormatTradeError(code int32) string {
	switch code {
	case TradeResultSuccess:
		return "Success"
	case TradeResultAlreadyInTrade:
		return "Item is already in the trade"
	case TradeResultNoTrade:
		return "Item cannot be traded"
	case TradeResultHeirloom:
		return "Heirloom item cannot be traded to this player"
	case TradeResultInvalidSlot:
		return "Invalid or occupied trade slot"
	case TradeResultSlotOutOfRange:
		return "Trade slot is out of range"
	case TradeResultInsufficientQty:
		return "Insufficient quantity to trade"
	default:
		return fmt.Sprintf("Unknown trade error: %d", code)
	}
}

// GetClientMaxSlots returns the maximum trade slots for a client version
// Converted from C++ Trade constructor logic
func GetClientMaxSlots(clientVersion int32) int8 {
	if clientVersion <= 561 {
		return TradeMaxSlotsLegacy
	}
	return TradeMaxSlotsDefault
}

// IsValidTradeState checks if a trade operation is valid for the current state
func IsValidTradeState(state TradeState, operation string) bool {
	switch operation {
	case "add_item", "remove_item", "add_coins", "remove_coins", "accept":
		return state == TradeStateActive
	case "cancel":
		return state == TradeStateActive
	case "complete":
		return state == TradeStateAccepted
	default:
		return false
	}
}

// GenerateTradeLogEntry creates a log entry for trade operations
func GenerateTradeLogEntry(tradeID string, operation string, entityID int32, details interface{}) string {
	return fmt.Sprintf("[Trade:%s] %s by entity %d: %v", tradeID, operation, entityID, details)
}

// CompareTradeItems checks if two trade item infos are equivalent
func CompareTradeItems(item1, item2 TradeItemInfo) bool {
	if item1.Item == nil && item2.Item == nil {
		return item1.Quantity == item2.Quantity
	}

	if item1.Item == nil || item2.Item == nil {
		return false
	}

	return item1.Item.GetID() == item2.Item.GetID() &&
		item1.Quantity == item2.Quantity
}

// CalculateTradeValue estimates the total value of items and coins in a trade
// This is a helper function for trade balancing and analysis
func CalculateTradeValue(participant *TradeParticipant) map[string]interface{} {
	value := make(map[string]interface{})

	// Add coin value
	value["coins"] = participant.Coins
	value["coins_formatted"] = FormatCoins(participant.Coins)

	// Add item information
	itemCount := len(participant.Items)
	value["item_count"] = itemCount

	if itemCount > 0 {
		items := make([]map[string]interface{}, 0, itemCount)
		for slot, itemInfo := range participant.Items {
			itemData := make(map[string]interface{})
			itemData["slot"] = slot
			itemData["quantity"] = itemInfo.Quantity
			if itemInfo.Item != nil {
				itemData["item_id"] = itemInfo.Item.GetID()
				itemData["item_name"] = itemInfo.Item.GetName()
			}
			items = append(items, itemData)
		}
		value["items"] = items
	}

	return value
}

// ValidateTradeCompletion checks if a trade is ready to be completed
func ValidateTradeCompletion(trade *Trade) []string {
	errors := make([]string, 0)

	if trade.GetState() != TradeStateActive {
		errors = append(errors, "Trade is not in active state")
		return errors
	}

	// Check if both parties have accepted
	trader1Accepted := trade.HasAcceptedTrade(trade.GetTrader1ID())
	trader2Accepted := trade.HasAcceptedTrade(trade.GetTrader2ID())

	if !trader1Accepted {
		errors = append(errors, "Trader 1 has not accepted the trade")
	}

	if !trader2Accepted {
		errors = append(errors, "Trader 2 has not accepted the trade")
	}

	// TODO: Add additional validation when entity system is available:
	// - Verify entities still exist and are online
	// - Check inventory space for received items
	// - Validate coin amounts against actual entity wealth
	// - Check for item/trade restrictions that may have changed

	return errors
}
