using UnityEngine;
using System.Collections.Generic;
using System.Linq;

/// <summary>
/// Manages character carry capacity and item weights
/// Provides penalties for exceeding carry limits
/// </summary>
[System.Serializable]
public class CarryCapacitySystem
{
    [Header("Base Capacity Settings")]
    [Tooltip("Base carry capacity in pounds")]
    public int baseCarryCapacity = 50;

    [Tooltip("How much strength affects carry capacity")]
    public float strengthMultiplier = 5f;

    [Header("Encumbrance Thresholds")]
    [Tooltip("Light load threshold (fraction of max capacity)")]
    [Range(0f, 1f)]
    public float lightLoadThreshold = 0.33f;

    [Tooltip("Medium load threshold (fraction of max capacity)")]
    [Range(0f, 1f)]
    public float mediumLoadThreshold = 0.66f;

    [Header("Encumbrance Penalties")]
    [Tooltip("Movement speed penalty for medium load (%)")]
    [Range(0f, 1f)]
    public float mediumLoadMovementPenalty = 0.25f;

    [Tooltip("Movement speed penalty for heavy load (%)")]
    [Range(0f, 1f)]
    public float heavyLoadMovementPenalty = 0.5f;

    [Tooltip("Dexterity penalty for heavy load")]
    public int heavyLoadDexterityPenalty = 3;

    public enum EncumbranceLevel
    {
        Light,      // 0-33% capacity
        Medium,     // 34-66% capacity
        Heavy,      // 67-100% capacity
        Overloaded  // 100%+ capacity
    }

    /// <summary>
    /// Calculate maximum carry capacity for a character based on strength
    /// </summary>
    public int CalculateMaxCapacity(int strength)
    {
        return baseCarryCapacity + Mathf.RoundToInt(strength * strengthMultiplier);
    }

    /// <summary>
    /// Get current encumbrance level based on carried weight and capacity
    /// </summary>
    public EncumbranceLevel GetEncumbranceLevel(int currentWeight, int maxCapacity)
    {
        if (currentWeight > maxCapacity)
            return EncumbranceLevel.Overloaded;

        float loadRatio = (float)currentWeight / maxCapacity;

        if (loadRatio <= lightLoadThreshold)
            return EncumbranceLevel.Light;
        else if (loadRatio <= mediumLoadThreshold)
            return EncumbranceLevel.Medium;
        else
            return EncumbranceLevel.Heavy;
    }

    /// <summary>
    /// Get movement speed modifier based on encumbrance
    /// </summary>
    public float GetMovementSpeedModifier(EncumbranceLevel encumbrance)
    {
        switch (encumbrance)
        {
            case EncumbranceLevel.Light:
                return 1.0f; // No penalty
            case EncumbranceLevel.Medium:
                return 1.0f - mediumLoadMovementPenalty;
            case EncumbranceLevel.Heavy:
                return 1.0f - heavyLoadMovementPenalty;
            case EncumbranceLevel.Overloaded:
                return 0.25f; // Severe penalty for being overloaded
            default:
                return 1.0f;
        }
    }

    /// <summary>
    /// Get dexterity modifier based on encumbrance
    /// </summary>
    public int GetDexterityModifier(EncumbranceLevel encumbrance)
    {
        switch (encumbrance)
        {
            case EncumbranceLevel.Light:
            case EncumbranceLevel.Medium:
                return 0; // No penalty
            case EncumbranceLevel.Heavy:
                return -heavyLoadDexterityPenalty;
            case EncumbranceLevel.Overloaded:
                return -heavyLoadDexterityPenalty * 2; // Double penalty
            default:
                return 0;
        }
    }

    /// <summary>
    /// Get encumbrance status description
    /// </summary>
    public string GetEncumbranceDescription(EncumbranceLevel encumbrance)
    {
        switch (encumbrance)
        {
            case EncumbranceLevel.Light:
                return "Light Load - No penalties";
            case EncumbranceLevel.Medium:
                return $"Medium Load - {mediumLoadMovementPenalty * 100:F0}% movement penalty";
            case EncumbranceLevel.Heavy:
                return $"Heavy Load - {heavyLoadMovementPenalty * 100:F0}% movement, -{heavyLoadDexterityPenalty} DEX penalty";
            case EncumbranceLevel.Overloaded:
                return $"Overloaded! - Severe penalties, consider dropping items";
            default:
                return "Unknown";
        }
    }
}

