using System;
using System.Collections;
using SGModule.Common;
using SGModule.Common.Base;
using SGModule.Common.Helper;
using SGModule.Net;
using UnityEngine;

namespace SGModule.NetKit {
    public class HeartbeatKit : SingletonMonoBehaviour<HeartbeatKit> {
        private Coroutine _heartbeatCoroutine;
        private static int HeartbeatInterval => 60;
        private const string HeartbeatForegroundTime = "HeartbeatForegroundTime";

        /// <summary>
        ///     后台时逻辑
        /// </summary>
        /// <param name="pauseStatus"></param>
        private void OnApplicationPause(bool pauseStatus) {
            Log.NetKit.Warning($"OnApplication Pause :{pauseStatus}");
            // 应用程序失去焦点
            if (pauseStatus) {
                SaveRemainingHeartbeatTime();
            }
            else {
                RestoreNextHeartbeatTime();
            }
        }

        // 应用程序退出
        private void OnApplicationQuit() {
            Log.NetKit.Warning("OnApplication Quit");

            SaveRemainingHeartbeatTime();
        }

        public void StartHeartbeat() {
            _heartbeatCoroutine??= StartCoroutine(HeartbeatRequestCoroutine());
        }

        private IEnumerator HeartbeatRequestCoroutine() {
            RestoreNextHeartbeatTime(); // 恢复之前剩余时间或默认值

            while (true) {
                if (Now() >= NextHeartbeatTime) {
                    NextHeartbeatTime += HeartbeatInterval;
                    RequestHeart();
                }

                yield return new WaitForSeconds(1);
            }
        }

        // 应用程序失去焦点, 保存心跳剩余时间
        private void SaveRemainingHeartbeatTime() {
            var remain = Math.Max((int) (NextHeartbeatTime - Now()), 0);
            LastRemainingInterval = remain % HeartbeatInterval;
        }


        // 应用程序获得焦点, 恢复下次心跳时间
        private void RestoreNextHeartbeatTime() {
            var now = Now();
            if (LastRemainingInterval < 0) {
                NextHeartbeatTime = now;
                return;
            }

            var remain = LastRemainingInterval % HeartbeatInterval;
            if (remain <= 0) {
                remain = HeartbeatInterval;
            }

            NextHeartbeatTime = now + remain;
        }

        private long _nextHeartbeatTime;

        private long NextHeartbeatTime {
            get {
                if (_nextHeartbeatTime <= 0) {
                    _nextHeartbeatTime = Now() + HeartbeatInterval;
                }

                return _nextHeartbeatTime;
            }
            set {
                var now = Now();
                if (value <= now) {
                    value = now + HeartbeatInterval;
                }

                _nextHeartbeatTime = value;
            }
        }

        private int? _lastRemainingInterval;

        private int LastRemainingInterval {
            get {
                if (_lastRemainingInterval != null) {
                    return _lastRemainingInterval.Value;
                }

                _lastRemainingInterval = PlayerPrefs.GetInt(HeartbeatForegroundTime, -1);

                return _lastRemainingInterval.Value;
            }
            set {
                _lastRemainingInterval = value;
                PlayerPrefs.SetInt(HeartbeatForegroundTime, value);
            }
        }


        private void RequestHeart() {
            if (ConfigManager.NetworkConfig.connectionMode == ConnectionMode.WebSocket) {
                WebSocketService.Instance.SendHeartbeat();
            }
            else {
                NetKit.Instance.Post("user/health");
            }
        }

        private static long Now() {
            return DateTimeOffset.UtcNow.ToUnixTimeSeconds();
        }
    }
}
