using System;
using System.Collections;
using System.Collections.Concurrent;
using Alibabacloud.Rum.Unity.Integrations;
using UnityEngine;

namespace Alibabacloud.Rum.Unity
{
    internal interface IAlibabacloudMonoBehaviour
    {
        event Action? ApplicationResuming;
        public Coroutine StartCoroutine(IEnumerator routine);
        public void QueueCoroutine(IEnumerator routine);
    }

    /// <summary>
    /// Singleton and DontDestroyOnLoad setup.
    /// </summary>
    [AddComponentMenu("")] // Hides it from being added as a component in the inspector
    public partial class AlibabacloudMonoBehaviour : MonoBehaviour, IAlibabacloudMonoBehaviour
    {
        private static AlibabacloudMonoBehaviour? _instance;

        public static AlibabacloudMonoBehaviour Instance
        {
            get
            {
                // Unity overrides `==` operator in MonoBehaviours
                if (_instance == null)
                {
                    // HideAndDontSave excludes the gameObject from the scene meaning it does not get destroyed on loading/unloading
                    var alibabacloudGameObject = new GameObject("AlibabacloudMonoBehaviour")
                        { hideFlags = HideFlags.HideAndDontSave };
                    _instance = alibabacloudGameObject.AddComponent<AlibabacloudMonoBehaviour>();
                }

                return _instance;
            }
        }
    }

    /// <summary>
    /// A MonoBehaviour used to provide access to helper methods used during Performance Auto Instrumentation
    /// </summary>
    public partial class AlibabacloudMonoBehaviour
    {
        
    }

    /// <summary>
    ///  A MonoBehavior used to forward application focus events to subscribers.
    /// </summary>
    public partial class AlibabacloudMonoBehaviour
    {
        // Unbounded queue - used by the ScreenshotEventProcessor where capture is already limited by Interlocked to 1/frame
        private readonly ConcurrentQueue<IEnumerator> _coroutineQueue = new();

        public void QueueCoroutine(IEnumerator routine)
        {
            // if (MainThreadData.IsMainThread())
            // {
            //     StartCoroutine(routine);
            // }
            // else
            // {
            //     // On background thread (e.g., Burst job) - queue for next Update()
            //     _coroutineQueue.Enqueue(routine);
            // }
        }

        private void Update()
        {
            while (_coroutineQueue.TryDequeue(out var coroutine))
            {
                StartCoroutine(coroutine); // 协程
            }
        }

        /// <summary>
        /// Hook to receive an event when the application gains focus.
        /// </summary>
        public event Action? ApplicationResuming;

        /// <summary>
        /// Hook to receive an event when the application loses focus.
        /// </summary>
        public event Action? ApplicationPausing;

        // Keeping internal track of running state because OnApplicationPause and OnApplicationFocus get called during startup and would fire false resume events
        internal bool _isRunning = true;

        private IApplication? _application;

        internal IApplication Application
        {
            get
            {
                _application ??= ApplicationAdapter.Instance;
                return _application;
            }
            set => _application = value;
        }

        /// <summary>
        /// Updates the SDK's internal pause status
        /// </summary>
        public void UpdatePauseStatus(bool paused)
        {
            if (paused && _isRunning)
            {
                _isRunning = false;
                ApplicationPausing?.Invoke();
            }
            else if (!paused && !_isRunning)
            {
                _isRunning = true;
                ApplicationResuming?.Invoke();
            }
        }

        /// <summary>
        /// To receive Pause events.
        /// </summary>
        internal void OnApplicationPause(bool pauseStatus) => UpdatePauseStatus(pauseStatus);

        /// <summary>
        /// To receive Focus events.
        /// </summary>
        /// <param name="hasFocus"></param>
        internal void OnApplicationFocus(bool hasFocus) => UpdatePauseStatus(!hasFocus);

        // The GameObject has to destroy itself since it was created with HideFlags.HideAndDontSave
        private void OnApplicationQuit() => Destroy(gameObject);

        private void Awake()
        { 
            DontDestroyOnLoad(gameObject);
        }
    }
}
