using CommonAI.RTS;
using CommonLang.Vector;
using CommonAI.Zone.Helper;
using CommonLang;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CommonAI.Zone.Instance
{
    /// <summary>
    /// 纯手动控制AI,完全没有自动成分
    /// </summary>
    public class InstanceManual : InstanceUnit
    {
        private StateFollowAndAttack mAttackTargget;
        private TimeExpire<WaitTimeHandler> mWaitCommand;

        public InstanceManual(InstanceZone zone, UnitInfo info, string name, int force, int level)
            : base(zone, info, name, force, level)
        {
        }

        public void queueDoAction(float timeSEC, string actionName, State.StateStopHandler over = null)
        {
            mAttackTargget = null;
            QueueStateActionTime state = new QueueStateActionTime(this, timeSEC, actionName);
            if (over != null)
            {
                state.AddStopOnce(over);
            }
            queueState(state);
        }

        public void queueIdle(float timeSEC, State.StateStopHandler over = null)
        {
            mAttackTargget = null;
            QueueStateIdleTime state = new QueueStateIdleTime(this, timeSEC);
            if (over != null)
            {
                state.AddStopOnce(over);
            }
            queueState(state);
        }

        public void queueMoveTo(float x, float y, State.StateStopHandler over = null)
        {
            mAttackTargget = null;
            QueueStateMoveTo state = new QueueStateMoveTo(this, x, y);
            if (over != null)
            {
                state.AddStopOnce(over);
            }
            queueState(state);
        }

        public void queueLaunchSkill(int skillID, bool random, State.StateStopHandler over = null)
        {
            mAttackTargget = null;
            QueueStateLaunchSkill state = new QueueStateLaunchSkill(this, skillID, random, over);
            queueState(state);
        }

        public void focuseAttack(InstanceUnit targget)
        {
            mAttackTargget = new StateFollowAndAttack(this, targget);
            changeState(mAttackTargget);
        }

        public void wait(float timeSEC, WaitTimeHandler over)
        {
            // 强制中断前一个等待指令
            if (mWaitCommand != null)
            {
                mWaitCommand.Tag.Invoke();
            }
            mWaitCommand = new TimeExpire<WaitTimeHandler>(over, (int)(timeSEC * 1000));
        }

        protected override void onUpdate(bool slowRefresh)
        {
            base.onUpdate(slowRefresh);

            if (mWaitCommand != null && mWaitCommand.Update(Parent.UpdateIntervalMS))
            {
                mWaitCommand.Tag.Invoke();
                mWaitCommand = null;
            }
        }

        protected override void onAction(ObjectAction act)
        {
            if (IsDead())
            {
                return;
            }
            if (act is UnitStopMoveAction)
            {
                doSomething();
            }
            else if (act is UnitMoveAction)
            {
                UnitMoveAction move = act as UnitMoveAction;
                startMoveTo(move.x, move.y);
            }
            else if (act is UnitAxisAction)
            {

            }
            else if (act is UnitLaunchSkillAction)
            {
                UnitLaunchSkillAction sk = act as UnitLaunchSkillAction;
                launchSkill(sk.SkillID, new InstanceUnit.LaunchSkillParam(sk.TargetObjID, sk.SpellTargetPos, sk.IsAutoFocusNearTarget));
            }
            else if (act is UnitFaceToAction)
            {
                UnitFaceToAction ufa = act as UnitFaceToAction;
                this.faceTo(ufa.Direction);
            }
            else if (act is UnitSlipAction)
            {
                // do nothing
            }
            else if (act is UnitGuardAction)
            {
                // do nothing
            }
            else if (act is UnitFocuseTargetAction)
            {
                // do nothing
            }
        }

        public delegate void WaitTimeHandler();


        class QueueStateMoveTo : State
        {
            private readonly float targetX;
            private readonly float targetY;
            private bool isEnd = false;
            private MoveAI moveAI;

            public QueueStateMoveTo(InstanceUnit unit, float x, float y)
                : base(unit)
            {
                this.targetX = x;
                this.targetY = y;
            }

            override public bool onBlock(State new_state)
            {
                if (unit.IsDead()) return true;
                return isEnd;
            }
            override protected void onStart()
            {
                unit.SetActionStatus(UnitActionStatus.Move);
                this.moveAI = new MoveAI(unit);
                this.moveAI.FindPath(targetX, targetY);
            }
            override protected void onUpdate()
            {
                if (!isEnd)
                {
                    unit.faceTo(targetX, targetY);
                    MoveBlockResult result = moveAI.Update();
                    if ((result.result & MoveResult.MOVE_RESULT_NO_WAY) != 0)
                    {
                        isEnd = true;
                        unit.doSomething();
                    }
                    else if ((result.result & MoveResult.RESULTS_MOVE_END) != 0)
                    {
                        float r = Math.Max(zone.MinStep, unit.BodyBlockSize);
                        if (CMath.includeRoundPoint(unit.X, unit.Y, r, targetX, targetY))
                        {
                            isEnd = true;
                            unit.doSomething();
                        }
                    }
                    else
                    {
                        float r = Math.Max(zone.MinStep, unit.BodyBlockSize);
                        if (CMath.includeRoundPoint(unit.X, unit.Y, r, targetX, targetY))
                        {
                            isEnd = true;
                            unit.doSomething();
                        }
                    }
                }
            }

            override protected void onStop()
            {

            }



        }

        class QueueStateLaunchSkill : State
        {
            private readonly int SkillID;
            private readonly bool IsRandom;
            private readonly StateStopHandler SkillOver;
            private StateSkill mSkillState;


            public QueueStateLaunchSkill(InstanceUnit unit, int skillID, bool random, StateStopHandler over)
                : base(unit)
            {
                this.SkillID = skillID;
                this.IsRandom = random;
                this.SkillOver = over;
            }
            public override bool onBlock(State new_state)
            {
                if (unit.IsDead()) return true;
                if (new_state is StateSkill)
                {
                    return true;
                }
                return mSkillState != null;
            }
            protected override void onStart()
            {

            }
            protected override void onUpdate()
            {
                if (IsRandom)
                {
                    mSkillState = unit.launchRandomSkillForAll(new InstanceUnit.LaunchSkillParam());
                }
                else
                {
                    mSkillState = unit.launchSkill(SkillID, new InstanceUnit.LaunchSkillParam());
                }
                if (mSkillState != null && SkillOver != null)
                {
                    mSkillState.AddStopOnce(SkillOver);
                }
            }
            protected override void onStop()
            {
                if (mSkillState == null && SkillOver != null)
                {
                    SkillOver.Invoke(unit, this);
                }
            }
        }

        class QueueStateIdleTime : State
        {
            private readonly TimeExpire<int> mIdleTime;


            public QueueStateIdleTime(InstanceUnit unit, float timeSEC)
                : base(unit)
            {
                mIdleTime = new TimeExpire<int>((int)(timeSEC * 1000));
            }

            override public bool onBlock(State new_state)
            {
                if (unit.IsDead()) return true;
                return mIdleTime.IsEnd;
            }

            override protected void onStart()
            {
                unit.SetActionStatus(UnitActionStatus.Idle);
            }

            override protected void onUpdate()
            {
                if (mIdleTime.Update(zone.UpdateIntervalMS))
                {
                    unit.doSomething();
                }
            }
            override protected void onStop() { }
        }

        class QueueStateActionTime : QueueStateIdleTime
        {
            private readonly string ActionName;

            public QueueStateActionTime(InstanceUnit unit, float timeSEC, string actionName)
                : base(unit, timeSEC)
            {
                this.ActionName = actionName;
            }

            override protected void onStart()
            {
                unit.queueEvent(new UnitDoActionEvent(unit.ID, ActionName));
            }

        }
    }

}