using System;
using System.Collections.Generic;
using System.Text;
using CommonAI.RTS.Manhattan;
using CommonAI.RTS;
using CommonLang.Vector;
using CommonLang;
using CommonAI.ZoneClient;
using CommonAI.Zone.Helper;
using CommonAI.Zone.Formula;
using CommonAI.Zone.Attributes;

namespace CommonAI.Zone.Instance
{

    //--------------------------------------------------------------------------------------------------------

    /// <summary>
    /// 所有自动电脑AI
    /// </summary>
    public class InstanceGuard : InstanceUnit, IGuardUnit, ViewTrigger.ViewTriggerListener
    {
        protected ViewTrigger mViewTrigger;
        protected HateSystem mHateSystem;
        protected StateAttackTo mRunningPath;
        protected StateFollowAndAttack mTracingTarget;
        protected StateFollowAndGuard mGuardTarget;
        protected StateBackToPosition mBackToPosition;
        protected Vector2 mOrginPosition;
        //protected TimeInterval<int> mCheckInGuardLimit;
		protected SimpleTrigger mNextCheckGuardLimit;
		public InstanceUnit TracingTarget
        {
            get
            {
                if (mTracingTarget != null) return mTracingTarget.TargetUnit;
                return null;
            }
        }

        public InstanceGuard(InstanceZone zone, UnitInfo info, string name, int force, int level)
            : base(zone, info, name, force, level)
        {
            //this.mCheckInGuardLimit = new TimeInterval<int>(Templates.CFG.AI_NPC_CHECK_IN_GUARD_LIMIT_TIME_MS);
			this.mNextCheckGuardLimit = new SimpleTrigger(Templates.CFG.AI_NPC_CHECK_IN_GUARD_LIMIT_TIME_MS);

			this.OnActivated += this.onUnitActivated;
        }

        protected override void onAdded(bool pointLv)
        {
            base.onAdded(pointLv);
            this.mHateSystem = TemplateManager.Factory.CreateHateSystem(this);
            this.mOrginPosition = new Vector2(X, Y);
        }

        protected override void Disposing()
        {
            base.Disposing();
            if (mViewTrigger != null) mViewTrigger.Dispose();
            mHateSystem.Clear();
            mRunningPath = null;
            mTracingTarget = null;
            mGuardTarget = null;
            mBackToPosition = null;
            mOrginPosition = null;
            this.mNextCheckGuardLimit = null;
            this.OnActivated -= this.onUnitActivated;
        }

        override protected void onResetAI()
        {
            mTracingTarget = null;
            mHateSystem.Clear();
            doSomething();
        }

        protected override void onDead(InstanceUnit killer)
        {
            base.onDead(killer);
            SetEnableView(false);
        }

        //--------------------------------------------------------------------------------------------------------
        #region View

        public void SetEnableView(bool view)
        {
            if (mViewTrigger != null)
            {
                this.mViewTrigger.Enable = view && !IsNature && !IsNoneSkill;
            }
        }

        private void initViewTrigger()
        {
            this.mViewTrigger = CreateViewTrigger(Parent);
            if (mViewTrigger != null)
            {
                this.mViewTrigger.setListener(this);
            }
        }

        protected virtual ViewTrigger CreateViewTrigger(InstanceZone zone)
        {
            if (Info.GuardRange > 0)
            {
                return new ViewTriggerRoundBody(zone, Info.GuardRange);
            }
            else
            {
                return new ViewTriggerBlind(zone);
            }
        }

        void ViewTrigger.ViewTriggerListener.onObjectEnterView(ViewTrigger src, InstanceZoneObject obj)
        {
            onAddEnemy(obj as InstanceUnit, true, AttackReason.Look);
        }
        void ViewTrigger.ViewTriggerListener.onObjectLeaveView(ViewTrigger src, InstanceZoneObject obj)
        {

        }
        bool ViewTrigger.ViewTriggerListener.select(ViewTrigger src, InstanceZoneObject obj)
        { 
            if (obj == this)
            {
                return false;
            }
            else if ((obj is InstanceUnit))
            {
                InstanceUnit u = obj as InstanceUnit;
                if (!u.IsNature && !this.IsNature && Parent.IsAttackable(this, u, SkillTemplate.CastTarget.Enemy, AttackReason.Look, Info))
                {
                    return true;
                }
            }
            return false;
        }

