using System;
using System.IO;
using System.Net;
using DotNetty.Buffers;
using dotNetty_kcp;
using UnityEngine;
using Guru;
using Dof;

public class KcpDofClient : KcpListener
{
    public Action OnConnected;
    public Action<ServerMessage> OnServerMessage;

    private Ukcp _ukcp;
    private KcpClient _kcpClient;
    private MemoryStream _localSendMs = new (1024 * 1024 * 1);

    public long Cid { get; private set; }

    public KcpDofClient()
    {
        // 指定DotNetty日志的显示级别
        DotNetty.Unity.UnityLoggerFactory.Default.Level = DotNetty.Unity.Level.ERROR;
    }

    public async void Connect(string ip_str, int port)
    {
        var channelConfig = new ChannelConfig();
        channelConfig.initNodelay(true, 40, 2, true);
        channelConfig.Sndwnd = 512;
        channelConfig.Rcvwnd = 512;
        channelConfig.Mtu = 512;
        channelConfig.FecDataShardCount = 10;
        channelConfig.FecParityShardCount = 3;
        channelConfig.AckNoDelay = true;
        channelConfig.Crc32Check = false;
        channelConfig.UseConvChannel = true;
        //channelConfig.Conv = UnityEngine.Random.Range(1, int.MaxValue);
        channelConfig.TimeoutMillis = 10000;

        _kcpClient = new KcpClient();
        _kcpClient.init(channelConfig);

        var remoteAddress = new IPEndPoint(IPAddress.Parse(ip_str), port);
        var task = _kcpClient.BindLocal();
        await task;
        var channel = task.Result;
        _ukcp = _kcpClient.connect(channel, remoteAddress, channelConfig, this);
    }

    public void Send(ClientMessage msg)
    {
        _localSendMs.SetLength(0);
        _localSendMs.Position = 0;

        ProtobufHelper.ToStream(msg, _localSendMs);
        
        var dataBuf = Unpooled.DirectBuffer(1024 * 1024 * 1);
        dataBuf.WriteBytes(_localSendMs.GetBuffer(), 0, (int)_localSendMs.Length);
        _ukcp.write(dataBuf);
        dataBuf.Release();
    }

    public void Close()
    {
        _kcpClient.stop();
    }

    public void onConnected(Ukcp ukcp)
    {
        Debug.Log($"[KcpDofClient]onConnected");

        if (OnConnected != null)
        {
            Loom.QueueOnMainThread(() =>
            {
                OnConnected.Invoke();
            });
        }
    }

    /// <summary>
    /// kcp 接收到消息的回调函数
    /// </summary>
    /// <param name="byteBuf">接收到的消息buffer</param>
    /// <param name="ukcp">kcp连接</param>
    public void handleReceive(IByteBuffer byteBuf, Ukcp ukcp)
    {
        Debug.Log("[KcpDofClient]handleReceive");

        var ms = new MemoryStream(1024 * 1024 * 1);
        var data_len = byteBuf.ReadableBytes;
        byteBuf.ReadBytes(ms, data_len);
        var msg = ProtobufHelper.FromBytes(typeof(ServerMessage), ms.GetBuffer(), 0, data_len);
        var server_msg = msg as ServerMessage;

        if (server_msg != null)
        {
            ServerMessageHandler(server_msg);
        }
        else
        {
            Debug.LogError("[KcpDofClient]handleReceive: Fail to Deserialize ServerMessage");
        }
    }

    public void handleException(Exception ex, Ukcp ukcp)
    {
        Debug.LogError($"[KcpDofClient]{ex}");
    }

    public void handleClose(Ukcp ukcp)
    {
    }

    void ServerMessageHandler(ServerMessage msg)
    {
        if (msg.PlayerEntered != null)
        {
            Cid = msg.PlayerEntered.Cid;
            Debug.Log($"Player Enter cid: {Cid}");
        }
        else if (msg.GameStart != null)
        {
            Debug.Log($"Game Start");
        }
        else if (msg.LevelStart != null)
        {
            Debug.Log($"Level Start");
        }
        else if (msg.PointFound != null)
        {
            Debug.Log($"Point Found");
        }
        else if (msg.GameFinish != null)
        {
            Debug.Log($"Game Finish");
        }
        else
        {
            Debug.LogError($"Unhandled ServerMessage");
        }

        if (OnServerMessage != null)
        {
            Loom.QueueOnMainThread(() =>
            {
                OnServerMessage.Invoke(msg);
            });
        }
    }

}
