using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using SGModule.Common.Base;
using SGModule.Common.Helper;
using UnityEngine;
using UnityEngine.Networking;

namespace SGModule.Net {
    public enum ConnectionStatus {
        Uninitialized, // 未初始化
        Connected, // 已连接
        Disconnected // 未连接
    }

    // 网络检测类
    public class NetChecker : SingletonMonoBehaviour<NetChecker> {
        private const float WebRequestInterval = 5f;
        private const float PingInterval = 2;

        // 可配置多个检测 URL
        [SerializeField] private List<string> checkUrls = new() {
            "https://www.baidu.com", // 国内 URL
            "https://www.google.com" // 国外 URL
        };

        // 是否启用 Ping 检测
        [SerializeField] private bool usePingCheck;

        // 配置可用的 Ping 地址列表
        private readonly List<string> _pingAddresses = new() {
            "8.8.8.8", // Google DNS（适合全球）
            "223.5.5.5", // 阿里云
            "1.1.1.1" // Cloudflare DNS（全球可用）
        };


        private Coroutine _checkInternetCoroutine;
        private float _checkInterval = WebRequestInterval;
        private bool _isChecking;
        private bool _lastConnected;
        private string _preferredUrl; // 当前优先检测的 URL

        /// <summary>
        ///     null = 未检测；true = 联网；false = 未联网
        /// </summary>
        private bool? IsConnected {
            get;
            set;
        }

        private void OnEnable() {
            StartCheckingInternet();
        }

        private void OnDisable() {
            StopCheckingInternet();
        }

        /// <summary>
        ///     等待网络连通，自动处理初始化和总超时时间
        /// </summary>
        /// <param name="timeout">最多等待的总时间（秒）</param>
        /// <param name="checkInterval">每次重试间隔</param>
        /// <param name="callback">检测结果回调</param>
        public IEnumerator WaitUntilNetworkConnected(float timeout, float checkInterval, Action<bool> callback) {
            var elapsed = 0f;

            // 阶段 1: 等待初始化完成
            while (!IsConnected.HasValue && elapsed < timeout) {
                yield return new WaitForSeconds(checkInterval);
                elapsed += checkInterval;
            }

            if (!IsConnected.HasValue) {
                Log.Net.Warning("网络检测初始化超时！");
                callback(false);
                yield break;
            }

            // 阶段 2: 等待网络恢复
            while (IsConnected == false && elapsed < timeout) {
                Log.Net.Warning($"网络异常，等待中... 已耗时: {elapsed:F1}s");
                yield return new WaitForSeconds(checkInterval);
                elapsed += checkInterval;
            }

            var success = IsConnected == true;
            if (!success) {
                Log.Net.Warning("网络连接等待超时！");
            }

            callback(success);
        }

        public ConnectionStatus GetConnectionStatus() {
            return IsConnected switch {
                null => ConnectionStatus.Uninitialized,
                true => ConnectionStatus.Connected,
                false => ConnectionStatus.Disconnected
            };
        }

        public void Init() {
            StartCheckingInternet();
        }

        private void StartCheckingInternet() {
            _checkInterval = usePingCheck ? PingInterval : WebRequestInterval;
            _checkInternetCoroutine ??= StartCoroutine(CheckInternetRoutine());
        }

        private void StopCheckingInternet() {
            if (_checkInternetCoroutine != null) {
                StopCoroutine(_checkInternetCoroutine);
                _checkInternetCoroutine = null;
            }
        }

        private IEnumerator CheckInternetRoutine() {
            while (true) {
                if (_isChecking) {
                    yield break; // 避免并发冲突
                }

                _isChecking = true;

                if (QuickNetDeviceCheck()) {
                    // if (usePingCheck) {
                    yield return CheckWithPing();
                    // }
                    // else {
                    //     yield return CheckWithUnityWebRequest();
                    // }
                }
                else {
                    IsConnected = false;
                }

                if (IsConnected.HasValue && _lastConnected != IsConnected.Value) {
                    Log.Net.Info($"网络状态变化: {IsConnected}");
                    _lastConnected = IsConnected.Value;
                }

                _isChecking = false;
                yield return new WaitForSecondsRealtime(_checkInterval);
            }
        }