/// <summary>
/// Component for managing a character's carry capacity and current load
/// Attach to Character objects that need inventory weight management
/// </summary>
public class CharacterCarryCapacity : MonoBehaviour
{
    [Header("Carry Capacity System")]
    public CarryCapacitySystem carrySystem = new CarryCapacitySystem();

    [Header("Current Load Info (Read-Only)")]
    [SerializeField] private int currentWeight = 0;
    [SerializeField] private int maxCapacity = 0;
    [SerializeField] private CarryCapacitySystem.EncumbranceLevel currentEncumbrance = CarryCapacitySystem.EncumbranceLevel.Light;

    [Header("Debug")]
    public bool showDebugInfo = true;

    private Character character;
    private Inventory inventory;

    // Events
    public event System.Action<CarryCapacitySystem.EncumbranceLevel> OnEncumbranceChanged;

    void Start()
    {
        character = GetComponent<Character>();
        inventory = GetComponent<Inventory>();

        if (character == null)
        {
            Debug.LogError($"CharacterCarryCapacity requires a Character component on {gameObject.name}");
            enabled = false;
            return;
        }

        UpdateCapacity();
    }

    /// <summary>
    /// Update maximum capacity based on current strength
    /// </summary>
    public void UpdateCapacity()
    {
        if (character == null) return;

        maxCapacity = carrySystem.CalculateMaxCapacity(character.Strength);
        UpdateCurrentWeight();

        if (showDebugInfo)
            Debug.Log($"📦 {character.CharacterName} capacity: {currentWeight}/{maxCapacity} lbs ({currentEncumbrance})");
    }

    /// <summary>
    /// Update current weight by calculating all carried items
    /// </summary>
    public void UpdateCurrentWeight()
    {
        currentWeight = CalculateTotalWeight();

        var previousEncumbrance = currentEncumbrance;
        currentEncumbrance = carrySystem.GetEncumbranceLevel(currentWeight, maxCapacity);

        if (previousEncumbrance != currentEncumbrance)
        {
            OnEncumbranceChanged?.Invoke(currentEncumbrance);

            if (showDebugInfo)
                Debug.Log($"📦 {character.CharacterName} encumbrance changed to: {carrySystem.GetEncumbranceDescription(currentEncumbrance)}");
        }
    }

    /// <summary>
    /// Calculate total weight of all carried items
    /// </summary>
    private int CalculateTotalWeight()
    {
        int totalWeight = 0;

        // Calculate inventory weight if available
        if (inventory != null)
        {
            totalWeight += CalculateInventoryWeight();
        }

        // Calculate equipped item weight
        totalWeight += CalculateEquippedWeight();

        return totalWeight;
    }

    /// <summary>
    /// Calculate weight of items in inventory
    /// </summary>
    private int CalculateInventoryWeight()
    {
        int weight = 0;

        // Weapons
        foreach (var slot in inventory.Weapons)
        {
            if (slot.item is WeaponItem weapon)
            {
                weight += GetItemWeight(weapon) * slot.quantity;
            }
        }

        // Armor
        foreach (var slot in inventory.Armor)
        {
            if (slot.item is ArmorItem armor && !slot.isEquipped) // Don't count equipped armor twice
            {
                weight += GetItemWeight(armor) * slot.quantity;
            }
        }

        // Miscellaneous items
        foreach (var slot in inventory.Miscellaneous)
        {
            if (slot.item is MiscellaneousItem misc)
            {
                weight += GetItemWeight(misc) * slot.quantity;
            }
        }

        return weight;
    }

