using System;
using System.Collections.Generic;
using System.Linq;
using MyGame.Scripts;
using UniRx;
using UniRx.Triggers;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

public enum GameState
{
    TutorialBeforeGuide,
    Guide,
    Playing,
    Result
}

public class PopcornGameManager : MonoBehaviour
{
    public static readonly string CookingDataTag = "CookingData";
    public static readonly string PanDataTag = "PanData";
    public static readonly string CookingResultDataTag = "CookingResultData";
    public static readonly string RestartCallbackTag = "PopcornGameManagerRestartCallback";
    // View
    [SerializeField] private PopcornGameView gameView;

    [SerializeField] private ThermalControl thermalControl;
    [SerializeField] private ThermoMeter thermoMeter;
    [SerializeField] private CornManager cornManager;
    
#if DEVELOPMENT_BUILD || UNITY_EDITOR
    [SerializeField] private Button resetButton;
#endif

    private readonly ReactiveProperty<GameState> state = new ReactiveProperty<GameState>(GameState.Guide);
    private readonly CompositeDisposable compositeDisposable = new CompositeDisposable();
    
    // Start is called before the first frame update
    void Start()
    {
        compositeDisposable.AddTo(this);
        state.AddTo(this);
        
        SoundManager.Instance.PlayBGM("bgm_cooking");

        thermalControl.Condition.Subscribe(x =>
        {
            cornManager.ChangeGrowSpeed(x);
            gameView.ChangeCharacterState(x);
        }).AddTo(this);

        state.SkipLatestValueOnSubscribe().Subscribe(x =>
        {
            cornManager.GameState.Value = x;
            gameView.ChangeUI(x);
            switch (x)
            {
                case GameState.TutorialBeforeGuide:
                case GameState.Guide:
                    thermalControl.ResetMeter(GameDataManager.GameData.isFirstPlay);
                    thermoMeter.gameObject.SetActive(false);
                    cornManager.RespawnCorn();
                    break;
                case GameState.Playing:
                    thermoMeter.gameObject.SetActive(true);
                    thermalControl.StartMeter();
                    break;
                case GameState.Result:
                    thermalControl.StopMeter();
                    break;
                default:
                    throw new ArgumentOutOfRangeException(nameof(x), x, null);
            }
        });

        ResetGame();

        if (GameDataManager.GameData.isFirstPlay)
        {
            if (TutorialManager.Instance.Index == 7)
            {
                cornManager.SetCornsActive(false);
                state.SetValueAndForceNotify(GameState.TutorialBeforeGuide);
                TutorialManager.Instance.ShowTutorialConversation(8, () =>
                {
                    GameGuideDialog.ShowDialog(() =>
                    {
                        state.SetValueAndForceNotify(GameState.Guide);
                        cornManager.SetCornsActive(true);
                    });
                });
            }
        }
        
#if DEVELOPMENT_BUILD || UNITY_EDITOR
        resetButton.OnClickAsObservable().Subscribe(_ =>
        {
            TransitionManager.Instance.UnloadScene(GameScenes.CookingResults);
            ResetGame();
        }).AddTo(this);
#endif

#if UNITY_EDITOR
        this.UpdateAsObservable()
            .Where(_ => Input.GetKeyDown(KeyCode.R))
            // 連打防止
            .ThrottleFirst(TimeSpan.FromSeconds(0.1f))
            .Subscribe(_ => UnityEngine.SceneManagement.SceneManager.LoadScene("Cooking"))
            .AddTo(this);
        
        this.UpdateAsObservable()
            .Where(_ => Input.GetKeyDown(KeyCode.E))
            // 連打防止
            .ThrottleFirst(TimeSpan.FromSeconds(0.1f))
            .Subscribe(_ => ResetGame())
            .AddTo(this);

        cornManager.Result
            .SkipLatestValueOnSubscribe()
            // .DistinctUntilChanged()
            .Materialize()
            .Subscribe(x => { Debug.Log(x); }).AddTo(this);
#endif
    }

    private void ResetGame()
    {
        var panData = LocalCacheManager.Load<PanData>(PanDataTag);
        var rarityList = SpreadsheetDataManager.Instance.GetBaseDataList<RarityData>(Const.RarityDataSheet);
        var rarityData = rarityList.First(data => data.Rarity == panData.Rarity);
        // フライパン設定
        gameView.SetPan(panData.GetPrefab());
        thermalControl.SetPanData(panData);
        cornManager.SetCornsActive(true);
        compositeDisposable.Clear();
        cornManager.Result.SkipLatestValueOnSubscribe()
            .FirstOrDefault()
            .DelayFrame(1) // Disposeタイミング調整
            .Subscribe(result =>
            {
                state.Value = GameState.Result;
                // リザルト表示遅延
                this.CallWaitForSeconds(1.2f, () =>
                {
                    LocalCacheManager.Save(CookingResultDataTag, (rarityData, result, new Action(() => cornManager.SetCornsActive(false))));
                    LocalCacheManager.Save(RestartCallbackTag, new Action(ResetGame));
                    TransitionManager.Instance.LoadSceneAdditive(GameScenes.CookingResults);
                });
            }).AddTo(compositeDisposable);
        
        // 画面タップでスタート
        this.UpdateAsObservable()
            .Select(_ => Input.GetMouseButton(0))
            .DistinctUntilChanged()
            .Skip(1)
            .Where(_ => state.Value == GameState.Guide)
            .Take(1)
            .Subscribe(_ =>
            {
                state.Value = GameState.Playing;
            }).AddTo(compositeDisposable);
        state.SetValueAndForceNotify(GameState.Guide);
    }
}