        #endregion
        //--------------------------------------------------------------------------------------------------------
        #region Action

        void IGuardUnit.AttackTo(ZoneWayPoint start, int peaceTime)
        {
            this.attackTo(start, peaceTime);
        }
        void IGuardUnit.SetOrginPosition(float x, float y)
        {
            this.setOrginPosition(x, y);
        }
        void IGuardUnit.PatrolWith(ZoneWayPoint start, int holdMinTimeMS, int holdMaxTimeMS, int peaceTime)
        {
            this.patrolWith(start, holdMinTimeMS, holdMaxTimeMS, peaceTime);
        }
        bool IGuardUnit.FollowAndAttack(InstanceUnit target, AttackReason reason)
        {
            return this.followAndAttack(target, reason);
        }
        void IGuardUnit.GuardUnit(InstanceUnit vip)
        {
            this.guardUnit(vip);
        }


        public override void doSomething()
        {
            if (CurrentState is StateSkill)
            {
                var target = TracingTarget;
                if (target != null)
                {
                    if (tryMoveScatterTarget(target)) { return; }
                }
            }
            guard();
        }

        /// <summary>
        /// 设置警戒地点,如果在寻路或保护单位,则无效
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        public virtual void setOrginPosition(float x, float y)
        {
            this.mOrginPosition.SetX(x);
            this.mOrginPosition.SetY(y);
        }

        public virtual Vector2 GetOrginPosition()
        {
            return mOrginPosition;
        }

        /// <summary>
        /// 寻路攻击目标
        /// </summary>
        /// <param name="src"></param>
        /// <param name="reason"></param>
        public virtual bool followAndAttack(InstanceUnit src, AttackReason reason)
        {
            if (IsNoneSkill) return false;
            if ((src != null))
            {
                if (Parent.IsAttackable(this, src, SkillTemplate.CastTarget.Enemy, reason, Info))
                {
                    this.SetEnableView(false);
                    mHateSystem.Add(src);
                    if (TracingTarget != src)
                    {
                        //Console.WriteLine(" - - BBBBBB - - " + ((TracingTarget == null) ? "null" : TracingTarget.Name) + ", " + src.Name);
                        mTracingTarget = new StateFollowAndAttack(this, src);
                    }
                    changeState(mTracingTarget);
                    return true;
                }
                else
                {
                    mHateSystem.Remove(src);
                }
            }
            return false;
        }

        /// <summary>
        /// 寻路并一路警戒
        /// </summary>
        /// <param name="path"></param>
        public virtual void attackTo(ZoneWayPoint path, int peaceTime = 0)
        {
            this.mRunningPath = new StateAttackToZoneWayPoint(this, path, peaceTime);
            changeState(this.mRunningPath);
        }
        /// <summary>
        /// 在路点范围内警戒
        /// </summary>
        /// <param name="wp"></param>
        /// <param name="holdMinTimeMS"></param>
        /// <param name="holdMaxTimeMS"></param>
        public virtual void patrolWith(ZoneWayPoint wp, int holdMinTimeMS, int holdMaxTimeMS, int peaceTime = 0)
        {
            this.mRunningPath = new StatePatrolWayPoint(this, wp, holdMinTimeMS, holdMaxTimeMS, peaceTime);
            changeState(this.mRunningPath);
        }
        /// <summary>
        /// 保护单位
        /// </summary>
        /// <param name="vip"></param>
        public virtual void guardUnit(InstanceUnit vip)
        {
            if (mGuardTarget == null || !mGuardTarget.IsActive || mGuardTarget.TargetUnit != vip)
            {
                mGuardTarget = new StateFollowAndGuard(this, vip, this.BodyBlockSize * 2 + vip.BodyBlockSize, Info.GuardRange);
            }
            changeState(mGuardTarget);
        }
        /// <summary>
        /// 待机
        /// </summary>
        public virtual void guard()
        {
            if(mHateSystem != null)
            {
                if (followAndAttack(mHateSystem.GetHated(), AttackReason.Tracing))
                {
                    return;
                }
            }
            mTracingTarget = null;
            SetEnableView(true);
            if (mGuardTarget != null && mGuardTarget.IsActive)
            {
                changeState(this.mGuardTarget);
                return;
            }
            if (mRunningPath != null && !mRunningPath.IsDone)
            {
                changeState(this.mRunningPath);
                return;
            }
            if (mHateSystem != null)
            {
                if (mHateSystem.Count == 0)
                {
                    guardInPosition(mOrginPosition);
                    return;
                }
            }
            base.startIdle();
        }

