using UnityEngine;
using VOID.Generic.Objects.Item;
using VOID.Generic.Objects.Item.Events;
using VOID.Generic.Objects.Unit.Actions.Exceptions;
using VOID.Generic.Objects.Wearable;
using VOID.Generic.Objects.Wearable.Events;

namespace VOID.Generic.Objects.Unit.Actions
{
    public class ForcedDropAction : AbstractAction
    {
        private readonly UnitObject _unit;
        private readonly ItemObject _item;
        private readonly Vector3 _dropPosition;

        public ForcedDropAction(UnitObject unit, ItemObject item)
        {
            _unit = unit;
            _item = item;
            _dropPosition = unit.transform.position;
        }

        public ForcedDropAction(UnitObject unit, ItemObject item, Vector3 dropPosition)
        {
            _unit = unit;
            _item = item;
            _dropPosition = dropPosition;
        }

        public override bool IsInRange() => true;

        protected override void OnEndIt() {}
        protected override void OnCancelIt() {}

        public override void CanDoIt()
        {
            Check(
                state == ActionState.Ready,
                UnitActionErrorType.ActionStateIsNotReady);
            Check(
                _item.itemState.carriedBy == _unit,
                UnitActionErrorType.UnitDontCarryThatItem);
        }

        protected override void OnDoIt()
        {
            TryToUnEquip();

            var dropEvent = new DropEvent
            {
                item = _item,
                unit = _unit
            };
            
            _item.itemEvents.onDroppedBefore.Invoke(dropEvent);
            _unit.unitEvents.onDropBefore.Invoke(dropEvent);

            BeforePerform();
            _unit.unitBackpack.Drop(_item);
            _item.transform.position = _dropPosition;
            _item.itemEvents.onDroppedAfter.Invoke(dropEvent);
            _unit.unitEvents.onDropAfter.Invoke(dropEvent);
            AfterPerform();
            EndIt();
        }

        private void TryToUnEquip()
        {
            if (_item is not WearableObject item) return;
            if (!item.wearableState.wearerUnit) return;

            var unEquipEvent = new UnEquipEvent
            {
                wearable = item,
                unit = _unit
            };
            
            item.wearableEvents.onUnEquippedBefore.Invoke(unEquipEvent);
            _unit.unitEvents.onUnEquipBefore.Invoke(unEquipEvent);
                
            _unit.unitEquipment.UnEquip(item);
            _unit.unitBackpack.Take(item); 
            
            item.wearableEvents.onUnEquippedAfter.Invoke(unEquipEvent);
            _unit.unitEvents.onUnEquipAfter.Invoke(unEquipEvent);
        }
    }
}