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,
    Spilled
}

[RequireComponent(typeof(Rigidbody2D))]
public class Corn : MonoBehaviour
{
    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 SpriteRenderer spriteRenderer;
    [SerializeField] private Sprite cornSeedSprite;
    [SerializeField] private Sprite cornSimpleSprite;
    [SerializeField] private Sprite cornBurntSprite;
    [SerializeField] private GameObject effectBurnt;
    [SerializeField] private Animator animator;

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

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

    private void Awake()
    {
        condition.AddTo(this);
        rigidbody = GetComponent<Rigidbody2D>();
        spriteRenderer.sprite = cornSeedSprite;
        
        spriteTransform = spriteRenderer.transform;
        rotationResolverTransform = spriteTransform.parent.parent;
        
        animator.SetFloat(HashWaitOffset, Random.value/2);
    }

    private void Start()
    {
        rigidbody.MovePosition(new Vector2(Random.value * 2 - 1, Random.value * 2 - 1));
        rigidbody.SetRotation(Random.value * 360);

        // コーンが飛んでいく
        this.ObserveEveryValueChanged(x => x.rigidbody.velocity.magnitude)
            .Where(x => x >= cornSpillSpeed)
            .FirstOrDefault()
            .Subscribe(_ =>
        {
            condition.Value = CornCondition.Spilled;
        }).AddTo(this);

        condition.Pairwise().Subscribe(x =>
        {
            switch (x.Current)
            {
                case CornCondition.Seed:
                    break;
                case CornCondition.Simple:
                    CornPop();
                    break;
                case CornCondition.Burnt:
                    CornBurnt();
                    break;
                case CornCondition.Spilled:
                    CornSpilled(x.Previous);
                    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.Spilled)
        {
            return;
        }

        cornGrowTime += Time.deltaTime * cornGrowSpeed;
        if (cornGrowTime >= cornBurntTime)
        {
            condition.Value = CornCondition.Burnt;
        }
        else if (cornGrowTime >= cornPopTime)
        {
            condition.Value = CornCondition.Simple;
        }
    }

    private void CornPop()
    {
        spriteRenderer.sprite = cornSimpleSprite;
        rigidbody.AddForce(cornPopSpeed * new Vector2(Random.value * 2 - 1, Random.value * 2 - 1), ForceMode2D.Impulse);
        animator.SetTrigger(HashCornGrow);
        VibrationManager.Instance.PlayVibrationOnce();
    }

    private void CornBurnt()
    {
        spriteRenderer.sprite = cornBurntSprite;
        animator.SetTrigger(HashCornBurn);
        Instantiate(effectBurnt, transform);
    }

    private void CornSpilled(CornCondition prevCondition)
    {
        GetComponent<Collider2D>().enabled = false;
        // フライパンに追従しないようにparent解除
        transform.parent = null;
        this.CallWaitForSeconds(.5f, () => Destroy(gameObject));
        if (prevCondition == CornCondition.Seed)
        {
            VibrationManager.Instance.PlayVibrationOnce();
        }
    }

    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;
    }
}
