using System;
using Sirenix.OdinInspector;
using UnityEngine;
using VOID.Generic.Objects.Unit.Events;
using VOID.Generic.Objects.Usable;
using VOID.ScriptableObjects.Abilities;

namespace VOID.Generic.Objects.Unit
{
    [Serializable]
    public class UnitObjectActionBar : ObjectComponent<UnitObject>
    {
        #region Initialize

        protected override void SelfInitialize()
        {
            slots = new (UsableObject usable, BasicAbility ability)[slotCount];
        }

        protected override void EventInitialize()
        {
            parent.unitEvents.onBackpackDrop.AddListener(OnUsableDrop);
        }

        #endregion

        [SerializeField, MinValue(20), MaxValue(200)] private int slotCount = 100;
        public (UsableObject usable, BasicAbility ability)[] slots { get; private set; }
        
        public void Set(UsableObject usable) => Set(FirstFreeIndex(), usable);
        public void Set(int index, UsableObject usable)
        {
            if (index < 0 || index >= slotCount)
            {
                Debug.LogWarning("UnitObjectActionBar.Set() - index out of limit");
                return;
            }

            UnSet(index);
            slots[index].usable = usable;
            
            parent.unitEvents.onActionBarSet.Invoke(new ActionBarSetEvent
            {
                unit = parent,
                index = index,
                usable = usable,
                ability = null
            });
        }

        public void Set(BasicAbility ability) => Set(FirstFreeIndex(), ability);
        public void Set(int index, BasicAbility ability)
        {
            if (index < 0 || index >= slotCount)
            {
                Debug.LogWarning("UnitObjectActionBar.Set() - index out of limit");
                return;
            }
            
            UnSet(index);
            slots[index].ability = ability;
            
            parent.unitEvents.onActionBarSet.Invoke(new ActionBarSetEvent
            {
                unit = parent,
                index = index,
                usable = null,
                ability = ability
            });
        }

        public void UnSet(int index)
        {

            if (slots[index] == default) return;
            
            slots[index] = default;

            parent.unitEvents.onActionBarUnSet.Invoke(new ActionBarUnSetEvent
            {
                unit = parent,
                index = index
            });
        }

        public void UnSet(UsableObject usable)
        {
            for (var i = 0; i < slots.Length; i++)
                if (slots[i].usable == usable)
                    UnSet(i);
        }

        public void Clear()
        {
            for (var j = 0; j < slotCount; j++) UnSet(j);
        }
        
        private void OnUsableDrop(BackpackDropEvent backpackDropEvent)
        {
            if (backpackDropEvent.item is not UsableObject usable) return;
            
            UnSet(usable);
        }

        private int FirstFreeIndex()
        {
            for (var i = 0; i < slots.Length; i++)
                if (slots[i].usable == default || slots[i].ability == default)
                    return i;

            return -1;
        }
    }
}
