using System.Collections;
using System.Collections.Generic;
using SGModule.Common.Base;
using SGModule.Common.Extensions;
using SGModule.Common.Helper;
using UnityEngine;
using UnityEngine.Events;

namespace SGModule.Net {
    // Token管理类
    public class TokenManager : SingletonMonoBehaviour<TokenManager> {
        public delegate IEnumerator ReauthenticateDelegate(UnityAction<string, long> onCompleted);

        public delegate IEnumerator RefreshTokenDelegate(UnityAction<string, long> onCompleted);

        private const string JarvisTokenKey = "JarvisToken";
        private const string JarvisTokenExpiresAtKey = "JarvisTokenExpiresAt";
        private const float MinRefreshInterval = 10f; // 刷新间隔秒数限制
        private const int MaxTokenRecordCount = 10; // 最多记录最近token数

        private readonly List<string> _tokenRecord = new();

        private long _cachedExpiresAt;
        private string _cachedToken;

        private bool _isReauthenticating;
        private bool _isRefreshing;
        private float _lastRefreshTime;
        private ReauthenticateDelegate _reauthenticateHandler;

        private RefreshTokenDelegate _refreshTokenHandler;

        public string CachedToken {
            get {
                if (string.IsNullOrEmpty(_cachedToken)) {
                    _cachedToken = PlayerPrefs.GetString(JarvisTokenKey, null);
                }

                return _cachedToken;
            }
            set {
                _cachedToken = value;
                if (!string.IsNullOrEmpty(value)) {
                    PlayerPrefs.SetString(JarvisTokenKey, value);
                }
                else {
                    PlayerPrefs.DeleteKey(JarvisTokenKey);
                }
            }
        }

        public long CachedExpiresAt {
            get {
                if (_cachedExpiresAt == 0) {
                    var expiresStr = PlayerPrefs.GetString(JarvisTokenExpiresAtKey, "0");
                    if (!long.TryParse(expiresStr, out _cachedExpiresAt)) {
                        _cachedExpiresAt = 0;
                    }
                }

                return _cachedExpiresAt;
            }
            set {
                _cachedExpiresAt = value;
                PlayerPrefs.SetString(JarvisTokenExpiresAtKey, value.ToString());
            }
        }


        private long RemainingTokenSeconds => CachedExpiresAt - ServerClock.GetCurrentServerTime();

        public void InitHandlers(RefreshTokenDelegate refreshTokenHandler, ReauthenticateDelegate reauthenticateHandler) {
            _refreshTokenHandler = refreshTokenHandler;
            _reauthenticateHandler = reauthenticateHandler;
        }

        /// <summary>
        ///     获取有效Token，自动处理刷新和重新登录
        /// </summary>
        public IEnumerator GetToken(UnityAction<string> callback) {
            // 若正在重新登录，则等待其完成，避免刷新或登录并发
            yield return WaitForReauthenticationComplete();
            if (_isReauthenticating) {
                callback?.Invoke(null);
                yield break;
            }


            if (IsTokenValid()) {
                callback?.Invoke(CachedToken); // 优先返回现有有效 Token

                // 如果快过期，则后台触发刷新，不等待
                if (IsTokenExpiringSoon() && ShouldStartRefresh()) {
                    _lastRefreshTime = Time.realtimeSinceStartup;
                    StartCoroutine(RefreshTokenRoutine()); // 不阻塞当前流程
                }
            }
            else {
                // token 已过期，必须重新登录
                yield return ReauthenticateRoutine(success => {
                    callback?.Invoke(success ? CachedToken : null);
                });
            }
        }

        private IEnumerator WaitForReauthenticationComplete() {
            var waitCount = 0;
            while (_isReauthenticating && waitCount < 6) {
                yield return new WaitForSeconds(0.5f);
                waitCount++;
            }
        }


        private IEnumerator RefreshTokenRoutine() {
            if (_isRefreshing || _refreshTokenHandler == null) {
                if (_refreshTokenHandler == null) {
                    Log.Net.Error("未设置 RefreshTokenHandler 委托，请先调用 InitHandlers 进行注入！");
                }

                yield break;
            }

            _isRefreshing = true;
            var retryCount = 0;
            var refreshSuccess = false;

            while (!refreshSuccess && retryCount < 3) {
                retryCount++;
                Log.Net.Info($"Token快过期了, 尝试刷新Token, 次数: {retryCount}");
                yield return _refreshTokenHandler((token, expiresAt) => {
                    refreshSuccess = !token.IsNullOrWhiteSpace();
                    if (refreshSuccess) {
                        UpdateTokenCache(token, expiresAt);
                    }
                });

                if (!refreshSuccess) {
                    yield return new WaitForSeconds(1f);
                }
            }

            if (!refreshSuccess) {
                Log.Net.Error("Token刷新失败");
            }

            _isRefreshing = false;
        }

        private IEnumerator ReauthenticateRoutine(UnityAction<bool> onCompleted) {
            if (_isReauthenticating || _reauthenticateHandler == null) {
                if (_reauthenticateHandler == null) {
                    Log.Net.Error("未设置 ReauthenticateHandler 委托，请先调用 InitHandlers 进行注入！");
                }

                onCompleted?.Invoke(false);
                yield break;
            }

            _isReauthenticating = true;
            Log.Net.Error("Token过期，开始重新登录流程");
            yield return _reauthenticateHandler((token, expiresAt) => {
                var success = !token.IsNullOrWhiteSpace();
                if (success) {
                    UpdateTokenCache(token, expiresAt);
                }

                onCompleted?.Invoke(success);
            });
            _isReauthenticating = false;
        }

        private bool IsTokenValid() {
            return !string.IsNullOrEmpty(CachedToken) && RemainingTokenSeconds > 0;
        }

        // 小于1小时(3600秒)有效期，认为快过期需要刷新
        private bool IsTokenExpiringSoon() {
            return RemainingTokenSeconds < 3600;
        }

        public void UpdateTokenCache(string token, long expiresAt) {
            CachedToken = token;
            CachedExpiresAt = expiresAt;


            _tokenRecord.Add(token);
            if (_tokenRecord.Count > MaxTokenRecordCount) {
                _tokenRecord.RemoveAt(0);
            }
        }

        private bool ShouldStartRefresh() {
            return !_isRefreshing && Time.realtimeSinceStartup - _lastRefreshTime > MinRefreshInterval;
        }

        /// <summary>
        ///     获取Token记录（测试功能用）
        /// </summary>
        public List<string> GetTokenRecord() {
            return _tokenRecord;
        }
    }
}
