using System;
using System.Collections;
using System.Collections.Generic;
using UniRx;
using UniRx.Triggers;
using UnityEngine;
using Random = UnityEngine.Random;

public enum CornCondition
{
    Seed,
    Simple,
    Burnt,
}

[RequireComponent(typeof(Rigidbody2D))]
public class Corn : MonoBehaviour
{
    private static readonly int HashCornWait = Animator.StringToHash("CornWait");
    private static readonly int HashCornGrow = Animator.StringToHash("CornGrow");
    private static readonly int HashCornBurn = Animator.StringToHash("CornBurn");
    private static readonly int HashWaitOffset = Animator.StringToHash("WaitOffset");

    [SerializeField] private CornSkin cornSkin;
    [SerializeField] private GameObject effectBurnt;
    [SerializeField] private GameObject effectSpillSeed;
    [SerializeField] private GameObject effectSpillPopped;
    [SerializeField] private Material burntMaterial;
    [SerializeField] private Animator animator;
    [Space][Range(0,1)]
    [SerializeField] private float spillProbability;

    private Rigidbody2D rigidbody;
    private float cornPopTime;
    private float cornBurntTime;
    private float cornGrowTime;
    private float cornGrowSpeed;
    private float cornSpillSpeed;
    private float cornPopSpeed;
    private bool isHot;
    
    public IReadOnlyReactiveProperty<CornCondition> Condition => condition;
    private readonly ReactiveProperty<CornCondition> condition = new ReactiveProperty<CornCondition>(CornCondition.Seed);
    public IReadOnlyReactiveProperty<bool> Spilled => spilled;
    private readonly ReactiveProperty<bool> spilled = new ReactiveProperty<bool>();

    
    // 角度調整
    private Transform rotationResolverTransform;
    private Transform spriteTransform;

    private void Awake()
    {
        condition.AddTo(this);
        rigidbody = GetComponent<Rigidbody2D>();

        spriteTransform = cornSkin.transform;
        rotationResolverTransform = spriteTransform.parent.parent;
        
        animator.SetFloat(HashWaitOffset, Random.value/2);
    }

    private void Start()
    {
        rigidbody.AddForce(Random.onUnitSphere * 10f, ForceMode2D.Impulse);
        rigidbody.SetRotation(Random.rotation);
        cornSkin.ChangeSkin(condition.Value);

        // コーン飛び出し演出
        this.ObserveEveryValueChanged(x => x.rigidbody.velocity.magnitude)
            .Where(x => x >= cornSpillSpeed)
            .ThrottleFirstFrame(30) // 30フレーム間隔開ける
            .Where(_ => Random.value < spillProbability) // 演出を出す確率
            .FirstOrDefault()
            .Subscribe(_ =>
            {
                spilled.Value = true;
                GameObject effect;
                if (condition.Value == CornCondition.Seed)
                {
                    effect = Instantiate(effectSpillSeed, transform.position, Quaternion.identity, null);
                    this.CallWaitForSeconds(5f, () => Destroy(effect));
                }
                else
                {
                    effect = Instantiate(effectSpillPopped, transform.position, Quaternion.identity, null);
                    if (condition.Value == CornCondition.Burnt)
                    {
                        effect.transform.GetChild(0).GetComponentInChildren<ParticleSystemRenderer>().material = burntMaterial;
                    }
                    this.CallWaitForSeconds(5f, () => Destroy(effect));
                }
            }).AddTo(this);

        condition.Pairwise().Subscribe(x =>
        {
            switch (x.Current)
            {
                case CornCondition.Seed:
                    break;
                case CornCondition.Simple:
                    // コーンが弾けたとき、GrowSpeedを再設定する
                    // ThermalCondition.Hot以外では焦げ進行なし
                    if (!isHot)
                    {
                        ChangeGrowSpeed(0f);
                    }
                    CornPop();
                    break;
                case CornCondition.Burnt:
                    CornBurnt();
                    break;
                default:
                    throw new ArgumentOutOfRangeException(nameof(x), x, null);
            }
        }).AddTo(this);
        
        this.UpdateAsObservable().Subscribe(_ =>
        {
            // アニメーション向けに回転をリセット
            rotationResolverTransform.rotation = Quaternion.identity;
            // コーンの回転を伝搬
            spriteTransform.localRotation = transform.localRotation;
        }).AddTo(this);
    }

    private void Update()
    {
        if (condition.Value == CornCondition.Burnt) return;
        cornGrowTime += Time.deltaTime * cornGrowSpeed;
        if (cornGrowTime >= cornBurntTime)
        {
            condition.Value = CornCondition.Burnt;
        }
        if (cornGrowTime >= cornPopTime && condition.Value == CornCondition.Seed)
        {
            if (isHot)
            {
                condition.Value = CornCondition.Burnt;
            }
            else
            {
                condition.Value = CornCondition.Simple;
            }
        }
    }

    private void CornPop()
    {
        cornSkin.ChangeSkin(condition.Value);
        rigidbody.AddForce(cornPopSpeed * Random.insideUnitCircle, ForceMode2D.Impulse);
        animator.SetTrigger(HashCornGrow);
        VibrationManager.Instance.PlayVibrationOnce();
    }

    private void CornBurnt()
    {
        cornSkin.ChangeSkin(condition.Value);
        animator.SetTrigger(HashCornBurn);
        var effect = Instantiate(effectBurnt, transform);
        this.CallWaitForSeconds(.8f, () => Destroy(effect));
    }

    public void SetCornProperty(float popTime, float burntDuration, float spillSpeed, float popSpeed)
    {
        cornPopTime = popTime;
        cornBurntTime = cornPopTime + burntDuration;
        cornSpillSpeed = spillSpeed;
        cornPopSpeed = popSpeed;
    }

    public void ChangeGrowSpeed(float speed)
    {
        cornGrowSpeed = speed;
    }

    public void ChangeHotStatus(bool status)
    {
        isHot = status;
    }

    public void StartCornDance()
    {
        animator.SetTrigger(HashCornWait);
    }
}
