using UnityEngine;
using UnityEngine.UI;
using W.o.N_Stats;

public class Character : MonoBehaviour
{
    [Header("Stats")]
    public CharacterStat Health;
    public CharacterStat Mana;
    public CharacterStat Defence;
    public CharacterStat Attack;
    public CharacterStat AttackSpeed;
    public CharacterStat Critical;
    public CharacterStat LifeSteal;
    public CharacterStat Range;
    public CharacterStat ElementalMastery;
    public CharacterStat Speed;
    public CharacterStat Cooldown;
    public CharacterStat Knockback;
    public CharacterStat Recovery;
    public CharacterStat Evade;
    public CharacterStat Fortune;

    public int maxHealth;
    public int maxMana;
    public int maxDefense;
    public int maxAttack;
    public float maxAttackSpeed;
    public int maxCritical;
    public float maxLifeSteal;
    public float maxRange;
    public float maxElementalMastery;
    public float maxSpeed;
    public float maxCooldown;
    public float maxKnockback;
    public float maxRecovery;
    public float maxEvade;
    public float maxFortune;

    [Header("Public")]
    public Inventory Inventory;
    public EquipmentPanel EquipmentPanel;
    public Player player; // Reference to the Player script
    private WeaponTypeDetector weaponTypeDetector;

    
    [Header("Selected Seed")]
    public SeedItem selectedSeed; // Reference to the selected seed item
    public Color normalColor = Color.white;
    public Color selectedColor = new Color(0.5f, 0.5f, 0.5f, 1f);
    private static Character instance; // Reference to the character instance

    [Header("Serialize Field")]
    [SerializeField] CraftingWindow craftingWindow;
    [SerializeField] StatPanel statPanel;
    [SerializeField] ItemTooltip itemTooltip;
    [SerializeField] Image draggableItem;
    [SerializeField] DropItemArea dropItemArea;
    [SerializeField] QuestionDialog reallyDropItemDialog;

    private BaseItemSlot dragItemSlot;

    private void OnValidate()
    {
        if (itemTooltip == null)
            itemTooltip = FindObjectOfType<ItemTooltip>();
    }

    public void Awake()
    {
        statPanel.SetStats(Health, Mana, Defence, Attack, AttackSpeed, Critical, LifeSteal, Range, ElementalMastery, Speed, Cooldown, Knockback, Recovery, Evade, Fortune);
        instance = this; // Assign the current instance to the static variable
        statPanel.UpdateStatValues();
        // Get the WeaponTypeDetector component
        weaponTypeDetector = GetComponent<WeaponTypeDetector>();

        // Setup Events:
        // Right Click
        Inventory.OnRightClickEvent += InventoryRightClick;
        EquipmentPanel.OnRightClickEvent += EquipmentPanelRightClick;
        // Pointer Enter
        Inventory.OnPointerEnterEvent += ShowTooltip;
        EquipmentPanel.OnPointerEnterEvent += ShowTooltip;
        craftingWindow.OnPointerEnterEvent += ShowTooltip;
        // Pointer Exit
        Inventory.OnPointerExitEvent += HideTooltip;
        EquipmentPanel.OnPointerExitEvent += HideTooltip;
        craftingWindow.OnPointerExitEvent += HideTooltip;
        // Begin Drag
        Inventory.OnBeginDragEvent += BeginDrag;
        EquipmentPanel.OnBeginDragEvent += BeginDrag;
        // End Drag
        Inventory.OnEndDragEvent += EndDrag;
        EquipmentPanel.OnEndDragEvent += EndDrag;
        // Drag
        Inventory.OnDragEvent += Drag;
        EquipmentPanel.OnDragEvent += Drag;
        // Drop
        Inventory.OnDropEvent += Drop;
        EquipmentPanel.OnDropEvent += Drop;
        dropItemArea.OnDropEvent += DropItemOutsideUI;

    }

    public static Character GetInstance()
    {
        if (instance == null)
        {
            instance = FindObjectOfType<Character>(); // Find the Character instance in the scene
        }
        return instance;
    }
    
    private void Update()
    {
        // Change the following line to continuously update stats in real-time
        UpdateStatValues();
    }

