using VOID.Generic.Objects.Container;
using VOID.Generic.Objects.Container.Events;
using VOID.Generic.Objects.Unit.Actions.Exceptions;
using VOID.Generic.Util;

namespace VOID.Generic.Objects.Unit.Actions
{
    public class OpenContainerAction : AbstractAction
    {
        private readonly UnitObject _unit;
        private readonly ContainerObject _container;
        
        public OpenContainerAction(UnitObject unit, ContainerObject container)
        {
            _unit = unit;
            _container = container;
        }

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

        protected override void OnEndIt() {}

        protected override void OnCancelIt() {}
        
        public override void CanDoIt()
        {
            Check(
                state == ActionState.Ready,
                UnitActionErrorType.ActionStateIsNotReady);
            if (_unit.basicState.turnManager)
            {
                Check(
                    _unit.unitState.isSelfTurn || _container.itemState.carriedBy == _unit,
                    UnitActionErrorType.UnitSelfTurnNotActive);
            }
            Check(
                _unit.unitState.isControllable,
                UnitActionErrorType.UnitStateIsNotControllable);
            Check(
                IsInRange(),
                UnitActionErrorType.NotInRange);
            Check(
                !_container.containerState.openedBy.Contains(_unit),
                UnitActionErrorType.ContainerIsAlreadyOpenedByThisUnit);
        }

        protected override void OnDoIt()
        {
            var containerOpenEvent = new ContainerOpenEvent
            {
                openedBy = _unit,
                container = _container
            };

            if (_container.itemState.carriedBy != _unit)
                _unit.OrderInstantly(new RotateAction(_unit, _container));
            
            BeforePerform();
            _container.containerEvents.onOpen.Invoke(containerOpenEvent);
            _unit.unitEvents.onContainerOpen.Invoke(containerOpenEvent);
            AfterPerform();
            EndIt();
        }
    }
}