using System.Threading;
using Cysharp.Threading.Tasks;
using RebootKit.Engine.Foundation;
using UnityEngine;
using UnityEngine.SceneManagement;
using Logger = RebootKit.Engine.Foundation.Logger;

namespace RebootKit.Engine.Main {
    public static class EntryPoint {
        static readonly Logger s_logger = new Logger(nameof(EntryPoint));

        static CancellationTokenSource s_cancellationTokenSource;

        [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSplashScreen)]
        public static void Start() {
            if (s_cancellationTokenSource != null) {
                s_cancellationTokenSource.Cancel();
            }

            s_cancellationTokenSource = new CancellationTokenSource();
            RunAsync(s_cancellationTokenSource.Token).Forget();

#if UNITY_EDITOR
            static void OnPlayerModeState(UnityEditor.PlayModeStateChange state) {
                if (state == UnityEditor.PlayModeStateChange.ExitingPlayMode) {
                    s_cancellationTokenSource.Cancel();
                }
            }

            UnityEditor.EditorApplication.playModeStateChanged -= OnPlayerModeState;
            UnityEditor.EditorApplication.playModeStateChanged += OnPlayerModeState;
#endif
        }
        
        static async UniTask RunAsync(CancellationToken cancellationToken) {
            ConfigVarsContainer.Init();

            // We are loading the boot scene only in the editor.
            // In the player, we assume that the boot scene is already loaded.
#if UNITY_EDITOR
            s_logger.Info("Loading boot scene");
            SceneManager.LoadScene(RConsts.k_BootSceneBuildIndex, LoadSceneMode.Single);
#endif

            s_logger.Info("Loading engine config");
            EngineConfigAsset configAsset = Resources.Load<EngineConfigAsset>(RConsts.k_EngineConfigResourcesPath);
            if (configAsset is null) {
                s_logger.Error($"Couldn't load engine config from resources: {RConsts.k_EngineConfigResourcesPath}");
                return;
            }

            s_logger.Info("Initializing RR");
            await RR.InitAsync(configAsset, cancellationToken);

            s_logger.Info("Loading main scene");
            await SceneManager.LoadSceneAsync(RConsts.k_MainSceneBuildIndex, LoadSceneMode.Single)
                              .ToUniTask(cancellationToken: cancellationToken);

            s_logger.Info("Starting RR");
            await RR.RunAsync(cancellationToken);

            await UniTask.WaitUntilCanceled(Application.exitCancellationToken);

            RR.Shutdown();
        }
    }
}