using System;
using TMPro;
using UniRx;
using UnityEngine;

public class CustomerAnimator : MonoBehaviour
{
    private static readonly string WantFlavorAmountFormat = "x{0}";
        
    private static readonly int WalkFront = Animator.StringToHash("WalkFront");
    private static readonly int WalkSide = Animator.StringToHash("WalkSide");
    private static readonly int WalkBack = Animator.StringToHash("WalkBack");
    private static readonly int StayBack = Animator.StringToHash("StayBack");
    private static readonly int WalkFrontEat = Animator.StringToHash("WalkFrontEat");
    private static readonly int WalkSideEat = Animator.StringToHash("WalkSideEat");
    private static readonly int TouchNotice = Animator.StringToHash("TouchNotice");
    private static readonly int TouchQuestion = Animator.StringToHash("TouchQuestion");
    private static readonly int HashTouchNoticeState = Animator.StringToHash("Base Layer.customer_nomal_touch_notice");
    private static readonly int HashTouchQuestionState = Animator.StringToHash("Base Layer.customer_nomal_touch_Question");
    
    private static readonly int Complain = Animator.StringToHash("ComplainTrigger");
    
    [SerializeField] private Animator animator;
    [SerializeField] private CustomerDirection customerDirection;
    [SerializeField] private Animator orderAnimator;
    [SerializeField] private GameObject tapReaction;
    [SerializeField] private GameObject orderPopup;
    [SerializeField] private Transform leftPopcornTarget;
    [SerializeField] private Transform rightPopcornTarget;
    [SerializeField] private Transform frontPopcornTarget;
    [SerializeField] private Transform wantFlavorSpriteTarget;
    [SerializeField] private TextMeshPro wantFlavorAmountText;
    
    private readonly ReactiveProperty<int> triggerName = new ReactiveProperty<int>();
    public readonly ReactiveProperty<bool> IsPause = new ReactiveProperty<bool>();

    private void Start()
    {
        triggerName.AddTo(this);
        triggerName.Subscribe(x =>
        {
            animator.SetTrigger(x);
        }).AddTo(this);
        IsPause.AddTo(this);
        IsPause.DistinctUntilChanged().Subscribe(x =>
        {
            animator.speed = x ? 0f : 1f;
            orderAnimator.speed = x ? 0f : 1f;
        }).AddTo(this);
    }

    public void SetTrigger(CustomerMovingType movingType, float duration)
    {
        switch (movingType)
        {
            case CustomerMovingType.WalkSide:
                triggerName.Value = WalkSide;
                break;
            case CustomerMovingType.WalkSideEat:
                triggerName.Value = WalkSideEat;
                break;
            case CustomerMovingType.WalkCenter:
                triggerName.Value = WalkSide;
                break;
            case CustomerMovingType.TouchNotice:
                // Durationをもとに途中再生
                PlayResumeAnimation(HashTouchNoticeState, duration);
                break;
            case CustomerMovingType.TouchQuestion:
                // Durationをもとに途中再生
                PlayResumeAnimation(HashTouchQuestionState, duration);
                break;
            case CustomerMovingType.StayBackOrder:
                triggerName.Value = StayBack;
                break;
            case CustomerMovingType.StayBack:
                triggerName.Value = StayBack;
                break;
            case CustomerMovingType.WalkBack:
                triggerName.Value = WalkBack;
                break;
            case CustomerMovingType.WalkBackHalf:
                triggerName.Value = WalkBack;
                break;
            case CustomerMovingType.WalkFront:
                triggerName.Value = WalkFront;
                break;
            case CustomerMovingType.WalkFrontEat:
                triggerName.Value = WalkFrontEat;
                break;
            default:
                throw new ArgumentOutOfRangeException(nameof(movingType), movingType, null);
        }
        
    }

    private void PlayResumeAnimation(int stateHashName, float duration)
    {
        /*
         * durationをNormalizedTimeに変換するために
         * State指定して1フレーム後にGetCurrentAnimatorClipInfoしている
         */
        animator.Play(stateHashName);
        Observable.NextFrame().Subscribe(_ =>
        {
            var length = animator.GetCurrentAnimatorClipInfo(0)[0].clip.length;
            animator.Play(stateHashName, 0, Mathf.Clamp01(duration/length));
        }).AddTo(this);
    }

    public void SetSide(bool isDefaultSide)
    {
        if (isDefaultSide)
        {
            customerDirection.SetDefaultSide();
        }
        else
        {
            customerDirection.SetFlipSide();
        }
    }

    public void SetWantFlavor(MarketPopcornView prefab, ProductRarity rarity, int amount)
    {
        leftPopcornTarget.DestroyAllChildrens();
        rightPopcornTarget.DestroyAllChildrens();
        frontPopcornTarget.DestroyAllChildrens();
        wantFlavorSpriteTarget.DestroyAllChildrens();
        Instantiate(prefab, leftPopcornTarget).ChangeRarity(rarity);
        Instantiate(prefab, rightPopcornTarget).ChangeRarity(rarity);
        Instantiate(prefab, frontPopcornTarget).ChangeRarity(rarity);
        Instantiate(prefab, wantFlavorSpriteTarget).ChangeRarity(rarity);
        
        wantFlavorAmountText.text = String.Format(WantFlavorAmountFormat, amount);
    }
    
    public void ShowWantFlavor()
    {
        orderPopup.SetActive(true);
    }

    public void ShowComplain()
    {
        orderAnimator.SetTrigger(Complain);
        this.CallWaitForSeconds(1.5f, () =>
        {
            orderPopup.SetActive(false);
        });
    }

    public void HideOrderPopup()
    {
        orderPopup.SetActive(false);
    }

    public void ShowTapReaction()
    {
        tapReaction.SetActive(true);
    }
}