package tradeskills

import (
	"fmt"
	"time"
)

// PlayerManager defines the interface for player-related operations needed by tradeskills.
type PlayerManager interface {
	// GetPlayer retrieves player information by ID
	GetPlayer(playerID uint32) (Player, error)

	// GetPlayerTarget gets the current target of a player
	GetPlayerTarget(playerID uint32) (Spawn, error)

	// SetPlayerVisualState sets the visual animation state for a player
	SetPlayerVisualState(playerID uint32, animationID uint32) error

	// SendMessageToPlayer sends a message to a player
	SendMessageToPlayer(playerID uint32, channel int8, message string) error
}

// ItemManager defines the interface for item-related operations needed by tradeskills.
type ItemManager interface {
	// GetItem retrieves item information by ID
	GetItem(itemID uint32) (Item, error)

	// GetPlayerItem gets a specific item from a player's inventory
	GetPlayerItem(playerID uint32, uniqueID uint32) (Item, error)

	// GetPlayerItemsByID gets all items of a specific type from player inventory
	GetPlayerItemsByID(playerID uint32, itemID uint32) ([]Item, error)

	// ConsumePlayerItems removes items from player inventory
	ConsumePlayerItems(playerID uint32, components []ComponentUsage) error

	// GiveItemToPlayer adds an item to player inventory
	GiveItemToPlayer(playerID uint32, itemID uint32, quantity int16, creator string) error

	// LockPlayerItems locks items in player inventory for crafting
	LockPlayerItems(playerID uint32, components []ComponentUsage) error

	// UnlockPlayerItems unlocks previously locked items
	UnlockPlayerItems(playerID uint32, components []ComponentUsage) error
}

// RecipeManager defines the interface for recipe-related operations.
type RecipeManager interface {
	// GetRecipe retrieves recipe information by ID
	GetRecipe(recipeID uint32) (Recipe, error)

	// GetPlayerRecipe gets a player's copy of a recipe (with progress tracking)
	GetPlayerRecipe(playerID uint32, recipeID uint32) (PlayerRecipe, error)

	// UpdatePlayerRecipe updates a player's recipe progress
	UpdatePlayerRecipe(playerID uint32, recipeID uint32, highestStage int8) error

	// ValidateRecipeComponents checks if player has required components
	ValidateRecipeComponents(playerID uint32, recipeID uint32, components []ComponentUsage) error
}

// SpellManager defines the interface for spell-related operations needed by tradeskills.
type SpellManager interface {
	// GetPlayerTradeskillSpells gets tradeskill spells for a player
	GetPlayerTradeskillSpells(playerID uint32, technique uint32) ([]Spell, error)

	// LockTradeskillSpells locks tradeskill spells for a player
	LockTradeskillSpells(playerID uint32) error

	// UnlockTradeskillSpells unlocks tradeskill spells for a player
	UnlockTradeskillSpells(playerID uint32) error
}

// ZoneManager defines the interface for zone-related operations.
type ZoneManager interface {
	// GetSpawn retrieves spawn information by ID
	GetSpawn(spawnID uint32) (Spawn, error)

	// PlayAnimation plays an animation for a spawn
	PlayAnimation(spawnID uint32, animationID uint32) error

	// ValidateCraftingTable checks if a spawn is a valid crafting table for a recipe
	ValidateCraftingTable(spawnID uint32, requiredDevice string) error
}

// ExperienceManager defines the interface for experience-related operations.
type ExperienceManager interface {
	// CalculateTradeskillXP calculates XP for a recipe level
	CalculateTradeskillXP(playerID uint32, recipeLevel int16) (float32, error)

	// AwardTradeskillXP gives tradeskill XP to a player
	AwardTradeskillXP(playerID uint32, xp int32) (bool, error) // Returns true if level changed

	// GetPlayerTradeskillLevel gets a player's current tradeskill level
	GetPlayerTradeskillLevel(playerID uint32) (int16, error)
}

// QuestManager defines the interface for quest-related operations.
type QuestManager interface {
	// CheckCraftingQuests checks for quest updates related to crafting
	CheckCraftingQuests(playerID uint32, itemID uint32, quantity int8) error
}

