package transmute

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

// Manager provides high-level management of the transmutation system
type Manager struct {
	transmuter     *Transmuter
	database       Database
	requestTimeout time.Duration
	cleanupTicker  *time.Ticker
	mutex          sync.RWMutex

	// Statistics
	totalTransmutes      int64
	successfulTransmutes int64
	failedTransmutes     int64
	materialCounts       map[int32]int64 // Material ID -> count produced
}

// NewManager creates a new transmutation manager
func NewManager(database Database, itemMaster ItemMaster, spellMaster SpellMaster, packetBuilder PacketBuilder) *Manager {
	transmuter := NewTransmuter(itemMaster, spellMaster, packetBuilder)

	manager := &Manager{
		transmuter:     transmuter,
		database:       database,
		requestTimeout: 5 * time.Minute, // Requests expire after 5 minutes
		materialCounts: make(map[int32]int64),
	}

	// Start cleanup routine
	manager.cleanupTicker = time.NewTicker(1 * time.Minute)
	go manager.cleanupRoutine()

	return manager
}

// Initialize loads transmuting data from database
func (m *Manager) Initialize() error {
	return m.transmuter.LoadTransmutingTiers(m.database)
}

// CreateItemRequest creates a new transmutation item selection request
func (m *Manager) CreateItemRequest(client Client, player Player) (int32, error) {
	return m.transmuter.CreateItemRequest(client, player)
}

// HandleItemResponse handles the player's item selection response
func (m *Manager) HandleItemResponse(client Client, player Player, requestID int32, itemID int32) error {
	return m.transmuter.HandleItemResponse(client, player, requestID, itemID)
}

// HandleConfirmResponse handles the player's confirmation response
func (m *Manager) HandleConfirmResponse(client Client, player Player, itemID int32) error {
	return m.transmuter.HandleConfirmResponse(client, player, itemID)
}

// CompleteTransmutation completes the transmutation process
func (m *Manager) CompleteTransmutation(client Client, player Player) error {
	m.mutex.Lock()
	m.totalTransmutes++
	m.mutex.Unlock()

	err := m.transmuter.CompleteTransmutation(client, player)

	m.mutex.Lock()
	if err != nil {
		m.failedTransmutes++
	} else {
		m.successfulTransmutes++
	}
	m.mutex.Unlock()

	return err
}

// IsItemTransmutable checks if an item can be transmuted
func (m *Manager) IsItemTransmutable(item Item) bool {
	return m.transmuter.IsItemTransmutable(item)
}

// GetTransmutingTiers returns the current transmuting tiers
func (m *Manager) GetTransmutingTiers() []*TransmutingTier {
	return m.transmuter.GetTransmutingTiers()
}

// ReloadTransmutingTiers reloads transmuting tiers from database
func (m *Manager) ReloadTransmutingTiers() error {
	return m.transmuter.LoadTransmutingTiers(m.database)
}

// GetStatistics returns transmutation statistics
func (m *Manager) GetStatistics() map[string]interface{} {
	m.mutex.RLock()
	defer m.mutex.RUnlock()

	stats := make(map[string]interface{})
	stats["total_transmutes"] = m.totalTransmutes
	stats["successful_transmutes"] = m.successfulTransmutes
	stats["failed_transmutes"] = m.failedTransmutes

	if m.totalTransmutes > 0 {
		stats["success_rate"] = float64(m.successfulTransmutes) / float64(m.totalTransmutes) * 100
	}

	// Copy material counts
	materialStats := make(map[int32]int64)
	for matID, count := range m.materialCounts {
		materialStats[matID] = count
	}
	stats["material_counts"] = materialStats

	return stats
}

// RecordMaterialProduced records that a material was produced (for statistics)
func (m *Manager) RecordMaterialProduced(materialID int32, count int32) {
	m.mutex.Lock()
	defer m.mutex.Unlock()

	m.materialCounts[materialID] += int64(count)
}

// GetMaterialProductionCount returns how many of a material have been produced
func (m *Manager) GetMaterialProductionCount(materialID int32) int64 {
	m.mutex.RLock()
	defer m.mutex.RUnlock()

	return m.materialCounts[materialID]
}

// ResetStatistics resets all statistics
func (m *Manager) ResetStatistics() {
	m.mutex.Lock()
	defer m.mutex.Unlock()

	m.totalTransmutes = 0
	m.successfulTransmutes = 0
	m.failedTransmutes = 0
	m.materialCounts = make(map[int32]int64)
}

// ValidateTransmutingSetup validates that all transmuting tiers are properly configured
func (m *Manager) ValidateTransmutingSetup() []string {
	tiers := m.GetTransmutingTiers()
	issues := make([]string, 0)

	if len(tiers) == 0 {
		issues = append(issues, "No transmuting tiers configured")
		return issues
	}

	// Check for gaps or overlaps in level ranges
	for i, tier := range tiers {
		if tier.MinLevel <= 0 {
			issues = append(issues, fmt.Sprintf("Tier %d has invalid min level: %d", i, tier.MinLevel))
		}

		if tier.MaxLevel < tier.MinLevel {
			issues = append(issues, fmt.Sprintf("Tier %d has max level (%d) less than min level (%d)",
				i, tier.MaxLevel, tier.MinLevel))
		}

		if tier.FragmentID <= 0 {
			issues = append(issues, fmt.Sprintf("Tier %d has invalid fragment ID: %d", i, tier.FragmentID))
		}

		if tier.PowderID <= 0 {
			issues = append(issues, fmt.Sprintf("Tier %d has invalid powder ID: %d", i, tier.PowderID))
		}

		if tier.InfusionID <= 0 {
			issues = append(issues, fmt.Sprintf("Tier %d has invalid infusion ID: %d", i, tier.InfusionID))
		}

		if tier.ManaID <= 0 {
			issues = append(issues, fmt.Sprintf("Tier %d has invalid mana ID: %d", i, tier.ManaID))
		}

		// Check for overlaps with other tiers
		for j, otherTier := range tiers {
			if i != j {
				if tier.MinLevel <= otherTier.MaxLevel && tier.MaxLevel >= otherTier.MinLevel {
					issues = append(issues, fmt.Sprintf("Tier %d (levels %d-%d) overlaps with tier %d (levels %d-%d)",
						i, tier.MinLevel, tier.MaxLevel, j, otherTier.MinLevel, otherTier.MaxLevel))
				}
			}
		}
	}

	return issues
}

