using NativeWebSocket;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using UnityEngine;

[XLua.LuaCallCSharp]
public class WebsocketMgr 
{
    [XLua.CSharpCallLua]
    public delegate void WebsocketCallback(string evventName,string msg);
    readonly Dictionary<string, WebSocket> wsDict = new();
    static WebsocketMgr _instance = null;
    int reconnectDelay = 10000;
    int maxReconnectDelay = 60000 * 1;

    public static WebsocketMgr Instance
    {
        get
        {
            if (_instance == null)
            {
                _instance = new();
            }
            return _instance;
        }
    }
    public void Connect(string name, string address, WebsocketCallback callback)
    { 
        ConnectAsync(name, address, callback);
    }
    async void ConnectAsync(string name, string address, WebsocketCallback callback)
    {
        WebSocket websocket = new(address);
        if (wsDict.ContainsKey(name))
        {
            wsDict.Remove(name);
            wsDict.Add(name, websocket);
        }
        else 
        { 
            wsDict.Add(name, websocket);
        }

        websocket.OnOpen += () =>
        {
            Debug.Log($"[WebsocketMgr]OnOpen");
            callback("open",null);
        };

        websocket.OnError += (e) =>
        {
            Debug.Log($"[ERROR][WebsocketMgr]OnError:{e}");
            callback("error",e);
        };

        websocket.OnClose += (e) =>
        {
            Debug.Log($"[WebsocketMgr]OnClose");
            wsDict.Remove(name);
            callback("close",e.ToString());
            new Timer((object state) => { 
                Connect(name, address, callback);
            }, null, reconnectDelay, Timeout.Infinite);

            reconnectDelay *= 2;
            if (reconnectDelay >= maxReconnectDelay) {
                reconnectDelay = maxReconnectDelay;
            }
        };

        websocket.OnMessage += (bytes) =>
        {
            callback("message",System.Text.Encoding.UTF8.GetString(bytes));
        };

        await websocket.Connect();
    }
    //public void Send(string name, string msg)
    //{
    //    Task.Run(async () => { 
    //        wsDict.TryGetValue(name, out WebSocket ws);
    //        //Debug.Log($"[WebsocketMgr]Send:${msg}");
    //        if (ws != null) { 
    //            if (ws.State == WebSocketState.Open) { 
    //                await ws.SendText(msg);
    //            }
    //        }
    //    });
    //}
    public void Send(string name, string msg)
    {
        SendAsync(name, msg);
    }
    async void SendAsync(string name, string msg)
    {
        wsDict.TryGetValue(name, out WebSocket ws);
        //Debug.Log($"[WebsocketMgr]Send:${msg}");
        if (ws != null)
        {
            if (ws.State == WebSocketState.Open)
            {
                await ws.SendText(msg);
            }
        }
    }
}
