using System;
using System.Collections.Generic;
using UniRx;
using UniRx.Triggers;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

public enum GameState
{
    Guide,
    Playing,
    Result
}

public class PopcornGameManager : MonoBehaviour
{
    [SerializeField] private GameObject startingGuide;
    [SerializeField] private GameObject fire;
    [SerializeField] private GameObject perfectResultObject;
    [SerializeField] private GameObject goodResultObject;
    [SerializeField] private GameObject failureResultObject;

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

    public IReadOnlyReactiveProperty<GameState> State => state;
    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);

        thermalControl.Condition.Subscribe(x =>
        {
            cornManager.ChangeGrowSpeed(x);
            switch (x)
            {
                case ThermalCondition.Cold:
                    characterFlower.gameObject.SetActive(false);
                    characterSweat.gameObject.SetActive(false);
                    break;
                case ThermalCondition.Yellow:
                    characterFlower.gameObject.SetActive(true);
                    characterSweat.gameObject.SetActive(false);
                    break;
                case ThermalCondition.Hot:
                    characterFlower.gameObject.SetActive(false);
                    characterSweat.gameObject.SetActive(true);
                    break;
                default:
                    throw new ArgumentOutOfRangeException(nameof(x), x, null);
            }
        }).AddTo(this);

        ResetGame();
        
#if DEVELOPMENT_BUILD || UNITY_EDITOR
        resetButton.OnClickAsObservable().Subscribe(_ =>
        {
            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 ResetUI()
    {
        startingGuide.SetActive(true);
        fire.SetActive(false);
        perfectResultObject.SetActive(false);
        goodResultObject.SetActive(false);
        failureResultObject.SetActive(false);
        
        thermalControl.StopMeter();
        thermoMeter.gameObject.SetActive(false);
        characterFlower.gameObject.SetActive(false);
        characterSweat.gameObject.SetActive(false);
    }

    private void ResetGame()
    {
        compositeDisposable.Clear();
        cornManager.Result.SkipLatestValueOnSubscribe()
            .FirstOrDefault()
            .DelayFrame(1) // Disposeタイミング調整
            .Subscribe(x =>
            {
                state.Value = GameState.Result;
                thermalControl.StopMeter();
                characterFlower.gameObject.SetActive(false);
                characterSweat.gameObject.SetActive(false);
                // リザルト表示遅延
                this.CallWaitForSeconds(1.2f, () =>
                {
                    switch (x)
                    {
                        case CornResult.Perfect:
                            perfectResultObject.SetActive(true);
                            break;
                        case CornResult.Good:
                            goodResultObject.SetActive(true);
                            break;
                        case CornResult.Failure:
                            failureResultObject.SetActive(true);
                            break;
                        default:
                            throw new ArgumentOutOfRangeException(nameof(x), x, null);
                    }
                    // 再度画面タップでリセット
                    this.UpdateAsObservable()
                        .Select(_ => Input.GetMouseButton(0))
                        .DistinctUntilChanged()
                        .Skip(1)
                        .FirstOrDefault(b => b)
                        .DelaySubscription(TimeSpan.FromSeconds(1f))
                        .Subscribe(_ =>
                        {
                            ResetGame();
                        }).AddTo(compositeDisposable);
                });
            }).AddTo(compositeDisposable);
        
        this.UpdateAsObservable()
            .Select(_ => Input.GetMouseButton(0))
            .DistinctUntilChanged()
            .Skip(1)
            .FirstOrDefault(b => b)
            .Subscribe(_ =>
            {
                StartGame();
            }).AddTo(compositeDisposable);
        
        ResetUI();
        thermalControl.ResetMeter();
        cornManager.RespawnCorn();
        state.Value = GameState.Guide;
    }

    private void StartGame()
    {
        startingGuide.SetActive(false);
        fire.SetActive(true);
        thermoMeter.gameObject.SetActive(true);
        thermalControl.StartMeter();
        state.Value = GameState.Playing;
    }
}