// GetTierForItemLevel returns the transmuting tier for a given item level
func (m *Manager) GetTierForItemLevel(itemLevel int32) *TransmutingTier {
	tiers := m.GetTransmutingTiers()

	for _, tier := range tiers {
		if tier.MinLevel <= itemLevel && tier.MaxLevel >= itemLevel {
			return tier
		}
	}

	return nil
}

// GetTransmutableItems returns all transmutable items from a player's inventory
func (m *Manager) GetTransmutableItems(player Player) []Item {
	itemList := player.GetItemList()
	transmutable := make([]Item, 0)

	for _, item := range itemList {
		if item != nil && m.IsItemTransmutable(item) {
			transmutable = append(transmutable, item)
		}
	}

	return transmutable
}

// CalculateRequiredSkill calculates the transmuting skill required for an item
func (m *Manager) CalculateRequiredSkill(item Item) int32 {
	itemLevel := item.GetAdventureDefaultLevel()
	if itemLevel <= 5 {
		return 0
	}
	return (itemLevel - 5) * 5
}

// CanPlayerTransmuteItem checks if a player can transmute a specific item
func (m *Manager) CanPlayerTransmuteItem(player Player, item Item) (bool, string) {
	if !m.IsItemTransmutable(item) {
		return false, fmt.Sprintf("%s is not transmutable", item.GetName())
	}

	requiredSkill := m.CalculateRequiredSkill(item)
	skill := player.GetSkillByName("Transmuting")

	currentSkill := int32(0)
	if skill != nil {
		currentSkill = skill.GetCurrentValue() + player.GetStat(ItemStatTransmuting)
	}

	if currentSkill < requiredSkill {
		return false, fmt.Sprintf("Need %d Transmuting skill, have %d", requiredSkill, currentSkill)
	}

	return true, ""
}

// cleanupRoutine runs periodically to cleanup expired requests
func (m *Manager) cleanupRoutine() {
	for range m.cleanupTicker.C {
		// TODO: Implement request cleanup based on timestamps
		// For now, this is a placeholder for future cleanup logic
		// In a full implementation, we'd track request timestamps
		// and remove requests older than the timeout period
	}
}

// Shutdown gracefully shuts down the manager
func (m *Manager) Shutdown() {
	if m.cleanupTicker != nil {
		m.cleanupTicker.Stop()
	}
}

// ProcessCommand handles transmutation-related commands
func (m *Manager) ProcessCommand(command string, args []string, client Client, player Player) (string, error) {
	switch command {
	case "stats":
		return m.handleStatsCommand(args)
	case "validate":
		return m.handleValidateCommand(args)
	case "reload":
		return m.handleReloadCommand(args)
	case "tiers":
		return m.handleTiersCommand(args)
	default:
		return "", fmt.Errorf("unknown transmute command: %s", command)
	}
}

// handleStatsCommand shows transmutation statistics
func (m *Manager) handleStatsCommand(args []string) (string, error) {
	stats := m.GetStatistics()

	result := "Transmutation Statistics:\n"
	result += fmt.Sprintf("Total Transmutes: %d\n", stats["total_transmutes"])
	result += fmt.Sprintf("Successful: %d\n", stats["successful_transmutes"])
	result += fmt.Sprintf("Failed: %d\n", stats["failed_transmutes"])

	if successRate, exists := stats["success_rate"]; exists {
		result += fmt.Sprintf("Success Rate: %.1f%%\n", successRate)
	}

	return result, nil
}

// handleValidateCommand validates the transmuting setup
func (m *Manager) handleValidateCommand(args []string) (string, error) {
	issues := m.ValidateTransmutingSetup()

	if len(issues) == 0 {
		return "Transmuting setup is valid.", nil
	}

	result := fmt.Sprintf("Found %d issues with transmuting setup:\n", len(issues))
	for i, issue := range issues {
		result += fmt.Sprintf("%d. %s\n", i+1, issue)
	}

	return result, nil
}

// handleReloadCommand reloads transmuting data
func (m *Manager) handleReloadCommand(args []string) (string, error) {
	err := m.ReloadTransmutingTiers()
	if err != nil {
		return "", fmt.Errorf("failed to reload transmuting tiers: %w", err)
	}

	return "Transmuting tiers reloaded successfully.", nil
}

// handleTiersCommand shows transmuting tier information
func (m *Manager) handleTiersCommand(args []string) (string, error) {
	tiers := m.GetTransmutingTiers()

	if len(tiers) == 0 {
		return "No transmuting tiers configured.", nil
	}

	result := fmt.Sprintf("Transmuting Tiers (%d):\n", len(tiers))
	for i, tier := range tiers {
		result += fmt.Sprintf("%d. Levels %d-%d: Fragment(%d) Powder(%d) Infusion(%d) Mana(%d)\n",
			i+1, tier.MinLevel, tier.MaxLevel, tier.FragmentID, tier.PowderID, tier.InfusionID, tier.ManaID)
	}

	return result, nil
}

// Constants for stat types - these would typically be defined elsewhere
const (
	ItemStatTransmuting = 1 // Placeholder - actual value depends on stat system
)