        public virtual void guardInPosition(Vector2 pos)
        {
            changeState(new StateGuardInPosition(this, pos));
        }

        /// <summary>
        /// 立刻开始返回原点
        /// </summary>
        public virtual void backToOrgin()
        {
            mHateSystem.Clear();
            mTracingTarget = null;

            if (mGuardTarget != null && mGuardTarget.IsActive)
            {
                changeState(this.mGuardTarget);
            }
            else
            {
                mBackToPosition = new StateBackToPosition(this, mOrginPosition);
                changeState(mBackToPosition);
            }

            OnBackToOrgin();
        }

        /// <summary>
        /// 在一定范围内浪
        /// </summary>
        /// <param name="timeMS">浪多久</param>
        /// <param name="range">浪多远</param>
        public virtual void idleMove(int timeMS, int range)
        {
            changeState(new StateIdleMove(this, mOrginPosition, timeMS, range));
        }


        #endregion
        //--------------------------------------------------------------------------------------------------------
        #region Update

        protected override void onUpdateRecover()
        {
            if (mTracingTarget == null)
            {
                base.onUpdateRecover();
            }
        }

        override protected void onUpdate(bool slowRefresh)
        {
            base.onUpdate(slowRefresh);
            updateTracingTarget();
            updateRunningPath();
            updateGuardTarget();
            updateBackToOrgin();
            //updateHate();
            updateView();
        }
        protected virtual void updateTracingTarget()
        {
            if (mTracingTarget != null)
            {
                if (Parent.IsAttackable(this, mTracingTarget.TargetUnit, SkillTemplate.CastTarget.Enemy, AttackReason.Tracing, Info))
                {
                    //有攻击目标//
                    if ((CurrentState is StateSkill))
                    {
                        tryLaunchRandomSkillAndCancelCurrentSkill(TracingTarget, false);
                    }
                    else if (CurrentState is StateIdle)
                    {
                        tryMoveScatterTarget(TracingTarget);
                    }
                }
                else
                {
                    mHateSystem.Remove(mTracingTarget.TargetUnit);
                    if (mTracingTarget == CurrentState)
                    {
                        doSomething();
                    }
                    mTracingTarget = null;
                }
            }
        }
        protected virtual void updateRunningPath()
        {
            if (mRunningPath != null)
            {
                if (CurrentState == mRunningPath)
                {
                    if (mRunningPath.IsDone)
                    {
                        mRunningPath = null;
                    }
                    else if (mRunningPath.Target != null)
                    {
                        mOrginPosition.SetX(this.X);
                        mOrginPosition.SetY(this.Y);
                    }
                }
                else if (CurrentState is StateIdle)
                {
                    changeState(this.mRunningPath);
                }
            }
        }
        protected virtual void updateGuardTarget()
        {
            //如果在寻路或保护,则实时更新OrginPosition//
            if (mGuardTarget != null)
            {
                if (!mGuardTarget.IsActive)
                {
                    mGuardTarget = null;
                }
                else
                {
                    mOrginPosition.SetX(mGuardTarget.TargetUnit.X);
                    mOrginPosition.SetY(mGuardTarget.TargetUnit.Y);
                }
            }
        }
        protected virtual void updateBackToOrgin()
        {
            if (mBackToPosition != null)
            {
                if (mBackToPosition.IsDone)
                {
                    mBackToPosition = null;
                }
            }
            if (Info.GuardRangeLimit > Info.GuardRange)
            {
                //if (mCheckInGuardLimit.Update(Parent.UpdateIntervalMS))
				if(mNextCheckGuardLimit != null && mNextCheckGuardLimit.IsTrigger())
                {
                    if (!CMath.includeRoundPoint(X, Y, Info.GuardRangeLimit, mOrginPosition.X, mOrginPosition.Y))
                    {
                        backToOrgin();
                    }
                    else if (mTracingTarget != null)
                    {
                        if (!mTracingTarget.IsActive || !CMath.intersectRound(
                            X, Y, Info.GuardRangeLimit,
                            mTracingTarget.TargetUnit.X,
                            mTracingTarget.TargetUnit.Y,
                            mTracingTarget.TargetUnit.BodyHitSize))
                        {
                            backToOrgin();
                            return;
                        }
                    }
                }
            }
        }
        protected virtual void updateView()
        {
            if (mViewTrigger != null)
            {
                mViewTrigger.onLookUpdate(X, Y);
            }
        }
        //protected virtual void updateHate(bool slowRefresh, int intervalMS)
        //{
        //    if(slowRefresh && mHateSystem != null)
        //    {
        //        mHateSystem.Update(intervalMS);
        //    }
        //}
        /// <summary>
        /// 攻击间歇,尝试换个位置,避免怪物堆在一个点
        /// </summary>
        protected virtual bool tryMoveScatterTarget(InstanceUnit target)
        {
            //只有单位为非碰撞时,才有这个需求//
            if (!this.IntersectObj)
            {
                if (CommonLang.CUtils.localTimeMS > mCheckAttackSpread  && CUtils.RandomPercent(Parent.RandomN, Templates.CFG.AI_NPC_ATTACK_IDLE_SCATTER_PCT))
                {
					mCheckAttackSpread = CommonLang.CUtils.localTimeMS + Templates.CFG.AI_NPC_ATTACK_IDLE_INTERVAL;

					InstanceUnit block = null;
                    Parent.ForEachNearObjects(X, Y, (InstanceZoneObject o, ref bool cancel) =>
                    {
                        if ((o != this) && (o is InstanceUnit) && Parent.TouchObject2(this, o))
                        {
                            block = o as InstanceUnit;
                            cancel = true;
                        }
                    });
                    if (block != null)
                    {
                        float degree = MathVector.getDegree(X, Y, target.X, target.Y);
                        float distance = this.BodyBlockSize + block.BodyBlockSize;
                        Vector2 turnL = new Vector2(X, Y);
                        Vector2 turnR = new Vector2(X, Y);
                        MathVector.movePolar(turnL, degree + CMath.PI_DIV_2, distance);
                        MathVector.movePolar(turnR, degree - CMath.PI_DIV_2, distance);
                        float dl = MathVector.getDistanceSquare(turnL.X, turnL.Y, target.X, target.Y);
                        float dr = MathVector.getDistanceSquare(turnR.X, turnR.Y, target.X, target.Y);
                        if (dl < dr)
                        {
                            this.startMoveTo(turnL.X, turnL.Y);
                        }
                        else
                        {
                            this.startMoveTo(turnR.X, turnR.Y);
                        }
                        return true;
                    }
                }
            }
            return false;
        }