    private void InventoryRightClick(BaseItemSlot itemSlot)
    {
        // Deselect the currently selected seed if the clicked item is not a seed item
        if (!(itemSlot.Item is SeedItem))
        {
            DeselectSeed();
        }

        // Handle the action for the clicked item
        if (itemSlot.Item is EquippableItem)
        {
            Equip((EquippableItem)itemSlot.Item);
        }
        else if (itemSlot.Item is UsableItem)
        {
            // Use the Usable Item
            UsableItem usableItem = (UsableItem)itemSlot.Item;
            usableItem.Use(player); // Assuming 'player' is a reference to the Player script
            Inventory.RemoveItem(usableItem); // Remove the used item from the inventory
        }
        else if (itemSlot.Item is SeedItem)
        {
            SeedItem seedItem = (SeedItem)itemSlot.Item;

            // If the clicked seed is the same as the currently selected seed, deselect it
            if (selectedSeed == seedItem)
            {
                DeselectSeed();
            }
            else // If the clicked seed is different from the currently selected one, select it
            {
                // Check if there's a previously selected seed, and deselect it
                if (selectedSeed != null)
                {
                    DeselectSeed();
                }

                selectedSeed = seedItem;
                Debug.Log("Selected seed: " + selectedSeed.name);
                UpdateSeedTintColors();
            }
        }

        UpdateMax();
        AdjustStatsIfNeeded();
    }

    private void DeselectSeed()
    {
        if (selectedSeed != null)
        {
            Debug.Log("Deselected seed: " + selectedSeed.name);
            selectedSeed = null;
            UpdateSeedTintColors();
        }
    }

    private void UpdateSeedTintColors()
    {
        // Update tint colors of seed items based on selection state
        foreach (BaseItemSlot itemSlot in Inventory.ItemSlots)
        {
            if (itemSlot.Item is SeedItem seedItem)
            {
                Image seedImage = itemSlot.GetComponent<Image>();
                if (seedItem == selectedSeed)
                {
                    seedImage.color = selectedColor;
                }
                else
                {
                    seedImage.color = normalColor;
                }
            }
        }
    }

    private void EquipmentPanelRightClick(BaseItemSlot itemSlot)
    {
        if (itemSlot.Item is EquippableItem)
        {
            Unequip((EquippableItem)itemSlot.Item);
        }
        UpdateMax();
    }

    private void ShowTooltip(BaseItemSlot itemSlot)
    {
        if (itemSlot.Item != null)
        {
            itemTooltip.ShowTooltip(itemSlot.Item);
        }
    }

    private void HideTooltip(BaseItemSlot itemSlot)
    {
        if (itemTooltip.gameObject.activeSelf)
        {
            itemTooltip.HideTooltip();
        }
    }

    private void BeginDrag(BaseItemSlot itemSlot)
    {
        if (itemSlot.Item != null && !(itemSlot is EquipmentSlot))
        {
            dragItemSlot = itemSlot;
            draggableItem.sprite = itemSlot.Item.Icon;
            draggableItem.transform.position = Input.mousePosition;
            draggableItem.gameObject.SetActive(true);
        }
    }

    private void Drag(BaseItemSlot itemSlot)
    {
        if (dragItemSlot != null)
        {
            draggableItem.transform.position = Input.mousePosition;
        }
    }

    private void EndDrag(BaseItemSlot itemSlot)
    {
        dragItemSlot = null;
        draggableItem.gameObject.SetActive(false);
    }

    private void Drop(BaseItemSlot dropItemSlot)
{
    if (dragItemSlot == null) return;

    // Case 1: Prevent dropping equippable items into equipment slots if the item is already equipped
    if (dragItemSlot.Item is EquippableItem && dropItemSlot is EquipmentSlot)
    {
        EndDrag(null);
        return;
    }

    // Case 2: Try to stack the item if dropItemSlot can accept stacks
    if (dropItemSlot.CanAddStack(dragItemSlot.Item))
    {
        AddStacks(dropItemSlot);
    }
    // Case 3: Swap items if both slots can receive each other's items
    else if (dropItemSlot.CanReceiveItem(dragItemSlot.Item) && dragItemSlot.CanReceiveItem(dropItemSlot.Item))
    {
        SwapItems(dropItemSlot, dragItemSlot);
    }
    // Case 4: Move item to dropItemSlot if it’s a valid drop
    else if (dropItemSlot.CanReceiveItem(dragItemSlot.Item))
    {
        MoveItemToSlot(dropItemSlot, dragItemSlot);
        RemoveItemFromSlot(dragItemSlot);
    }

    EndDrag(null);
}

