using Nox.Game;
using Jovian.SaveSystem;
using Jovian.InGameLogging;
using Nox.UI;
using System;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
using UnityEngine.ResourceManagement.ResourceProviders;

namespace Nox.Core {

    public class MenuGameStateData {
        public Action<PlayMode> startGameRequests;
        public Action continueGameRequest;
    }

    public class MainMenuGameState : IGameState {
        private readonly GameDataState gameDataState;
        private readonly MenuGameStateData menuGameStateData;
        private readonly BootstrapReferences bootstrapReferences;
        private readonly ISaveSystem saveSystem;
        private readonly IGameLogStore gameLogStore;
        private AdventureData adventureData;
        private Action<PlayMode> onStartGameRequested;
        private Action onContinueRequested;
        private MainMenuView mainMenuView;
        private AsyncOperationHandle<SceneInstance> loadSceneAsync;
        public bool IsGameStateInitialized { get; set; }

        public MainMenuGameState(GameDataState gameDataState,
            MenuGameStateData menuGameStateData,
            BootstrapReferences bootstrapReferences,
            ISaveSystem saveSystem,
            AdventureData adventureData,
            IGameLogStore gameLogStore) {
            this.gameDataState = gameDataState;
            this.menuGameStateData = menuGameStateData;
            this.bootstrapReferences = bootstrapReferences;
            this.saveSystem = saveSystem;
            this.adventureData = adventureData;
            this.gameLogStore = gameLogStore;
        }

        public void EnterGameState() {
            IsGameStateInitialized = false;
            onStartGameRequested = mode => {
                var sessions = saveSystem.GetAllSessions();
                gameDataState.activeSessionId = sessions.Count > 0
                    ? sessions[0].sessionId
                    : saveSystem.CreateSession();
                gameDataState.savedPartyPosition = new Vector3(7.285129f, 0, 0.4297419f);
                gameDataState.ChangeGameState(GameState.GameMode);
                gameDataState.ChangePlayMode(mode);
            };
            onContinueRequested = () => {
                var saveData = NoxSaveData.RestoreSavedData(saveSystem, gameDataState, ref adventureData, gameLogStore);
                if(saveData == null) {
                    return;
                }

                gameDataState.ChangeGameState(GameState.GameMode);
                gameDataState.ChangePlayMode(saveData.activePlayMode);
                gameDataState.ActiveParty = saveData.activeParty;

            };
            menuGameStateData.startGameRequests += onStartGameRequested;
            menuGameStateData.continueGameRequest += onContinueRequested;
            _ = InitializeGameState();
        }

        private async Task InitializeGameState() {
            var sceneHandle = Addressables.LoadSceneAsync(bootstrapReferences.startMenuScene);
            await sceneHandle.Task;
            await sceneHandle.Result.ActivateAsync();
            var assetHandle = Addressables.LoadAssetAsync<MenuPrefabsContainer>(bootstrapReferences.menuPrefabsContainer);
            await assetHandle.Task;
            var characterBaseSettings = Addressables.LoadAssetAsync<StarterCharacterSettings>("CharacterBaseSettings").WaitForCompletion();
            var perKRegistry = Addressables.LoadAssetAsync<PerksRegistry>("PerksRegistry").WaitForCompletion();
            var characterRegistry = Addressables.LoadAssetAsync<CharacterRegistry>("CharacterRegistry").WaitForCompletion();
            var modifiersRegistry = Addressables.LoadAssetAsync<ModifiersRegistry>("ModifiersRegistry").WaitForCompletion();
            var partySettings = Addressables.LoadAssetAsync<PartySettings>("DefaultPartySettings").WaitForCompletion();
            var portraitsHolder = Addressables.LoadAssetAsync<PortraitsHolder>(assetHandle.Result.portraitsHolder).WaitForCompletion();
            var characterSystems = CharacterSystemsFactory.Create(partySettings, characterBaseSettings, perKRegistry, characterRegistry, modifiersRegistry);

            mainMenuView = new MainMenuView(assetHandle.Result, menuGameStateData, saveSystem, gameDataState, partySettings, characterSystems, portraitsHolder, characterBaseSettings);
            mainMenuView.Initialize();
            mainMenuView.Show();
            IsGameStateInitialized = true;
        }

        public GameState Tick() {
            mainMenuView?.Tick();
            return gameDataState.ActiveGameState;
        }
        public void LateTick() { }
        public void Dispose() { }

        public void ExitGameState() {
            if(onStartGameRequested != null) {
                menuGameStateData.startGameRequests -= onStartGameRequested;
                onStartGameRequested = null;
            }
            if(onContinueRequested != null) {
                menuGameStateData.continueGameRequest -= onContinueRequested;
                onContinueRequested = null;
            }
            mainMenuView?.Dispose();
        }
    }

}
