using System;
using UniRx;
using UniRx.Triggers;
using UnityEngine;

public class BrotherPinkView : SingletonMonoBehaviour<BrotherPinkView>
{
    private static readonly int Normal = Animator.StringToHash("Normal");
    private static readonly int Promotion = Animator.StringToHash("Promotion");
    private static readonly int Sleepy = Animator.StringToHash("Sleepy");
    private static readonly int Walk = Animator.StringToHash("Walk");
    private static readonly Vector2 RightPos = new Vector2(4.96f, -0.26f);
    private static readonly Vector2 LeftPos = new Vector2(-4.96f, -0.26f);
    
    [SerializeField] private Animator animatorPrefab;
    [SerializeField] private Transform pinkTransform;
    [SerializeField] private float walkSideBottomPos;
    [SerializeField] private float pinkWalkSpeed = 4f;
    [SerializeField] private float coolTime = 10f;
    [SerializeField] private int fewerBorder = 5;

    public int FewerBorder => fewerBorder;

    private Animator animator;
    private bool isManyCustomer;
    private bool isLocked;
    private bool isPromotion;
    private int nextId;
    private readonly (int trigger, Vector2 wayPoint, float wait)[] pinkMoves =
    {
        (Walk, LeftPos, 0f),
        (Promotion, LeftPos + Vector2.right * .03f, 5.35f),
        (Walk, RightPos, 0f),
        (Promotion, RightPos + Vector2.left * .03f, 5.35f),
    };
    private int moveIndex;
    private Vector2 wayPoint;
    private float durationDelta;
    private float completedDuration;

    private void Awake()
    {
        nextId = Normal;
        isManyCustomer = true;
        Debug.Log($"normal");
    }

    private void Start()
    {
        pinkTransform.localPosition = RightPos;
        this.UpdateAsObservable().Subscribe(_ =>
        {
            if (isManyCustomer || isLocked || isPromotion)
            {
                return;
            }
            var localPosition = pinkTransform.localPosition;
            localPosition = Vector2.MoveTowards(localPosition, wayPoint, pinkWalkSpeed * Time.deltaTime);
            localPosition = localPosition + Vector3.forward * (localPosition.y + Mathf.Abs(walkSideBottomPos));
            pinkTransform.localPosition = localPosition;
            if (Vector2.Distance(localPosition, wayPoint) < .01f)
            {
                if (durationDelta < completedDuration)
                {
                    durationDelta += Time.deltaTime;
                    return;
                }
                durationDelta = 0;
                moveIndex++;
                if (moveIndex == pinkMoves.Length)
                {
                    ResetMove();
                    isLocked = true;
                    this.CallWaitForSeconds(coolTime, () =>
                    {
                        isLocked = false;
                    });
                    return;
                }
                SetPinkMove();
            }
        }).AddTo(this);
    }

    private void ResetMove()
    {
        moveIndex = 0;
        isManyCustomer = true;
        if (animator != null) animator.SetTrigger(nextId);
    }

    public void SetBrotherView(Transform target)
    {
        target.DestroyAllChildrens();
        animator = Instantiate(animatorPrefab, target);
        this.UpdateAsObservable().Subscribe(_ =>
        {
            target.localPosition = pinkTransform.localPosition;
            target.localRotation = pinkTransform.localRotation;
        }).AddTo(animator);
        if (isManyCustomer || isPromotion)
        {
            return;
        }
        SetPinkMove();
    }

    private void SetPinkMove()
    {
        var move = pinkMoves[moveIndex];
        wayPoint = move.wayPoint;
        completedDuration = move.wait;
        if (animator != null)
        {
            animator.ResetTrigger(Normal);
            animator.SetTrigger(move.trigger);
        }
        if (Vector2.Distance(wayPoint, pinkTransform.localPosition.ToVector2()) < .01f)
        {
            // nop
        } else if ((wayPoint - pinkTransform.localPosition.ToVector2()).x > 0)
        {
            pinkTransform.localRotation = Quaternion.Euler(Vector3.up * 180);
        }
        else
        {
            pinkTransform.localRotation = Quaternion.Euler(Vector3.zero);
        }
    }

    private void SetTrigger(int id)
    {
        nextId = id;
        if (isManyCustomer)
        {
            animator.SetTrigger(id);
        }
    }

    public void SetNormal()
    {
        SetTrigger(Normal);
    }

    public void SetSleepy()
    {
        SetTrigger(Sleepy);
    }
    
    public void StartPromotion()
    {
        isPromotion = true;
        animator.ResetTrigger(Normal);
        animator.SetTrigger(Promotion);
        Vector3 localPosition = RightPos;
        localPosition += Vector3.forward * (localPosition.y + Mathf.Abs(walkSideBottomPos));
        pinkTransform.localPosition = localPosition;
        pinkTransform.localRotation = Quaternion.Euler(Vector3.zero);
    }

    public void StopPromotion()
    {
        if (animator != null)
        {
            var stateInfo = animator.GetCurrentAnimatorStateInfo(0);
            if (stateInfo.IsName("Brother_pink_promotion"))
            {
                var length = stateInfo.length;
                var time = stateInfo.normalizedTime;
                this.CallWaitForSeconds((1 - time % 1) * length - .3f, () =>
                {
                    animator.ResetTrigger(Promotion);
                    ResetMove();
                    isPromotion = false;
                });
                return;
            }
        }
        ResetMove();
        isPromotion = false;
    }
    
    public void SetWalk()
    {
        if (isLocked || isPromotion)
        {
            return;
        }
        if (isManyCustomer)
        {
            isManyCustomer = false;
            SetPinkMove();
        }
    }
}