        #endregion
        //--------------------------------------------------------------------------------------------------------
        #region InternalEvents

        protected virtual void onUnitActivated(InstanceUnit unit)
        {
            initViewTrigger();
        }

        protected override void onStateChanged(State old_state, State state)
        {
            if (state is StateIdle)
            {
                followAndAttack(mHateSystem.GetHated(), AttackReason.Tracing);
            }
            if (old_state != null)
            {
                if (old_state == mBackToPosition)
                {
                    mBackToPosition = null;
                }
                if (old_state == mTracingTarget)
                {
                    if (mTracingTarget.IsNoWay)
                    {
                        mHateSystem.Remove(mTracingTarget.TargetUnit);
                        mTracingTarget = null;
                    }
                }
            }
        }

        protected override void onMoveBlockWithObject(InstanceZoneObject obj)
        {
            if (IsNoneSkill)
            {
                return;
            }
            if (obj is InstanceUnit)
            {
                followAndAttack(obj as InstanceUnit, AttackReason.MoveBlocked);
            }
        }
        protected override bool onBlockOther(InstanceZoneObject obj)
        {
            if (CurrentActionStatus == UnitActionStatus.Move)
            {
                return true;
            }
            if (CurrentActionStatus == UnitActionStatus.Idle)
            {
                //给自己友军让路//
                if (obj is InstanceUnit)
                {
                    InstanceUnit u = obj as InstanceUnit;
                    if (u.Force == this.Force)
                    {
                        return changeState(new StateMoveAway(this, u));
                    }
                }
            }
            return false;
        }

