using Nox.EditorCode;
using System;
using System.Threading.Tasks;
using Nox.Input;
using Nox.Platform;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.SceneManagement;

namespace Nox.Core {
    public class Boot {
        private static readonly AssetReferenceT<InitializerSettingsFile> InitializerSettingsFile = new ("InitializerSettingsFile");
        /// <summary>
        /// The is the first method called when the game starts. It will load the Initializer prefab which will initialize the project
        /// </summary>
        [RuntimeInitializeOnLoadMethod]
        private static void Initialize() {
#if UNITY_EDITOR
            switch(BootMode.BootType) {
                case BootType.UnityDefault:
                    return;
                case BootType.SceneBoot:
                    InitializeEntrypoint();
                    break;
                case BootType.FullBoot:
                    var loadOperation = SceneManager.LoadSceneAsync("Startup", LoadSceneMode.Single);
                    if(loadOperation != null) {
                        loadOperation.completed += OnCompleted;
                    }
                    break;
                default:
                    throw new ArgumentOutOfRangeException();
            }
#else
            InitializeEntrypoint();
#endif
        }

        private static void OnCompleted(AsyncOperation obj) {
            obj.allowSceneActivation = true;
            InitializeEntrypoint();
        }

        private static void InitializeEntrypoint() {
            var entryPoint = Addressables.InstantiateAsync("Initializer").WaitForCompletion().GetComponent<EntryPoint>();

            _ = CreatePlatformFactory(entryPoint);
        }

        private static async Task CreatePlatformFactory(EntryPoint entryPoint) {
            var gameDataState = new GameDataState {
                platformSelector = new PlatformSelector(PlatformSelector.GetDevicePlatform(), PlatformSelector.GetPlatformDefaultInputMode()),
            };
            
            var initSettingsHandle = Addressables.LoadAssetAsync<InitializerSettingsFile>(InitializerSettingsFile);
            await initSettingsHandle.Task;
            var initializerSettings = initSettingsHandle.Result;
            
            var devicePlatform = gameDataState.platformSelector.devicePlatform;
            IPlatform platform = devicePlatform switch {
                DevicePlatform.Desktop => new DesktopPlatform(initializerSettings.desktopPlatformSettings),
                DevicePlatform.UnityEditor => new UnityEditorPlatform(initializerSettings.unityEditorPlatformSettings),
                _ => null
            };

            if(!Equals(gameDataState.platformSelector.devicePlatform, DevicePlatform.Desktop) &&
               PlatformSelector.GetPlatformDefaultInputMode() == InputMode.Desktop) {
                platform = new DesktopPlatform(initializerSettings.desktopPlatformSettings);
            }
            await platform?.Initialize(gameDataState)!;
            
            _ = entryPoint.StartGame(gameDataState,initializerSettings, platform);
        }
    }
}