    private void MoveItemToSlot(BaseItemSlot dropItemSlot, BaseItemSlot dragItemSlot)
{
    dropItemSlot.Item = dragItemSlot.Item;
    dropItemSlot.Amount = dragItemSlot.Amount;
}

private void RemoveItemFromSlot(BaseItemSlot itemSlot)
{
    itemSlot.Item = null;
    itemSlot.Amount = 0;
}

    private void AddStacks(BaseItemSlot dropItemSlot)
    {
        int numAddableStacks = dropItemSlot.Item.MaximumStacks - dropItemSlot.Amount;
        int stacksToAdd = Mathf.Min(numAddableStacks, dragItemSlot.Amount);

        dropItemSlot.Amount += stacksToAdd;
        dragItemSlot.Amount -= stacksToAdd;
    }

    private void SwapItems(BaseItemSlot dropItemSlot, BaseItemSlot originalSlot)
    {
        Item draggedItem = originalSlot.Item;
        int draggedItemAmount = originalSlot.Amount;

        originalSlot.Item = dropItemSlot.Item;
        originalSlot.Amount = dropItemSlot.Amount;

        dropItemSlot.Item = draggedItem;
        dropItemSlot.Amount = draggedItemAmount;

        if (originalSlot is EquipmentSlot)
        {
            ((EquippableItem)originalSlot.Item)?.Equip(this);
        }

        if (dropItemSlot is EquipmentSlot)
        {
            ((EquippableItem)dropItemSlot.Item)?.Equip(this);
        }

        statPanel.UpdateStatValues();
    }

   private void DropItemOutsideUI()
{
    if (dragItemSlot == null) return;

    if (dragItemSlot.Item != null)
    {
        // Check if the dialog should be shown or bypassed
        if (reallyDropItemDialog.ShouldAskAgain())
        {
            // Show the confirmation dialog
            reallyDropItemDialog.Show();
            BaseItemSlot slot = dragItemSlot;
            reallyDropItemDialog.OnYesEvent += () => DestroyItemInSlot(slot);
        }
        else
        {
            // Directly destroy the item if the user opted not to be asked again
            DestroyItemInSlot(dragItemSlot);
        }
    }
}

    private void DestroyItemInSlot(BaseItemSlot itemSlot)
    {
        // If the item is equipped, unequip first
        if (itemSlot is EquipmentSlot)
        {
            EquippableItem equippableItem = (EquippableItem)itemSlot.Item;
            equippableItem.Unequip(this);
            AdjustStatsIfNeeded();
            UpdateStatValues();
        }

        itemSlot.Item.Destroy();
        itemSlot.Item = null;
    }

    public void Equip(EquippableItem item)
    {
        if (Inventory.RemoveItem(item))
        {
            EquippableItem previousItem;
            if (EquipmentPanel.AddItem(item, out previousItem))
            {
                if (previousItem != null)
                {
                    Inventory.AddItem(previousItem);
                    previousItem.Unequip(this);
                }
                item.Equip(this);
            }
            else
            {
                Inventory.AddItem(item);
            }

            // Update stats immediately after equipping
            UpdateStatValues();
            AdjustStatsIfNeeded();

            // Update weapon type
            weaponTypeDetector.ManualUpdateWeaponType();
        }
    }

    public void Unequip(EquippableItem item)
    {
        if (Inventory.CanAddItem(item) && EquipmentPanel.RemoveItem(item))
        {
            item.Unequip(this);
            // Update stats immediately after unequipping
            UpdateStatValues();
            Inventory.AddItem(item);

            // Reset current stats to their maximum values
            AdjustStatsIfNeeded();

            // Update weapon type
            weaponTypeDetector.ManualUpdateWeaponType();
        }
    }

    // Method to call SetCurrentStatsToMax from the Player script
    public void AdjustStatsIfNeeded()
    {
        player.AdjustStatsIfNeeded();
    }

    public void UpdateMax()
    {
        player.UpdateMaxStats();
    }