        protected override void onDamaged(InstanceUnit attacker, AttackSource attack, int reduceHP)
        {
            if (IsNoneSkill)
            {
                return;
            }

			if(attacker.IsPet)
			{
				InstanceUnit master = attacker.Virtual.GetMasterUnit();
				if(master == null)
				{
					log.Warn("onDamaged: 找不到宠物主人:" + attacker.Info.ID + ", " + attacker.Parent.GetSceneID());
				}
				else
				{
					attacker = master;
				}
			}

            // 被攻击转火
            mHateSystem.OnHitted(attacker, attack, reduceHP);
            onAddEnemy(attacker, true, AttackReason.Damaged);
        }



        protected virtual void onAddEnemy(InstanceUnit target, bool group, AttackReason reason)
        {
            if (onAddEnemyInternal(target, group, reason))
            {
                if (group && Info.GuardRangeGroup > 0)
                {
                    Parent.ForEachNearObjects(X, Y, Info.GuardRangeGroup, (InstanceZoneObject o, ref bool cancel) =>
                    {
                        if ((o != this) && (o is InstanceGuard))
                        {
                            InstanceGuard g = o as InstanceGuard;
                            if (g.Force == this.Force && Parent.IsAttackable(g, target, SkillTemplate.CastTarget.Enemy, AttackReason.Look, Info))
                            {
                                if (CMath.includeRoundPoint(g.X, g.Y, g.Info.GuardRangeLimit, target.X, target.Y))
                                {
                                    g.onAddEnemyInternal(target, true, reason);
                                }
                            }
                        }
                    });
                }
            }
        }
        protected bool onAddEnemyInternal(InstanceUnit target, bool group, AttackReason reason)
        {
            bool attack = true;
            if (mOnEnemyAdded != null)
            {
                mOnEnemyAdded.Invoke(this, target, ref attack);
            }
            if (attack)
            {
                if (!mHateSystem.Contains(target))
                {
                    mHateSystem.Add(target);
                }
                followAndAttack(mHateSystem.GetHated(), reason);
            }
            return attack;
        }

        protected virtual void OnBackToOrgin()
        {

        }



        #endregion
        //--------------------------------------------------------------------------------------------------------
        #region Events

        protected override void clearEvents()
        {
            base.clearEvents();
            mOnEnemyAdded = null;
        }

        public delegate void EnemyAdded(InstanceUnit unit, InstanceUnit enemy, ref bool attack);

        private EnemyAdded mOnEnemyAdded;

        [EventTriggerDescAttribute("Add敌人")]
        public event EnemyAdded OnEnemyAdded { add { mOnEnemyAdded += value; } remove { mOnEnemyAdded -= value; } }

        #endregion
        //--------------------------------------------------------------------------------------------------------

        /// <summary>
        /// 移动状态
        /// </summary>
        public class StateMoveAway : State
        {
            private Vector2 target;
            private InstanceUnit other;
            public StateMoveAway(InstanceGuard unit, InstanceUnit other)
                : base(unit)
            {
                this.other = other;
                this.target = new Vector2(unit.X, unit.Y);
                float angle = MathVector.getDegree(other.X, other.Y, unit.X, unit.Y);
                angle = (float)(-CMath.PI_DIV_2 + unit.RandomN.NextDouble() * CMath.PI_F);
                MathVector.movePolar(target, angle, (unit.BodyBlockSize));
            }
            override public bool onBlock(State new_state)
            {
                return true;
            }
            override protected void onStart()
            {
                unit.SetActionStatus(UnitActionStatus.Move);
            }
            override protected void onUpdate()
            {
                unit.SetActionStatus(UnitActionStatus.Move);
                unit.faceTo(target.X, target.Y);
                MoveBlockResult result = unit.moveBlockTo(target.X, target.Y, unit.MoveSpeedSEC, zone.UpdateIntervalMS);
                if ((result.result & MoveResult.RESULTS_MOVE_END) != 0)
                {
                    InstanceGuard guard = (unit as InstanceGuard);
                    guard.doSomething();
                }
            }
            override protected void onStop()
            {

            }
        }

        //----------------------------------------------------------------------------------------------------------

    }

    //--------------------------------------------------------------------------------------------------------

    public class InstanceSummon : InstanceGuard, ISummonedUnit
    {
        public InstanceUnit SummonerUnit { get; set; }

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

        override protected void onUpdate(bool slowRefresh)
        {
            base.onUpdate(slowRefresh);
            if ((PassTimeMS >= Info.LifeTimeMS) || (SummonerUnit != null && SummonerUnit.IsDead()))
            {
                kill();
            }
        }
    }

    //--------------------------------------------------------------------------------------------------------


}