// RuleManager defines the interface for rules/configuration access.
type RuleManager interface {
	// GetTradeskillSuccessChance gets the base success chance percentage
	GetTradeskillSuccessChance() float32

	// GetTradeskillCritSuccessChance gets the critical success chance percentage
	GetTradeskillCritSuccessChance() float32

	// GetTradeskillFailChance gets the base failure chance percentage
	GetTradeskillFailChance() float32

	// GetTradeskillCritFailChance gets the critical failure chance percentage
	GetTradeskillCritFailChance() float32

	// GetTradeskillEventChance gets the event trigger chance percentage
	GetTradeskillEventChance() float32
}

// Data structures used by the interfaces

// Player represents a player in the game.
type Player struct {
	ID                 uint32
	Name               string
	CurrentRecipe      uint32
	TradeskillLevel    int16
	SuccessModifier    int16 // Stat bonus to success chance
	ProgressModifier   int16 // Stat bonus to progress
	DurabilityModifier int16 // Stat bonus to durability
}

// Item represents an item in the game.
type Item struct {
	ID         uint32
	UniqueID   uint32
	Name       string
	Icon       uint32
	Count      int16
	Creator    string
	StackCount int16
}

// Recipe represents a crafting recipe.
type Recipe struct {
	ID                       uint32
	Name                     string
	Level                    int16
	Tier                     int8
	Technique                uint32
	Device                   string
	ProductID                uint32
	ProductQuantity          int16
	PrimaryComponentTitle    string
	PrimaryComponentQuantity int16
	Build1ComponentTitle     string
	Build1ComponentQuantity  int16
	Build2ComponentTitle     string
	Build2ComponentQuantity  int16
	Build3ComponentTitle     string
	Build3ComponentQuantity  int16
	Build4ComponentTitle     string
	Build4ComponentQuantity  int16
	FuelComponentTitle       string
	FuelComponentQuantity    int16
	Components               map[int8][]uint32       // Component slot -> item IDs
	Products                 map[int8]*RecipeProduct // Stage -> product
}

// PlayerRecipe represents a player's version of a recipe with progress tracking.
type PlayerRecipe struct {
	RecipeID     uint32
	PlayerID     uint32
	HighestStage int8 // Bitmask of completed stages
}

// RecipeProduct represents a product from a recipe stage.
type RecipeProduct struct {
	ProductID    uint32
	ProductQty   int16
	ByproductID  uint32
	ByproductQty int16
}

// Spell represents a spell/ability.
type Spell struct {
	ID            uint32
	Name          string
	Icon          int16
	TechniqueSlot int8 // Location index for tradeskill UI
}

// Spawn represents a spawn (NPC, object, etc.) in the game world.
type Spawn struct {
	ID       uint32
	Name     string
	IsObject bool
	DeviceID uint32 // For crafting tables
}

// TradeskillSystemAdapter provides a high-level interface to the complete tradeskill system.
type TradeskillSystemAdapter struct {
	manager           *TradeskillManager
	eventsList        *MasterTradeskillEventsList
	database          DatabaseService
	packetBuilder     PacketBuilder
	playerManager     PlayerManager
	itemManager       ItemManager
	recipeManager     RecipeManager
	spellManager      SpellManager
	zoneManager       ZoneManager
	experienceManager ExperienceManager
	questManager      QuestManager
	ruleManager       RuleManager
}

// NewTradeskillSystemAdapter creates a new system adapter with all dependencies.
func NewTradeskillSystemAdapter(
	manager *TradeskillManager,
	eventsList *MasterTradeskillEventsList,
	database DatabaseService,
	packetBuilder PacketBuilder,
	playerManager PlayerManager,
	itemManager ItemManager,
	recipeManager RecipeManager,
	spellManager SpellManager,
	zoneManager ZoneManager,
	experienceManager ExperienceManager,
	questManager QuestManager,
	ruleManager RuleManager,
) *TradeskillSystemAdapter {
	return &TradeskillSystemAdapter{
		manager:           manager,
		eventsList:        eventsList,
		database:          database,
		packetBuilder:     packetBuilder,
		playerManager:     playerManager,
		itemManager:       itemManager,
		recipeManager:     recipeManager,
		spellManager:      spellManager,
		zoneManager:       zoneManager,
		experienceManager: experienceManager,
		questManager:      questManager,
		ruleManager:       ruleManager,
	}
}

