using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Cysharp.Threading.Tasks;
using Game.Plugins.JNGame.Sync.Frame;
using Google.Protobuf;
using Plugins.JNGame.Sync.Frame.Entity;
using Plugins.JNGame.Sync.Frame.game;
using Plugins.JNGame.Sync.Frame.game.Time;
using Plugins.JNGame.System;
using Plugins.JNGame.Util;
using UnityEngine;
using UnityEngine.SceneManagement;

namespace Plugins.JNGame.Sync.Frame
{

    //帧同步 通知
    public interface JNSyncFrameEvent
    {
        static string CLEAR = "JNSyncFrameEvent_CLEAR";
        static string CREATE = "JNSyncFrameEvent_CREATE";
        static string FRAME = "JNSyncFrameEvent_FRAME";
    }
    
    public abstract class JNSyncFrame : SystemBase
    {
        
        //同步时间 (和服务器保持一致)
        private int _nSyncTime = 67;
        //大于多少帧进行追帧
        private int _nMaxFrameBan = 4;
        //大于多少帧进行快速追帧
        private int _nMaxFrameLoopBan = 20;
        //将服务器帧数进行平分
        private int _nDivideFrame = 2;
        
        public int NSyncTime => _nSyncTime;
        public int NMaxFrameBan => _nMaxFrameBan;
        public int NMaxFrameLoopBan => _nMaxFrameLoopBan;
        public int NDivideFrame => _nDivideFrame;
        
        
        //帧队列
        private Queue<JNFrameInfo> _nFrameQueue = new();

        
        //本地已执行帧数
        private int _nLocalRunFrame = 0;
        //本地帧数
        private int _nLocalFrame = 0;
        //服务器的帧
        private int _nServerFrame = 0;

        public int NLocalRunFrame => _nLocalRunFrame;
        public int NLocalFrame => _nLocalFrame;
        public int NServerFrame => _nServerFrame;

        //暂存帧列表
        private Dictionary<int,JNFrameInfo> _nFrameTempQueue = new();
        
        //需要同步的Actor
        private List<IJNSyncFrameComponent> _nSyncActors = new();
        //需要被删除的Action
        private List<IJNSyncFrameComponent> _nDelSyncActors = new();
        
        //ID 每添加 JNSyncFrameComponent + 1
        public Func<int> nSyncID = RandomUtil.Next(0);
        
        //随机数
        public Func<float> nRandom = RandomUtil.SyncRandom();
        
        //随机数double
        public Func<float,float,float> nRandomFloat = RandomUtil.SyncRandomFloat();
        
        //随机数整数
        public Func<int, int, int> nRandomInt = RandomUtil.SyncRandomInt();
        
        //是否开始同步
        Boolean _isStart = false;
        
        //是否请求后台数据
        private Boolean _isRequestServerData = false;

        public bool IsRequestServerData => _isRequestServerData;

        //帧更新
        int dtTotal = 0;
        //输入更新
        int dtInputTotal = 0;
        
        //是否在追帧
        private Boolean _isLoop = false;
        public bool IsLoop => _isLoop;

        public JNTime Time => (new JNTime(this));
        
        //执行时间
        public long frameTime = 0;

        //是否正在执行
        private Boolean isRun = false;
        
        public override Task OnInit()
        {
            Physics.autoSimulation = false;
            Physics.autoSyncTransforms = false;
            this.OnReset();
            return Task.CompletedTask;
        }

        //开始
        public void OnStart()
        {
            this._isStart = true;
            // thread = new Thread(() =>
            // {
            //     this._isStart = true;
            //     while (true)
            //     {
            //         this.Update(33);
            //         Thread.Sleep(33);
            //     }
            // });
            // thread.Start();
        }
        
        //重置数据
        public void OnReset()
        {
            
            EventDispatcher.Event.Dispatch(JNSyncFrameEvent.CLEAR);
            
            this._isStart = false;
            this.nSyncID = RandomUtil.Next(0);
            this.nRandom = RandomUtil.SyncRandom();
            this.nRandomFloat = RandomUtil.SyncRandomFloat();
            this.nRandomInt = RandomUtil.SyncRandomInt();
            this._nSyncActors = new();
            this._nDelSyncActors = new();
            this._nFrameQueue = new();
            this._nFrameTempQueue = new();
            this._nLocalFrame = 0;
            this._nServerFrame = 0;
            this._nLocalRunFrame = 0;
            this.dtTotal = 0;
            this.dtInputTotal = 0;
            this._isRequestServerData = false;
            
            // Physics.SyncTransforms();
            
            //清除定时器
            SingletonUtil<JNFrameTime>.Clean();
            
            EventDispatcher.Event.Dispatch(JNSyncFrameEvent.CREATE);
            
        }
        
