using CommonAI;
using CommonAI.RTS;
using CommonAI.Zone;
using CommonAI.Zone.Helper;
using CommonAI.Zone.Instance;
using CommonLang;
using CommonLang.Log;
using CommonLang.Vector;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using XmdsCommonServer.Message;
using XmdsCommonServer.Plugin.Units;

namespace XmdsServerNode.CheatingDeath
{
    public class MoveSpeedChecker
    {
        private static Logger _log;
        private static Logger log
        {
            get { if (_log == null) _log = LoggerFactory.GetLogger("GapChecker"); return _log; }
        }

        private readonly XmdsInstancePlayer mActor;
        private Vector2 mLastPos = new Vector2();
        private long mLastCheckTime = CUtils.CurrentTimeMS;
        private bool mCheckFlag = false;

        public MoveSpeedChecker(InstancePlayer player)
        {
            this.mActor = player as XmdsInstancePlayer;
            this.mActor.OnUpdate += MActor_OnUpdate;
            this.mActor.OnObjectSendingEvent += MActor_OnObjectSendingEvent;
            this.mActor.OnHandleAction += MActor_OnHandleAction;
            this.mActor.OnRemoved += MActor_OnRemoved;
			this.mActor.OnRegionTransport += MActor_OnRegionTransport;
			this.mLastPos.SetX(mActor.X);
            this.mLastPos.SetY(mActor.Y);
        }


		private void MActor_OnRemoved(InstanceUnit unit)
        {
            this.mActor.OnUpdate -= MActor_OnUpdate;
            this.mActor.OnObjectSendingEvent -= MActor_OnObjectSendingEvent;
            this.mActor.OnHandleAction -= MActor_OnHandleAction;

			this.mActor.OnRemoved -= MActor_OnRemoved;
			this.mActor.OnRegionTransport -= MActor_OnRegionTransport;
		}

		private void MActor_OnRegionTransport()
		{
			this.mLastPos.SetX(mActor.X);
			this.mLastPos.SetY(mActor.Y);
		}

		private void MActor_OnHandleAction(InstanceUnit unit, ObjectAction act)
        {
            if (act is UnitUpdatePosAction)
            {
                var sync = act as UnitUpdatePosAction;
                mCheckFlag = true;
            }
        }

		public void setFrameNotCheckFlag()
		{
			mCheckFlag = false;
		}

        private void MActor_OnObjectSendingEvent(InstanceZoneObject obj, ref CommonAI.Zone.ObjectEvent evt)
        {
            if (evt is UnitForceSyncPosEvent)
            {
                this.mLastPos.SetX(mActor.X);
                this.mLastPos.SetY(mActor.Y);
				//Console.WriteLine("UnitForceSyncPosEvent : " + mActor.X + ", " + mActor.Y);
            }
        }

        private void MActor_OnUpdate(InstanceUnit unit)
        {
            if (!mActor.IsLock)
            {
                if (mCheckFlag)
                {
                    mCheckFlag = false;
                    var curtime = CUtils.CurrentTimeMS;
                    var intervalMS = (int)(curtime - mLastCheckTime);
                    this.mLastCheckTime = curtime;
                    //以每次上传坐标的时间间隔来检测,避免客户端包积压,一次发N个包导致的瞬移//
                    if (CheckCheating(intervalMS))
                    {
                        mActor.Lock(CheatingDeathConfig.CHEATER_LOCK_TIME_MS);
                        CheatingDeathManager.SendPlayerException(mActor, "speed too faster");
                    }
                }
            }
            else
            {
                mActor.transport(mLastPos.X, mLastPos.Y);
            }
            this.mLastPos.SetX(mActor.X);
            this.mLastPos.SetY(mActor.Y);
        }

        //移动偏差累加//
        private float over_move_distance = 0;
        //移动错误累加//
        private float over_move_tick = 0;

        protected virtual bool CheckCheating(int intervalMS)
        {
            if (mActor.CurrentActionStatus == UnitActionStatus.Move)
            {
                var expectDistance = MoveHelper.GetDistance(intervalMS, mActor.MoveSpeedSEC);
                var moveDistance = MathVector.getDistance(mLastPos.X, mLastPos.Y, mActor.X, mActor.Y);
                var delta = moveDistance - expectDistance;
                //计算预期移动距离和实际移动距离偏差//
                over_move_distance += delta;
                if (over_move_distance < 0)
                {
                    over_move_distance = 0;
                }
                else if (over_move_distance > CheatingDeathConfig.TOTAL_EXCEPTION_MOVE_DISTANCE_LIMIT)
                {
                    //位移偏差累加到阀值,错误增加1//
                    //PrintSpeed(delta, moveDistance, expectDistance);
                    over_move_distance = 0;
                    over_move_tick++;
                    mActor.transport(mLastPos.X, mLastPos.Y);
                    if (over_move_tick > CheatingDeathConfig.TOTAL_EXCEPTION_COUNT)
                    {
                        //累计N次错误,则判定为作弊//
                        over_move_tick = 0;
                        return true;
                    }
                }
                return false;
            }
            else
            {
                var expectDistance = MoveHelper.GetDistance(intervalMS, mActor.MoveSpeedSEC);
                over_move_distance -= expectDistance;
                if (over_move_distance < 0)
                {
                    over_move_tick = 0;
                    over_move_distance = 0;
                }
                return false;
            }
        }
        protected void PrintSpeed(float delta, float moveDistance, float expectDistance)
        {
            //Console.WriteLine(string.Format("Check move : total={0} delta={1} move_distance={2} expect_distance={3}",
            //    over_move_distance,
            //    delta,
            //    moveDistance,
            //    expectDistance
            //    ));
        }
	}
}