// Initialize sets up the tradeskill system (loads events, updates config, etc.).
func (tsa *TradeskillSystemAdapter) Initialize() error {
	// Load tradeskill events from database
	err := tsa.database.LoadTradeskillEvents(tsa.eventsList)
	if err != nil {
		return err
	}

	// Update manager configuration from rules
	err = tsa.updateManagerConfig()
	if err != nil {
		return err
	}

	return nil
}

// StartCrafting begins a crafting session with full validation and setup.
func (tsa *TradeskillSystemAdapter) StartCrafting(playerID uint32, recipeID uint32, components []ComponentUsage) error {
	// Get player info
	_, err := tsa.playerManager.GetPlayer(playerID)
	if err != nil {
		return err
	}

	// Get target (crafting table)
	target, err := tsa.playerManager.GetPlayerTarget(playerID)
	if err != nil {
		return err
	}

	// Get recipe
	recipe, err := tsa.recipeManager.GetRecipe(recipeID)
	if err != nil {
		return err
	}

	// Validate crafting table
	err = tsa.zoneManager.ValidateCraftingTable(target.ID, recipe.Device)
	if err != nil {
		return err
	}

	// Validate components
	err = tsa.recipeManager.ValidateRecipeComponents(playerID, recipeID, components)
	if err != nil {
		return err
	}

	// Lock inventory items
	err = tsa.itemManager.LockPlayerItems(playerID, components)
	if err != nil {
		return err
	}

	// Send recipe UI packet
	err = tsa.packetBuilder.SendCreateFromRecipe(playerID, recipeID)
	if err != nil {
		tsa.itemManager.UnlockPlayerItems(playerID, components) // Cleanup on error
		return err
	}

	// Send item creation UI packet
	err = tsa.packetBuilder.SendItemCreationUI(playerID, recipeID)
	if err != nil {
		tsa.itemManager.UnlockPlayerItems(playerID, components) // Cleanup on error
		return err
	}

	// Start crafting session
	request := CraftingRequest{
		PlayerID:     playerID,
		RecipeID:     recipeID,
		TableSpawnID: target.ID,
		Components:   components,
		Quantity:     1, // TODO: Support mass production
	}

	err = tsa.manager.BeginCrafting(request)
	if err != nil {
		tsa.itemManager.UnlockPlayerItems(playerID, components) // Cleanup on error
		return err
	}

	// Unlock tradeskill spells
	err = tsa.spellManager.UnlockTradeskillSpells(playerID)
	if err != nil {
		// Not critical, just log warning
		tsa.playerManager.SendMessageToPlayer(playerID, 1, "Warning: Failed to unlock tradeskill spells")
	}

	return nil
}

// StopCrafting ends a crafting session with full cleanup and rewards.
func (tsa *TradeskillSystemAdapter) StopCrafting(playerID uint32) error {
	// Get tradeskill session
	tradeskill := tsa.manager.GetTradeskill(playerID)
	if tradeskill == nil {
		return nil // Not crafting
	}

	// Calculate completion stage and rewards
	err := tsa.processCompletionRewards(playerID, tradeskill)
	if err != nil {
		// Log error but continue with cleanup
		tsa.playerManager.SendMessageToPlayer(playerID, 1, "Warning: Failed to process completion rewards")
	}

	// Stop the crafting session
	err = tsa.manager.StopCrafting(playerID)
	if err != nil {
		return err
	}

	// Send stop crafting packet
	err = tsa.packetBuilder.StopCrafting(playerID)
	if err != nil {
		return err
	}

	// Unlock inventory items
	err = tsa.itemManager.UnlockPlayerItems(playerID, tradeskill.UsedComponents)
	if err != nil {
		// Log warning but continue
		tsa.playerManager.SendMessageToPlayer(playerID, 1, "Warning: Failed to unlock inventory items")
	}

	// Lock tradeskill spells
	err = tsa.spellManager.LockTradeskillSpells(playerID)
	if err != nil {
		// Not critical, just log warning
		tsa.playerManager.SendMessageToPlayer(playerID, 1, "Warning: Failed to lock tradeskill spells")
	}

	// Reset player visual state
	err = tsa.playerManager.SetPlayerVisualState(playerID, 0)
	if err != nil {
		// Not critical, just log warning
		tsa.playerManager.SendMessageToPlayer(playerID, 1, "Warning: Failed to reset visual state")
	}

	return nil
}

