using System;
using System.Collections.Generic;
using System.Reflection;
using System.Threading.Tasks;
using AppGame;
using Cysharp.Threading.Tasks;
using DotRecast.Core.Collections;
using Google.Protobuf;
using Plugins.JNGame.Network.Entity;
using Plugins.JNGame.Network.Util;
using Plugins.JNGame.System;
using Plugins.JNGame.Util;

namespace Plugins.JNGame.Network
{
    /// <summary>
    /// 基础客户端网络类
    /// </summary>
    public abstract class JNClientBase : SystemBase
    {
        
        //消息Id
        protected int _id = 0;

        //创建通知
        protected EventDispatcher _event = new();
        
        //计入字节大小
        protected Dictionary<int, int> _byteSize = new();
        
        //回调消息
        protected Dictionary<int, UniTaskCompletionSource<byte[]>> _callback = new ();

        public void SetEvent(EventDispatcher dispatcher)
        {
            _event = dispatcher;
        }
        //外部监听消息
        public void AddListener(int hId,Action<byte[]> listener)
        {
            _event.AddListener($"{hId}",listener);
        }
        //删除外部监听
        public void RemoveListener(int hId,Action<byte[]> listener)
        {
            _event.RemoveListener($"{hId}",listener);
        }
        
        //通知消息
        public virtual void Dispatch(JNetParam data)
        {
            _byteSize[data.HId] = data.Bytes.Length;
            
            //判断是否是回调消息
            if (data.HId <= 0)
            {
                //回调消息
                _callback.TryGetValue(data.ID,out var task);
                if (task is null) return;
                task.TrySetResult(data.Bytes);
            }
            else
            {
                //通知消息
                _event.Dispatch($"{data.HId}",data.Bytes);
            }
            
        }

        //向服务器发送消息
        public virtual void Send(int hId,IMessage data = null)
        {
            var bytes = NDataUtil.Encrypt(JNetParam.Build(this._id++, hId).SetData(data));
            _byteSize[hId] = bytes.Length;
            SendBytes(bytes);
        }
        
        //向服务器发送消息(有回调的消息)
        public virtual async Task<byte[]> SendCallback(int hId,IMessage data = null,int timeout = 1000)
        {
            var id = this._id++;
            _callback[id] = new UniTaskCompletionSource<byte[]>();
            var bytes = NDataUtil.Encrypt(JNetParam.Build(id, hId).SetData(data));
            SendBytes(bytes);
            var message = await UniTask.WhenAny(_callback[id].Task, UniTask.Delay(timeout));
            return message.result;
        }

        public virtual void SendBytes(byte[] data){ }
        
        //获取字节大小
        public int GetByteSize(int hId = 0)
        {
            if (hId == 0)
            {
                int size = 0;
                _byteSize.ForEach(child =>
                {
                    size += child.Value;
                });
                return size;
            }
            return _byteSize.GetValueOrDefault(hId, 0);
        }

    }
}