using VOID.Generic.Dict;
using VOID.Generic.Objects.Item;
using VOID.Generic.Objects.Item.Events;
using VOID.Generic.Objects.Unit.Actions.Exceptions;
using VOID.Generic.Objects.Unit.Events;
using VOID.Generic.Util;

namespace VOID.Generic.Objects.Unit.Actions
{
    public class TakeAction : AbstractAction
    {
        private readonly UnitObject _unit;
        private readonly ItemObject _item;
        private readonly int _slotIndex;

        public TakeAction(UnitObject unit, ItemObject item)
        {
            _unit = unit;
            _item = item;
        }

        public TakeAction(UnitObject unit, ItemObject item, int slotIndex) : this(unit, item)
        {
            _slotIndex = slotIndex;
        }

        public override bool IsInRange()
        {
            return RangeUtil.IsInRange(_unit, _item, _unit.unitData.takeRange);
        }

        protected override void OnEndIt()
        {
        }

        protected override void OnCancelIt()
        {
        }
        
        public override void CanDoIt()
        {
            Check(
                _unit.unitData.canTake,
                UnitActionErrorType.ThisUnitCantTake);
            Check(
                state == ActionState.Ready,
                UnitActionErrorType.ActionStateIsNotReady);
            if (_unit.basicState.turnManager)
            {
                Check(
                    _unit.unitState.isSelfTurn,
                    UnitActionErrorType.UnitSelfTurnNotActive);
                Check(
                    _unit.unitData.currentResources.actionPoints >= 1,
                    UnitActionErrorType.UnitNotEnoughActionPoints);
            }
            Check(
                _unit.unitState.isControllable,
                UnitActionErrorType.UnitStateIsNotControllable);
            Check(
                _item.itemData.canBePicked && _item.itemData.canBeMoved,
                UnitActionErrorType.ItemIsNotPickable);
            Check(
                !_item.itemState.carriedBy || _item.itemState.carriedBy.basicState.isDead,
                UnitActionErrorType.ItemIsNotOnGround);
            Check(
                IsInRange(),
                UnitActionErrorType.NotInRange);
        }

        protected override void OnDoIt()
        {
            if (_unit.basicState.turnManager)
                _unit.unitData.UseResource(UnitResourceType.ActionPoints, 1);
            
            _unit.OrderInstantly(new RotateAction(_unit, _item));
            
            if (_item.itemState.carriedBy && _item.itemState.carriedBy.basicState.isDead)
                new ForcedDropAction(_item.itemState.carriedBy, _item).DoIt();
            
            Check(!_item.itemState.carriedBy, UnitActionErrorType.ItemIsNotOnGround);

            var pickEvent = new PickEvent
            {
                item = _item,
                unit = _unit
            };
            
            _item.itemEvents.onPickedBefore.Invoke(pickEvent);
            _unit.unitEvents.onTakeBefore.Invoke(pickEvent);
            
            Check(!pickEvent.prevented, UnitActionErrorType.PickIsPrevented);
            
            BeforePerform();

            if (_item.itemState.inContainer) _item.itemState.inContainer.containerContent.MoveOut(_item, _unit);

            _unit.unitBackpack.Take(_slotIndex, _item);
            _item.itemEvents.onPickedAfter.Invoke(pickEvent);
            _unit.unitEvents.onTakeAfter.Invoke(pickEvent);
            AfterPerform();
            EndIt();
        }
    }
}