// ProcessCraftingUpdates handles periodic processing with full integration.
func (tsa *TradeskillSystemAdapter) ProcessCraftingUpdates() {
	// Run the core manager processing
	tsa.manager.Process()

	// TODO: Handle any additional processing needed
	// This could include sending update packets, triggering events, etc.
}

// HandleEventCounter processes a player's attempt to counter a tradeskill event.
func (tsa *TradeskillSystemAdapter) HandleEventCounter(playerID uint32, spellIcon int16) error {
	request := EventCounterRequest{
		PlayerID:  playerID,
		SpellIcon: spellIcon,
	}

	// Process the counter attempt
	err := tsa.manager.CheckTradeskillEvent(request)
	if err != nil {
		return err
	}

	// Get the result and send reaction packet
	tradeskill := tsa.manager.GetTradeskill(playerID)
	if tradeskill != nil && tradeskill.EventChecked {
		err = tsa.packetBuilder.CounterReaction(playerID, tradeskill.EventCountered)
		if err != nil {
			return err
		}

		// Send message to player
		action := "failed to counter"
		if tradeskill.EventCountered {
			action = "successfully countered"
		}

		if tradeskill.CurrentEvent != nil {
			message := fmt.Sprintf("You %s %s.", action, tradeskill.CurrentEvent.Name)
			tsa.playerManager.SendMessageToPlayer(playerID, 2, message) // CHANNEL_NARRATIVE
		}
	}

	return nil
}

// updateManagerConfig updates the manager with current rule values.
func (tsa *TradeskillSystemAdapter) updateManagerConfig() error {
	critFail := tsa.ruleManager.GetTradeskillCritFailChance()
	critSuccess := tsa.ruleManager.GetTradeskillCritSuccessChance()
	fail := tsa.ruleManager.GetTradeskillFailChance()
	success := tsa.ruleManager.GetTradeskillSuccessChance()
	eventChance := tsa.ruleManager.GetTradeskillEventChance()

	return tsa.manager.UpdateConfiguration(critFail, critSuccess, fail, success, eventChance)
}

// processCompletionRewards handles giving rewards when crafting completes.
func (tsa *TradeskillSystemAdapter) processCompletionRewards(playerID uint32, ts *Tradeskill) error {
	// Get recipe
	recipe, err := tsa.recipeManager.GetRecipe(ts.RecipeID)
	if err != nil {
		return err
	}

	// Determine completion stage based on progress and durability
	stage := tsa.calculateCompletionStage(ts.CurrentProgress, ts.CurrentDurability)

	// Give appropriate rewards for the stage
	if stage >= 0 && recipe.Products != nil {
		if product, exists := recipe.Products[stage]; exists {
			// Give main product
			if product.ProductID > 0 {
				err = tsa.itemManager.GiveItemToPlayer(playerID, product.ProductID, product.ProductQty, "")
				if err != nil {
					return err
				}

				// Update quests
				tsa.questManager.CheckCraftingQuests(playerID, product.ProductID, int8(product.ProductQty))
			}

			// Give byproduct if any
			if product.ByproductID > 0 {
				err = tsa.itemManager.GiveItemToPlayer(playerID, product.ByproductID, product.ByproductQty, "")
				if err != nil {
					return err
				}

				// Update quests
				tsa.questManager.CheckCraftingQuests(playerID, product.ByproductID, int8(product.ByproductQty))
			}
		}
	}

	// Award tradeskill experience
	baseXP, err := tsa.experienceManager.CalculateTradeskillXP(playerID, recipe.Level)
	if err == nil && baseXP > 0 {
		// Apply stage-based XP reduction
		xpMultiplier := tsa.getXPMultiplierForStage(stage)
		finalXP := int32(baseXP * xpMultiplier)

		if finalXP > 0 {
			levelChanged, err := tsa.experienceManager.AwardTradeskillXP(playerID, finalXP)
			if err == nil {
				// Notify player of XP gain
				message := fmt.Sprintf("You gain %d Tradeskill XP!", finalXP)
				tsa.playerManager.SendMessageToPlayer(playerID, 3, message) // CHANNEL_REWARD

				// Handle level change if needed
				if levelChanged {
					// TODO: Handle tradeskill level up
				}
			}
		}
	}

	// Update player recipe progress
	playerRecipe, err := tsa.recipeManager.GetPlayerRecipe(playerID, ts.RecipeID)
	if err == nil {
		newStage := tsa.updatePlayerRecipeStage(playerRecipe.HighestStage, stage)
		if newStage != playerRecipe.HighestStage {
			tsa.recipeManager.UpdatePlayerRecipe(playerID, ts.RecipeID, newStage)
		}
	}

	// Play success/failure animation
	technique := recipe.Technique
	clientVersion := int16(1200) // TODO: Get actual client version

	var animationID uint32
	if stage == 4 { // Full completion
		animationID = tsa.manager.GetTechniqueSuccessAnim(clientVersion, technique)
	} else {
		animationID = tsa.manager.GetTechniqueFailureAnim(clientVersion, technique)
	}

	if animationID > 0 {
		tsa.zoneManager.PlayAnimation(playerID, animationID)
	}

	return nil
}

