using HighlightPlus;
using System;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

public class GameManager : MonoBehaviour
{
    public static GameManager Instance;

    public LevelManager Level { get; private set; }
    public CameraManager Camera { get; private set; }

    //UI
    public IntroUIManager IntroUI { get; private set; }
    public InGameUIManager InGameUI { get; private set; }
    public InventoryManager Inventory { get; private set; }

    //기타
    public ItemEffectManager ItemEffect { get; private set; }

    [Header("Item Dynamic Settings")]
    public float ItemRotationSpeed = 50f; // 회전 속도
    public float ItemBounceAmplitude = 0.1f; // 오르내리는 높이
    public float ItemBounceFrequency = 2f;   // 오르내리는 속도

    [Header("Global Refer")]
    public GameObject StaticObjectsField;
    public GameObject DynamicObjectsField;
    public HighlightProfile InteractionHighlightProfile;

    private void Awake()
    {
        if (Instance == null)
        {
            Instance = this; //만들어진 자신을 인스턴스로 설정
        }
        else
        {
            Destroy(gameObject); //이미 인스턴스가 있으면 자신을 파괴
        }

        SceneManager.sceneLoaded += OnSceneLoaded;
    }

    private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
    {
        // 씬이 로드될 때마다 해당 씬에 있는 Manager들을 찾아서 갱신
        // 없으면 자동으로 null이 들어감
        this.Level = FindFirstObjectByType<LevelManager>();
        this.Camera = FindFirstObjectByType<CameraManager>();
        this.IntroUI = FindFirstObjectByType<IntroUIManager>();
        this.InGameUI = FindFirstObjectByType<InGameUIManager>();
        this.Inventory = FindFirstObjectByType<InventoryManager>();
        this.ItemEffect = FindFirstObjectByType<ItemEffectManager>();

        if (this.Level != null) this.Level.OnSceneLoaded(scene, mode);
        if (this.Camera != null) this.Camera.OnSceneLoaded(scene, mode);
        if (this.ItemEffect != null) this.ItemEffect.OnSceneLoaded(scene, mode);

        InputManager.Instance.PlayerInputEnable(true);
        GlobalUIManager.Instance.SetSceneLoadingActive(false);
    }

    public void RequestSceneChange(string sceneName)
    {
        _ = SceneChange(sceneName);
    }

    private async Awaitable SceneChange(string sceneName)
    {
        try
        {
            GlobalUIManager.Instance.SetSceneLoadingActive(true);

            AsyncOperation op = SceneManager.LoadSceneAsync(sceneName);

            //자동 전환을 하고 싶지 않을 경우 해당값을 false로 두었다가 true로 바꾸면 그 때 전환됨
            op.allowSceneActivation = false;

            //화면에 보여줄 로딩 수치
            float displayProgress = 0f;

            //op.progress 0.9가 데이터 로딩이 끝난 기준 allowSceneActivation이 트루면 바로 다음으로 넘어가면서 op.isDone이 true가 된다.
            while (op.progress < 0.9f) 
            {
                //실제 로딩 수치
                float realProgress = Mathf.Clamp01(op.progress / 0.9f);

                //보여줄 값을 실제값을 향해 부드럽게 이동
                displayProgress = Mathf.MoveTowards(displayProgress, realProgress, Time.deltaTime * 0.5f);

                // UI에 적용
                GlobalUIManager.Instance.SetSceneLoadingProgressValue(displayProgress);

                await Awaitable.NextFrameAsync(this.destroyCancellationToken); //자기자신이 파괴될때 토큰에 취소요청을 보냄
            }

            GlobalUIManager.Instance.SetSceneLoadingProgressValue(1);

            // 잠시 대기했다가 전환
            await Awaitable.WaitForSecondsAsync(2.0f, this.destroyCancellationToken);

            op.allowSceneActivation = true;

            Debug.Log("씬 전환됨");

            InputManager.Instance.UnPairDevices();
        }
        catch (OperationCanceledException)
        {
            Debug.Log("씬 전환 작업이 취소됨");
        }
    }
}
