using System;
using System.Collections;
using UnityEngine;

namespace Benim.InventorySystem
{
public class Slot : MonoBehaviour, ISlot
{
[SerializeField] private GameObject itemHolderPrefab;
[SerializeField] private ItemType allowedItemTypes;


    [SerializeField] private GameObject itemHolderInstance;
    [SerializeField] private SlotItem slotItem;

    public GameObject ItemHolderInstance => itemHolderInstance;
    public SlotItem SlotItem => slotItem;
    public SlotItem TempSlotItem { get; set; }

    public bool IsEmpty => slotItem == null || slotItem.IsEmpty;
    public bool IsSlotFull => !IsEmpty && slotItem.Quantity >= slotItem.Item.MaxStackSize;

    public event Action OnItemAdded;
    public event Action OnItemRemoved;
    public event Action OnSlotChanged;

    private bool CanCombine(SlotItem other) => !other.IsEmpty &&
                                                other.Item == slotItem.Item &&
                                                slotItem.Item.IsStackable &&
                                                slotItem.Item.MaxStackSize > slotItem.Quantity;

    public TransferResult AddItemToSlot(SlotItem other)
    {
        if (!IsItemAllowed(other.Item)) return TransferResult.Failed;
        var result = IsEmpty ? CreateAndAddItem(other) : CombineItem(other);
        if (result != TransferResult.Failed) InvokeItemAdded();
        return result;
    }

    private TransferResult CreateAndAddItem(SlotItem other)
    {
        if (other.IsEmpty) return TransferResult.Failed;

        int transferAmount = Mathf.Min(other.Quantity, other.Item.MaxStackSize);
        var newSlotItem = new SlotItem(other.Item, transferAmount);
        var newHolder = Instantiate(itemHolderPrefab, transform);

        other.RemoveItem(transferAmount);
        AssingSlotReferences(newHolder, newSlotItem);
        return TransferResult.CreatedAndAdded;
    }

    private TransferResult CombineItem(SlotItem other)
    {
        if (!CanCombine(other)) return TransferResult.Failed;

        int transferAmount = Mathf.Min(other.Quantity, slotItem.Item.MaxStackSize - slotItem.Quantity);
        other.RemoveItem(transferAmount);
        slotItem.AddItem(transferAmount);
        return other.Quantity == 0 ? TransferResult.AllCombined : TransferResult.PartiallyCombined;
    }

    public TransferResult TransferItemWithinSlots(GameObject otherItemHolder, SlotItem other)
    {
        if (!IsItemAllowed(other.Item)) return TransferResult.Failed;

        TransferResult result = IsEmpty ? AddItemToEmpty(otherItemHolder, other) : CombineItem(other);
        if (result == TransferResult.Failed) result = SwapItem(otherItemHolder, other);
        InvokeItemAdded();

        var otherSlot = otherItemHolder.transform.parent.GetComponent<Slot>();
        if (otherSlot != null)
        {
            Debug.Log("asd");
            otherSlot.InvokeItemRemoved();
        }

        return result;
    }

    private TransferResult AddItemToEmpty(GameObject otherItemHolder, SlotItem other)
    {
        return TransferResult.AddedToEmpty;
    }

    private TransferResult SwapItem(GameObject otherItemHolder, SlotItem other)
    {
        return TransferResult.Swapped;
    }

    public TransferResult RemoveItemFromSlot(int quantity)
    {
        if (IsEmpty) return TransferResult.Failed;

        slotItem.RemoveItem(quantity);
        InvokeItemRemoved();
        return TransferResult.Removed;
    }

    public void AssingSlotReferences(GameObject itemHolder, SlotItem slotItem)
    {
        itemHolderInstance = itemHolder;
        this.slotItem = slotItem;
    }

    public TransferResult SplitItem(int splitQuantity, out SlotItem newSlotItem)
    {
        newSlotItem = null;

        if (IsEmpty || splitQuantity <= 0 || splitQuantity >= slotItem.Quantity)
        {
            Debug.LogWarning("Invalid split operation.");
            return TransferResult.Failed;
        }

        newSlotItem = new SlotItem(slotItem.Item, splitQuantity);
        slotItem.RemoveItem(splitQuantity);
        return TransferResult.Split;
    }

    public bool IsItemAllowed(Item item)
    {
        return (allowedItemTypes & item.ItemType) != ItemType.None;
    }

    public void SetAllowedItemTypes(ItemType types)
    {
        allowedItemTypes = types;
    }

    private void InvokeItemAdded()
    {
        OnItemAdded?.Invoke();
        OnSlotChanged?.Invoke();
        Debug.Log(name + " InvokeItemAdded");
    }

    private void InvokeItemRemoved()
    {
        OnItemRemoved?.Invoke();
        OnSlotChanged?.Invoke();
        Debug.Log(name + " InvokeItemRemoved");
    }
}
}

buradaki eventlerin tetiklenmesinden memnun değilim daha düzgün bir şekilde yapamaz mıyız