        //更新同步
        public void Update(int dt)
        {
            
            if(!_isStart) return;
            dtTotal += dt;
            dtInputTotal += dt;
            // if (isRun)
            // {
            //     return;
            // }
            // isRun = true;

            try
            {
                int nSyncTime = this.DyTime();


                if (nSyncTime > 0)
                {
                    this._isLoop = false;
                    while (nSyncTime != 0 && this.dtTotal > nSyncTime && _nFrameQueue.Count > 0)
                    {
                        this.OnUpdate();
                        this.dtTotal -= nSyncTime;
                        nSyncTime = this.DyTime();
                    }
                }
                else
                {
                    this._isLoop = true;
                    //追帧运行 保持前端 15 帧 刷新
                    long endTime = (new DateTimeOffset(DateTime.UtcNow)).ToUnixTimeMilliseconds() + 100;
                    // && ((new DateTimeOffset(DateTime.UtcNow)).ToUnixTimeMilliseconds()) < endTime
                    while (this.DyTime() == 0 && ((new DateTimeOffset(DateTime.UtcNow)).ToUnixTimeMilliseconds()) < endTime)
                    {
                        this.OnUpdate();
                    }
                    dtTotal = 0;
                }


                //更新输入
                if (this.dtInputTotal > (this._nSyncTime / this._nDivideFrame))
                {
                    this.dtInputTotal = 0;
                    this.OnInput();
                }
            }
            catch (Exception e)
            {
                Debug.LogError(e.Message);
            }
            // isRun = false;
            
        }
        
        //运行操作
        private void OnInput()
        {
            
            //输入数据
            JNFrameInputs inputs = new JNFrameInputs();
            
            
            //收集帧数据
            this._nSyncActors.ForEach(action =>
            {
                if (action.IsInput())
                {
                    //如果输入了 则添加到输入数据
                    var input = new JNFrameInput();
                    input.NId = action.NID;
                    var data = action.Encoder();
                    input.Input = ByteString.CopyFrom(data);
                    inputs.Inputs.Add(input);
                }
                action.ClearInput();
            });
            
            //发送帧操作
            if (inputs.Inputs.Count > 0)
            {
                this.OnSendInput(inputs);
            }
            
        }

        //运行帧
        private void OnUpdate()
        {
            if(!(_nFrameQueue.TryDequeue(out var frame))) return;
            
            var second = (new DateTimeOffset(DateTime.UtcNow)).ToUnixTimeMilliseconds();

            if(frame.Index != 0)
                this._nLocalRunFrame = frame.Index;
            
            int dt = this._nSyncTime / this._nDivideFrame;
            
            
            //拆出输入
            Dictionary<int, JNFrameInput> inputs = new();
            foreach (var message in frame.Messages)
            {
                inputs[message.NId] = message;
            }

            // Debug.Log(inputs.Count);
            
            //运行生命周期
            this._nSyncActors.ForEach(child =>
            {
                if (!child.IsRunStart)
                {
                    child.IsRunStart = true;
                    child.OnSyncStart();
                }
            });
            
            //运行之前帧
            this._nSyncActors.ForEach(child =>
            {
                MethodInfo OnSyncUpdate = child.GetType().GetMethod("OnLateSyncUpdate");
                MethodInfo Decoder = child.GetType().GetMethod("Decoder");
                if (inputs.ContainsKey(child.NID))
                {
                    OnSyncUpdate.Invoke(child,new []{dt,frame,Decoder.Invoke(child,new object[]{ inputs[child.NID].Input.ToByteArray() })});
                }
                else
                {
                    OnSyncUpdate.Invoke(child,new []{ dt,frame,(object)null });
                }
            });
            
            //更新帧
            this._nSyncActors.ForEach(child =>
            {
                MethodInfo OnSyncUpdate = child.GetType().GetMethod("OnSyncUpdate");
                MethodInfo Decoder = child.GetType().GetMethod("Decoder");
                if (inputs.ContainsKey(child.NID))
                {
                    OnSyncUpdate.Invoke(child,new []{dt,frame,Decoder.Invoke(child,new object[]{ inputs[child.NID].Input.ToByteArray() })});
                }
                else
                {
                    OnSyncUpdate.Invoke(child,new []{ dt,frame,(object)null });
                }
            });
            
            //执行定时器
            SingletonUtil<JNFrameTime>.Instance.Update(dt);
            //执行下一帧物理
            // Physics.Simulate((float)dt / 1000);
            // Physics.SyncTransforms();
            
            //并发
            // await JNFrameUtil.Parallel(this._nSyncActors,dt,frame);
            
            //删除Action
            this._nDelSyncActors.ForEach(child =>
            {
                this._nSyncActors.Remove(child);
            });
            this._nDelSyncActors.Clear();

            this.frameTime = (new DateTimeOffset(DateTime.UtcNow)).ToUnixTimeMilliseconds() - second;

        }
        