    /// <summary>
    /// Calculate weight of equipped items
    /// </summary>
    private int CalculateEquippedWeight()
    {
        int weight = 0;

        if (inventory != null)
        {
            // Equipped weapon
            if (inventory.EquippedWeapon != null)
            {
                weight += GetItemWeight(inventory.EquippedWeapon);
            }

            // Equipped armor
            var equippedArmor = inventory.GetEquippedArmor();
            foreach (var armor in equippedArmor)
            {
                weight += GetItemWeight(armor);
            }
        }

        return weight;
    }

    /// <summary>
    /// Get weight of a specific item (with fallback values)
    /// </summary>
    private int GetItemWeight(Item item)
    {
        // TODO: When items get weight properties, use those
        // For now, use reasonable defaults based on item type

        if (item is WeaponItem weapon)
        {
            return GetWeaponWeight(weapon.itemName);
        }
        else if (item is ArmorItem armor)
        {
            return GetArmorWeight(armor.itemName, armor.armorType);
        }
        else if (item is MiscellaneousItem misc)
        {
            return GetMiscWeight(misc.itemName);
        }

        return 1; // Default weight
    }

    /// <summary>
    /// Get weapon weight based on name/type
    /// </summary>
    private int GetWeaponWeight(string weaponName)
    {
        string lower = weaponName.ToLower();

        if (lower.Contains("dagger") || lower.Contains("knife"))
            return 1;
        else if (lower.Contains("sword") || lower.Contains("axe"))
            return 3;
        else if (lower.Contains("bow"))
            return 2;
        else if (lower.Contains("staff") || lower.Contains("wand"))
            return 2;
        else if (lower.Contains("hammer") || lower.Contains("mace"))
            return 4;
        else if (lower.Contains("fist") || lower.Contains("unarmed"))
            return 0;

        return 3; // Default sword weight
    }

    /// <summary>
    /// Get armor weight based on type
    /// </summary>
    private int GetArmorWeight(string armorName, ArmorType armorType)
    {
        switch (armorType)
        {
            case ArmorType.Light:
                return 5;
            case ArmorType.Medium:
                return 15;
            case ArmorType.Heavy:
                return 25;
            case ArmorType.Shield:
                return 3;
            default:
                return 10;
        }
    }

    /// <summary>
    /// Get miscellaneous item weight
    /// </summary>
    private int GetMiscWeight(string itemName)
    {
        string lower = itemName.ToLower();

        if (lower.Contains("potion") || lower.Contains("scroll"))
            return 0; // Negligible weight
        else if (lower.Contains("rope"))
            return 10;
        else if (lower.Contains("torch"))
            return 1;
        else if (lower.Contains("ration") || lower.Contains("bread"))
            return 2;
        else if (lower.Contains("bandage"))
            return 0;
        else if (lower.Contains("tool"))
            return 5;

        return 1; // Default misc weight
    }

    /// <summary>
    /// Check if character can carry additional weight
    /// </summary>
    public bool CanCarryWeight(int additionalWeight)
    {
        return (currentWeight + additionalWeight) <= maxCapacity;
    }

    /// <summary>
    /// Get available carrying capacity
    /// </summary>
    public int GetAvailableCapacity()
    {
        return Mathf.Max(0, maxCapacity - currentWeight);
    }

    /// <summary>
    /// Get current movement speed modifier due to encumbrance
    /// </summary>
    public float GetMovementSpeedModifier()
    {
        return carrySystem.GetMovementSpeedModifier(currentEncumbrance);
    }

    /// <summary>
    /// Get current dexterity modifier due to encumbrance
    /// </summary>
    public int GetDexterityModifier()
    {
        return carrySystem.GetDexterityModifier(currentEncumbrance);
    }

    /// <summary>
    /// Get encumbrance info for UI display
    /// </summary>
    public string GetEncumbranceInfo()
    {
        return $"{currentWeight}/{maxCapacity} lbs - {carrySystem.GetEncumbranceDescription(currentEncumbrance)}";
    }

    // Properties for external access
    public int CurrentWeight => currentWeight;
    public int MaxCapacity => maxCapacity;
    public CarryCapacitySystem.EncumbranceLevel CurrentEncumbrance => currentEncumbrance;

    // Manual weight update for when inventory changes
    public void RefreshWeight()
    {
        UpdateCurrentWeight();
    }
}
