using System;
using Intrepid.Diagnostics;
using UnityEngine;
using UnityEngine.SceneManagement;

namespace Intrepid.Gameplay.Journey.Runtime.Loading
{
    public sealed class JourneyStageLoader : MonoBehaviour
    {
        private StageStateMachine StageStateMachine { get; } = new();

        public StageTag CurrentStageTag => StageStateMachine.CurrentStageTag;

        public bool IsLoadingFinished => StageStateMachine.IsLoadingFinished;

        public bool HasCurrentStage => CurrentStageTag.IsNotNull();

        public void LoadMachine()
        {
            StageStateMachine.LoadMachine(JourneyService.Instance.StageTags);
            DLogger.LogDebug("loaded stage machine.", ctx: this);
        }

        public void Init(StageTag stageTag)
        {
            if (stageTag.IsNull())
            {
                DLogger.LogWarn("cannot init null stage.", ctx: this);
                return;
            }

            StageStateMachine.InitMachine(stageTag);

            DLogger.LogDebug($"initialized stage: {stageTag.StageId}", ctx: this);
        }

        public void ChangeTo(StageTag stageTag)
        {
            if (stageTag.IsNull())
            {
                DLogger.LogWarn("cannot change to null stage.", ctx: this);
                return;
            }

            if (CurrentStageTag == stageTag)
            {
                DLogger.LogDebug($"ignored change to same stage: {stageTag.StageId}", ctx: this);
                return;
            }

            StageStateMachine.ChangeState(stageTag);

            DLogger.LogDebug($"changing to stage: {stageTag.StageId}", ctx: this);
        }

        public void TearDown()
        {
            StageStateMachine.TearDown();
            DLogger.LogDebug("tear down.", ctx: this);
        }

        public bool AdoptLoadedStage(StageTag stageTag)
        {
            if (stageTag.IsNull())
            {
                DLogger.LogWarn("cannot adopt null stage.", ctx: this);
                return false;
            }

            var scene = SceneManager.GetSceneByName(stageTag.Code);
            if (!scene.IsValid() || !scene.isLoaded)
            {
                DLogger.LogWarn($"cannot adopt stage {stageTag.StageId}; scene is not loaded.", ctx: this);
                return false;
            }

            StageStateMachine.InitMachine(stageTag);

            DLogger.LogDebug($"adopted loaded stage: {stageTag.StageId}", ctx: this);

            return true;
        }
    }
}