        //自适应间隔时间
        public int DyTime(){
            int dt = this._nSyncTime / this._nDivideFrame;
            int loop = dt;

            //大于nMaxFrameBan 进行 追帧
            if(this._nFrameQueue.Count > this._nMaxFrameBan) {
                    
                //计算超过的帧数
                int exceed = this._nFrameQueue.Count - this._nMaxFrameBan;
                int most = this._nMaxFrameLoopBan - this._nMaxFrameBan;
                int ldt = ((most - exceed) / most) * dt;
            
                //自适应追帧算法
                if(exceed <= this._nMaxFrameLoopBan){
                    loop = ldt;
                }else{
                    loop = 0;
                }
            }else{
                loop = dt;
            }
            
            return loop;
        }
        
        /**
         * 接收帧数据
         * @param frame 帧数据
         * @param isLatestData 是否最新的帧数据
         */
        public void AddInput(JNFrameInfo frame,Boolean isLatestData = true)
        {

            if (!_isStart) return;
            
            if(isLatestData)
            {
                this._nServerFrame = frame.Index;
                //     //如果推的帧小于本地帧 则 重开
                //     if(frame.Index < _nLocalFrame){
                //         OnReset();
                //         OnStart();
                //         return;
                //     }
            }
            
            //我需要的下一帧
            int index = _nLocalFrame + 1;
            
            //判断接受的帧是否下一帧 如果不是则加入未列入
            if (frame.Index != index){
                
                _nFrameTempQueue.TryAdd(frame.Index,frame);
                
                //在未列入中拿到需要的帧
                JNFrameInfo tamp = null;

                if ((tamp = _nFrameTempQueue.GetValueOrDefault(index,null)) == null)
                {

                    var that = this;
                    
                    //如果没有则向服务器请求我需要的帧数
                    if (!that._isRequestServerData)
                    {
                        
                        that._isRequestServerData = true;
                        
                        //请求
                        that.OnServerData(this._nLocalFrame, 0).ContinueWith(infos =>
                        {
                            foreach (var frameInfo in infos.Frames)
                            {
                                if(frameInfo.Index >= this._nLocalFrame)
                                    that.AddInput(frameInfo,false);
                            }
                            that._isRequestServerData = false;
                        }).Forget();
                        
                    }

                    return;
                    
                }
                else
                {
                    //如果有则覆盖
                    frame = tamp;
                }

            }
            
            //删除临时帧
            _nFrameTempQueue.Remove(frame.Index);
            
            _nLocalFrame = index;
            
            //分帧插入
            _nFrameQueue.Enqueue(frame);
            for (var i = 0; i < this._nDivideFrame - 1; i++) {
                _nFrameQueue.Enqueue(new JNFrameInfo());            
            }

        }

        //添加同步组件
        public void AddSyncActor(IJNSyncFrameComponent sync){
            if(!this._nSyncActors.Contains(sync)){
                this._nSyncActors.Add(sync);
            }
        }

        //销毁同步组件
        public void DelSyncActor(IJNSyncFrameComponent sync){
            if(!this._nSyncActors.Contains(sync)){
                this._nDelSyncActors.Add(sync);
            }
        }
        
        //发送帧数据
        protected abstract void OnSendInput(JNFrameInputs inputs);
        //获取帧数据
        protected abstract UniTask<JNFrameInfos> OnServerData(int start,int end);
        
    }
}