using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using AppGame.Systems;
using DotRecast.Core.Collections;
using Game.Input;
using Game.JNGFrame.View;
using Game.JNGState.Logic.Data;
using JNGame.Math;
using JNGame.Sync.State.Tile;
using JNGame.Sync.System;
using JNGame.Sync.System.Data;
using JNGame.Util;
using Plugins.JNGame.Network.Action;
using UnityEngine;

namespace AppGame.Sync
{
    public class JNGTileClientSystem : JNSSTileClientService
    {
        
        //区块Socket
        public Dictionary<int, JNGClient> Sockets = new ();
        
        //玩家位置 和 区块
        public LVector3? PlayerPos;
        public int? PlayerTile;
        
        public override void Initialize()
        {
            
            
            base.Initialize();
            //默认玩家位置
            SetPlayerPosition(LVector3.Zero);
            
            //定时更新Socket
            Timers.Instance.SetInterval(1f, UpdateTileSocket);

        }

        protected override int[][] Tiles => new[]
        {
            new[] { 1, 2, 3 },
            new[] { 4, 5, 6 },
            new[] { 7, 8, 9 },
        };

        protected override int TileSize => 100;

        public override SLogicSystem[] NewLogicSystems()
        {
            return new SLogicSystem[]
            {

                //基础数据
                new DInputSystem(),         //游戏输入
                
            };
        }
        
        public override SDataSystemBase[] NewDataSystems()
        {
            return new SDataSystemBase[] {
                new EDNodeDataSystem(SStateDataEnum.Client),         //游戏数据
                new EDPlayerDataSystem(SStateDataEnum.Client),       //游戏数据
                new EDBossDataSystem(SStateDataEnum.Client),       //游戏数据
            };
        }
        
        public override SViewSystem[] NewViewSystems()
        {
            return new SViewSystem[]
            {
                //视图层
                new DViewSystem(),  //游戏视图
            };
        }
        
        protected override void OnRunSimulate()
        {
            //更新玩家位置
            UpdatePlayerPosition();
            
            base.OnRunSimulate();
            //发送输入
            OnSendInput();
            
        }
        
        /// <summary>
        /// 发送输入 (正常服务器是不需要发送输入的 这里用于测试)
        /// </summary>
        private void OnSendInput()
        {
            var inputs = GetSystem<DInputSystem>().Dequeue();
            if (inputs.Inputs.Count > 0)
            {
                //发送帧数据给服务端
                JNStateTileInputs tileInputs = new JNStateTileInputs()
                {
                    TId = PlayerTile ?? (Sockets.Keys.Count > 0 ? Sockets.Keys.Last() : 0),
                    Message = inputs
                };
                App.Client.Send((int)NActionEnum.NSyncTileInput,tileInputs);
            }
        }

        /// <summary>
        /// 设置玩家位置
        /// </summary>
        public void SetPlayerPosition(LVector3 pos)
        {
            PlayerPos = pos;
            int index = GetTileIndex(pos);
            if (PlayerTile != index)
            {
                PlayerTile = index;
                App.Event.Dispatch(GEvent.GSwPlayerTile);
            }
        }

        /// <summary>
        /// 更新玩家位置
        /// </summary>
        public void UpdatePlayerPosition()
        {
            if (PlayerPos is null) return;
            
            List<int> ids = GetTileGridIndex(PlayerPos.Value);
            
            ids.ForEach(AddTileShow);
            TileShow.ToArray().ForEach(id =>
            {
                if (!(ids.Contains(id)))
                {
                    RemoveTileShow(id);
                }
            });

        }


        /// <summary>
        /// 更新区块Socket
        /// </summary>
        public void UpdateTileSocket()
        {
            TileShow.ForEach(index =>
            {
                if (!IsTileConnect(index))
                {
                    AddSocket(index);
                }
            });
            var keysToRemove = Sockets.Keys.Where(key => !TileShow.Contains(key)).ToList();  
            foreach (var key in keysToRemove)  
            {
                RemoveSocket(key);
            }
        }
        
        /// <summary>
        /// 判断是否当前区块是否连接
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        public bool IsTileConnect(int index)
        {
            return Sockets.ContainsKey(index);
        }
        
        protected async Task AddSocket(int index,TileServerInfo info = null)
        {
            if (IsTileConnect(index)) return;
            
            var client = new JNGClient();
            Sockets.Add(index,client);
            
            //获取连接
            if (info is null)
            {
                var message = (await App.GAPI.NSyncTileServer(index));
                info = message.data;
            }
            
            if (info is not null)
            {
                client.SetPoint($"{info.ip}:{info.port}");
                client.SetTileServer(info.server);
            
                if (IsTileConnect(index))
                {
                    Debug.Log($"[{index}] 连接 Socket");
                    App.Client.AddClient(client);
                }
            }
            else
            {
                Sockets.Remove(index);
            }
            
        }

        public async Task SwSocket(int index,TileServerInfo info)
        {
            RemoveSocket(index);
            await AddSocket(index, info);
        } 
        
        protected void RemoveSocket(int index)
        {
            if (Sockets.TryGetValue(index,out var client))
            {
                Debug.Log($"[{index}] 卸载 Socket");
                App.Client.RemoveClient(client);
            }
            Sockets.Remove(index);
            //并且释放数据
            GetSystems<ISTileDataSystem>().ForEach(data =>
            {
                data.ClearTileData(index);
            });
        }
        public void RemoveSocket(string server)
        {
            Sockets.ToArray().ForEach(tile =>
            {
                if (tile.Value.TileServer != server) return;
                tile.Value.OnClose();
                Sockets.Remove(tile.Key);
                //并且释放数据
                GetSystems<ISTileDataSystem>().ForEach(data =>
                {
                    data.ClearTileData(tile.Key);
                });
            });
        }
    }
}