using System;
using System.Text;
using System.Threading.Tasks;
using NativeWebSocket;
using Newtonsoft.Json;
using SGModule.Common.Base;
using SGModule.Common.Helper;
using UnityEngine;

namespace SGModule.Net {
    public class WebSocketService : SingletonMonoBehaviour<WebSocketService> {
        private const float OffLineDecisionTime = 5f;
        private bool _bindToken;

        private float _offlineDuration;
        private string _url;
        private WebSocket _webSocket;

        private void Update() {
#if !UNITY_WEBGL || UNITY_EDITOR
            if (_webSocket != null) {
                _webSocket.DispatchMessageQueue();
            }
#endif
            if (IsInitComplete) {
                // 网络状态检测
                if (NetChecker.Instance.GetConnectionStatus() == ConnectionStatus.Connected) {
                    _offlineDuration = 0;
                    if (_webSocket == null || _webSocket.State == WebSocketState.Closed) {
                        Log.Net.Warning("网络恢复 重连");
                        TryReconnect();
                    }
                }
                else {
                    _offlineDuration += Time.deltaTime;
                    if (_offlineDuration > OffLineDecisionTime && _webSocket != null && _webSocket.State == WebSocketState.Open) {
                        Log.Net.Warning("断网 主动结束连接");
                        _ = Disconnect();
                    }
                }
            }
        }

        private async void OnApplicationQuit() {
            await Disconnect();
        }

        private void InitGmTool() {
        }

        /// <summary>
        ///     初始化
        /// </summary>
        /// <param name="url"></param>
        public async void Init(string url) {
            InitGmTool();

            NetChecker.Instance.SetUsePingCheck(true);

            Log.Net.Info($"Initializing WebSocket service. Url: {url}");
            _url = url;

            OnOpenAction += OnOpen;
            OnMessageAction += OnMessage;
            OnErrorAction += OnError;
            OnCloseAction += OnClose;

            await Connect();
        }

        private void Send(object data) {
            if (_webSocket == null) {
                Log.Net.Warning("webSocket is null");
                return;
            }

            if (_webSocket.State != WebSocketState.Open) {
                Log.Net.Warning("webSocket.State != Open");
                return;
            }

            var jsonString = JsonConvert.SerializeObject(data);
            var byteArray = Encoding.UTF8.GetBytes(jsonString);
            _webSocket.Send(byteArray);
        }

        /// <summary>
        ///     断开连接
        /// </summary>
        public async Task Disconnect() {
            if (_webSocket != null) {
                var webSocket = _webSocket;
                _webSocket = null;
                await webSocket.Close();
            }
        }

        #region 连接管理

        // 事件回调
        public event Action OnOpenAction;
        public event Action<string> OnMessageAction;
        public event Action<WebSocketCloseCode> OnCloseAction;
        public event Action<string> OnErrorAction;

        /// <summary>
        ///     初始化并尝试连接
        /// </summary>
        private async Task Connect() {
            if (_webSocket != null && (_webSocket.State == WebSocketState.Open || _webSocket.State == WebSocketState.Connecting)) {
                Log.Net.Warning("WebSocket is already connected or connecting.");
                return;
            }

            _webSocket = new WebSocket(_url);

            // 绑定事件
            _webSocket.OnOpen += () => {
                Log.Net.Info("WebSocket connected.");
                OnOpenAction?.Invoke();
            };

            _webSocket.OnMessage += bytes => {
                var message = Encoding.UTF8.GetString(bytes);
                Log.Net.Info($"Message received: {message}");
                OnMessageAction?.Invoke(message);
            };

            _webSocket.OnClose += code => {
                Log.Net.Info($"WebSocket disconnected with code: {code}");
                OnCloseAction?.Invoke(code);
            };

            _webSocket.OnError += error => {
                Log.Net.Error($"WebSocket error: {error}");
                OnErrorAction?.Invoke(error);
            };

            // 开始连接
            try {
                await _webSocket.Connect();
            }
            catch (Exception ex) {
                Log.Net.Error($"WebSocket connection failed: {ex.Message}");
                TryReconnect();
            }
        }


        private void OnOpen() {
            IsInitComplete = true;
            // 重连成功后绑定 Token
            if (_bindToken) {
                BindToken(TokenManager.Instance.CachedToken);
            }
        }

        private void OnClose(WebSocketCloseCode closeCode) {
        }

        private void OnMessage(string message) {
            var responseData = WebSocketTools.DeserializeResponse(message);
            WebSocketTools.ProcessResponseData(responseData);
        }

        private void OnError(string errorMsg) {
        }

        /// <summary>
        ///     尝试重连
        /// </summary>
        private async void TryReconnect() {
            var maxRetries = 5; // 最大重连次数
            var attempt = 0;
            while (attempt < maxRetries) {
                attempt++;
                Log.Net.Info($"Attempting to reconnect... (Attempt {attempt}/{maxRetries})");
                try {
                    await Connect();

                    //以下或许不会执行 这个
                    Log.Net.Info("Reconnected successfully.");
                    return; // 重连成功
                }
                catch (Exception ex) {
                    Log.Net.Error($"Reconnection attempt {attempt} failed: {ex.Message}");
                    await Task.Delay(2000); // 等待一段时间再尝试
                }
            }

            Log.Net.Error("Max reconnection attempts reached. Connection failed.");
        }

        #endregion

        #region 请求

        /// <summary>
        ///     绑定Token
        /// </summary>
        public void BindToken(string token) {
            Send(new WebSocketData {
                cmd = (int) WebSocketEvent.BindToken,
                token = token
            });

            _bindToken = true;
        }

        /// <summary>
        ///     发送心跳
        /// </summary>
        public void SendHeartbeat() {
            Send(new WebSocketData {
                cmd = (int) WebSocketEvent.SendHeartbeat
            });
        }

        #endregion
    }
}
