using System.Collections.Generic;
using System.Linq;
using Sirenix.OdinInspector;
using UnityEngine;
using VOID.Generic.Dict;
using VOID.Generic.Objects.Unit.Events;
using VOID.Generic.Objects.Weapon;
using VOID.Generic.Objects.Wearable.Events;
using VOID.ScriptableObjects.Abilities;

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

        protected override void SelfInitialize()
        {
            // Instantiate basic attack ability
            _attackAbility = Object.Instantiate(_defaultAttackAbility);
            _attackAbility.OnAddedToUnit(parent);
            
            // Instantiate all abilities
            _abilities.ToList().ForEach(ability =>
            {
                _abilities.Remove(ability);
                var instantiatedAbility = Object.Instantiate(ability);
                instantiatedAbility.OnAddedToUnit(parent);
                _abilities.Add(instantiatedAbility);
            });
        }

        protected override void EventInitialize()
        {
            parent.unitEvents.onEquipAfter.AddListener(OnWeaponEquip);
            parent.unitEvents.onUnEquipAfter.AddListener(OnWeaponUnEquip);
        }

        #endregion

        // Getters
        public List<BasicAbility> abilities => _abilities;
        public BasicAttackAbility attackAbility => _attackAbility;
        public BasicAttackAbility defaultAttackAbility => _defaultAttackAbility;
        
        [SerializeField, DisableInPlayMode] private List<BasicAbility> _abilities = new ();
        [ReadOnly, ShowInInspector] private BasicAttackAbility _attackAbility;
        [SerializeField, DisableInPlayMode] private BasicAttackAbility _defaultAttackAbility;

        public void RemoveAbility(BasicAbility abilityToRemove)
        {
            var deletedCount = _abilities.RemoveAll(ability => ability == abilityToRemove);
            if (deletedCount == 0) return;

            var abilityRemovedEvent = new AbilityBookAbilityRemovedEvent
            {
                unit = parent,
                abilityRemoved = abilityToRemove
            };
            
            parent.unitEvents.onAbilityRemoved.Invoke(abilityRemovedEvent);
            Object.Destroy(abilityToRemove);
        }

        public void AddAbility(BasicAbility abilityToAdd)
        {
            abilityToAdd = Object.Instantiate(abilityToAdd);
            _abilities.Add(abilityToAdd);

            var abilityAddedEvent = new AbilityBookAbilityAddedEvent
            {
                unit = parent,
                abilityAdded = abilityToAdd
            };
            
            abilityToAdd.OnAddedToUnit(parent);
            parent.unitEvents.onAbilityAdded.Invoke(abilityAddedEvent);
        }

        private void OnWeaponEquip(EquipEvent equipEvent)
        {
            if (equipEvent.wearable is not WeaponObject weaponObject) return;

            var attackAbilityToAdd = Object.Instantiate(weaponObject.weaponData.attackAbility);
            _attackAbility = weaponObject.weaponData.attackAbility;

            var attackAbilityChangeEvent = new AbilityBookAttackAbilityChangeEvent
            {
                unit = parent,
                newAttackAbility = attackAbilityToAdd
            };
            
            attackAbilityToAdd.OnAddedToUnit(parent);
            parent.unitEvents.onAttackAbilityChange.Invoke(attackAbilityChangeEvent);
        }

        private void OnWeaponUnEquip(UnEquipEvent unEquipEvent)
        {
            if (unEquipEvent.wearable is not WeaponObject) return;
            var mainHandWeapon = parent.unitEquipment.GetEquipped(EquipmentSlotType.MainHand);
            var offHandWeapon = parent.unitEquipment.GetEquipped(EquipmentSlotType.OffHand);
            if (mainHandWeapon || offHandWeapon) return;
            _attackAbility = _defaultAttackAbility;
        }
    }
}