// calculateCompletionStage determines the completion stage based on progress/durability.
func (tsa *TradeskillSystemAdapter) calculateCompletionStage(progress, durability int32) int8 {
	if durability >= 800 && progress >= 1000 {
		return 4 // Perfect completion
	} else if (durability >= 200 && durability < 800 && progress >= 800) || (durability >= 800 && progress >= 800 && progress < 1000) {
		return 3 // Stage 3
	} else if (durability < 200 && progress >= 600) || (durability >= 200 && progress >= 600 && progress < 800) {
		return 2 // Stage 2
	} else if progress >= 400 && progress < 600 {
		return 1 // Stage 1
	} else if progress < 400 {
		return 0 // Stage 0 (fuel/byproduct)
	}

	return 0
}

// getXPMultiplierForStage returns the XP multiplier for a completion stage.
func (tsa *TradeskillSystemAdapter) getXPMultiplierForStage(stage int8) float32 {
	switch stage {
	case 4:
		return 1.0 // Full XP for perfect completion
	case 3:
		return 0.85 // 85% XP for stage 3
	case 2:
		return 0.70 // 70% XP for stage 2
	case 1:
		return 0.55 // 55% XP for stage 1
	case 0:
		return 0.0 // No XP for stage 0
	default:
		return 0.0
	}
}

// updatePlayerRecipeStage updates the player's recipe stage progress bitmask.
func (tsa *TradeskillSystemAdapter) updatePlayerRecipeStage(currentStage int8, completedStage int8) int8 {
	// Set the bit for the completed stage
	switch completedStage {
	case 1:
		if (currentStage & 1) == 0 {
			return currentStage + 1
		}
	case 2:
		if (currentStage & 2) == 0 {
			return currentStage + 2
		}
	case 3:
		if (currentStage & 4) == 0 {
			return currentStage + 4
		}
	case 4:
		if (currentStage & 8) == 0 {
			return currentStage + 8
		}
	}

	return currentStage
}

// GetSystemStats returns comprehensive statistics about the tradeskill system.
func (tsa *TradeskillSystemAdapter) GetSystemStats() map[string]interface{} {
	managerStats := tsa.manager.GetStats()
	eventsStats := tsa.eventsList.GetStats()

	return map[string]interface{}{
		"active_sessions":      managerStats.ActiveSessions,
		"recent_completions":   managerStats.RecentCompletions,
		"average_session_time": managerStats.AverageSessionTime,
		"total_events":         eventsStats.TotalEvents,
		"events_by_technique":  eventsStats.EventsByTechnique,
		"last_update":          time.Now(),
	}
}