        /// <summary>
        ///     使用 Ping 检测网络连通性
        /// </summary>
        private IEnumerator CheckWithPing() {
            var pings = _pingAddresses.Select(ip => new Ping(ip)).ToList();

            var startTime = Time.realtimeSinceStartup;
            var success = false;

            // 等待所有 Ping 返回结果或超时
            while (Time.realtimeSinceStartup - startTime < _checkInterval) {
                foreach (var ping in pings) {
                    if (ping.isDone && ping.time >= 0) {
                        success = true;
                        break;
                    }
                }

                if (success) {
                    break;
                }

                yield return new WaitForSecondsRealtime(0.1f);
            }

            // 如果有任意一个 Ping 成功，网络即为可用
            IsConnected = success;
        }

        /// <summary>
        ///     使用 UnityWebRequest 检测网络连通性
        /// </summary>
        private IEnumerator CheckWithUnityWebRequest() {
            if (!string.IsNullOrEmpty(_preferredUrl)) {
                var request = UnityWebRequest.Get(_preferredUrl);
                request.timeout = (int) _checkInterval;
                yield return request.SendWebRequest();

                if (request.result == UnityWebRequest.Result.Success) {
                    IsConnected = true;
                    request.Dispose();
                    yield break;
                }

                Log.Net.Warning($"CheckNet 首选URL请求失败: {_preferredUrl}, 错误: {request.error}");

                _preferredUrl = null; // 失败则清除
                request.Dispose();
            }

            // fallback：尝试所有 URL
            var ops = new List<UnityWebRequestAsyncOperation>();
            var requests = new List<UnityWebRequest>();

            foreach (var url in checkUrls) {
                var req = UnityWebRequest.Get(url);
                req.timeout = (int) _checkInterval;
                ops.Add(req.SendWebRequest());
                requests.Add(req);
            }

            yield return StartCoroutine(WaitForAnyRequest(ops));

            foreach (var req in requests) {
                req.Dispose();
            }
        }


        // 等待任意一个请求完成并返回
        private IEnumerator WaitForAnyRequest(List<UnityWebRequestAsyncOperation> ops) {
            while (ops.Any(op => !op.isDone)) {
                if (ops.Any(op => op.isDone && op.webRequest.result == UnityWebRequest.Result.Success)) {
                    break;
                }

                yield return null;
            }

            var successOp = ops.FirstOrDefault(op => op.webRequest.result == UnityWebRequest.Result.Success);

            if (successOp == null) {
                foreach (var op in ops.Where(op => op.isDone)) {
                    Log.Net.Warning($"请求失败: {op.webRequest.url}, 错误: {op.webRequest.error}");
                }
            }

            IsConnected = successOp != null;
            _preferredUrl = successOp?.webRequest.url;
        }

        // 添加或删除检查 URL
        public void AddCheckUrl(string url) {
            if (!checkUrls.Contains(url)) {
                checkUrls.Add(url);
            }
        }

        public void RemoveCheckUrl(string url) {
            if (checkUrls.Contains(url)) {
                checkUrls.Remove(url);
            }
        }

        public void AddPingTarget(string ip) {
            if (!_pingAddresses.Contains(ip)) {
                _pingAddresses.Add(ip);
            }
        }

        public void RemovePingTarget(string ip) {
            if (_pingAddresses.Contains(ip)) {
                _pingAddresses.Remove(ip);
            }
        }

        // 切换是否使用 Ping 检测
        public void SetUsePingCheck(bool enablePing) {
            usePingCheck = enablePing;
#if UNITY_WEBGL
usePingCheck = false;
#endif
            _checkInterval = usePingCheck ? PingInterval : WebRequestInterval;
        }

        private bool QuickNetDeviceCheck() {
            if (Application.isEditor) {
                return true;
            }

            return Application.internetReachability != NetworkReachability.NotReachable;
        }
    }
}