    private ItemContainer openItemContainer;

public void OpenChest(Chest chest)
{
    OpenItemContainer(chest);
}

public void CloseChest(Chest chest)
{
    CloseItemContainer(chest);
}


private void TransferToItemContainer(BaseItemSlot itemSlot)
{
    Item item = itemSlot.Item;
    if (item != null && openItemContainer.CanAddItem(item))
    {
        Inventory.RemoveItem(item);
        openItemContainer.AddItem(item);
    }
}

private void TransferToInventory(BaseItemSlot itemSlot)
{
    Item item = itemSlot.Item;
    if (item != null && Inventory.CanAddItem(item))
    {
        openItemContainer.RemoveItem(item);
        Inventory.AddItem(item);
    }
}

public void OpenItemContainer(ItemContainer itemContainer)
{
    openItemContainer = itemContainer;

    Inventory.OnRightClickEvent -= InventoryRightClick;
    Inventory.OnRightClickEvent += TransferToItemContainer;

    itemContainer.OnRightClickEvent += TransferToInventory;

    itemContainer.OnPointerEnterEvent += ShowTooltip;
    itemContainer.OnPointerExitEvent += HideTooltip;
    itemContainer.OnBeginDragEvent += BeginDrag;
    itemContainer.OnEndDragEvent += EndDrag;
    itemContainer.OnDragEvent += Drag;
    itemContainer.OnDropEvent += Drop;
}

public void CloseItemContainer(ItemContainer itemContainer)
{
    openItemContainer = null;

    Inventory.OnRightClickEvent += InventoryRightClick;
    Inventory.OnRightClickEvent -= TransferToItemContainer;

    itemContainer.OnRightClickEvent -= TransferToInventory;

    itemContainer.OnPointerEnterEvent -= ShowTooltip;
    itemContainer.OnPointerExitEvent -= HideTooltip;
    itemContainer.OnBeginDragEvent -= BeginDrag;
    itemContainer.OnEndDragEvent -= EndDrag;
    itemContainer.OnDragEvent -= Drag;
    itemContainer.OnDropEvent -= Drop;
}

    public void UpdateStatValues()
    {
        statPanel.UpdateStatValues();
    }

       public void LoadStatsFromData(PlayerData data)
    {
        // Assign loaded max stats
        maxHealth = data.maxHealth;
        maxMana = data.maxMana;
        maxDefense = data.maxDefense;
        maxAttack = data.maxAttack;
        maxAttackSpeed = data.maxAttackSpeed;
        maxCritical = data.maxCritical;
        maxLifeSteal = data.maxLifeSteal;
        maxRange = data.maxRange;
        maxElementalMastery = data.maxElementalMastery;
        maxSpeed = data.maxSpeed;
        maxCooldown = data.maxCooldown;
        maxKnockback = data.maxKnockback;
        maxRecovery = data.maxRecovery;
        maxEvade = data.maxEvade;
        maxFortune = data.maxFortune;

        // Update CharacterStat fields
        Health.BaseValue = data.currentHealth;
        Mana.BaseValue = data.currentMana;
        Defence.BaseValue = data.currentDefense;
        Attack.BaseValue = data.currentAttack;
        AttackSpeed.BaseValue = data.currentAttackSpeed;
        Critical.BaseValue = data.currentCritical;
        LifeSteal.BaseValue = data.currentLifeSteal;
        Range.BaseValue = data.currentRange;
        ElementalMastery.BaseValue = data.currentElementalMastery;
        Speed.BaseValue = data.currentSpeed;
        Cooldown.BaseValue = data.currentCooldown;
        Knockback.BaseValue = data.currentKnockback;
        Recovery.BaseValue = data.currentRecovery;
        Evade.BaseValue = data.currentEvade;
        Fortune.BaseValue = data.currentFortune;

        // Update UI or any other components
        UpdateStatValues(); // Assuming this method updates UI with current stat values
    }

    public void UpdateMaxStats()
    {
        maxHealth = Mathf.RoundToInt(Health.Value);
        maxMana = Mathf.RoundToInt(Mana.Value);
        maxDefense = Mathf.RoundToInt(Defence.Value);
        maxAttack = Mathf.RoundToInt(Attack.Value);
        maxAttackSpeed = AttackSpeed.Value;
        maxCritical = Mathf.RoundToInt(Critical.Value);
        maxLifeSteal = LifeSteal.Value;
        maxRange = Range.Value;
        maxElementalMastery = ElementalMastery.Value;
        maxSpeed = Speed.Value;
        maxCooldown = Cooldown.Value;
        maxKnockback = Knockback.Value;
        maxRecovery = Recovery.Value;
        maxEvade = Evade.Value;
        maxFortune = Fortune.Value;
    }
}


i need to locate characters base values