using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using DG.Tweening;

namespace DuckHunter
{
    public class Duck : MonoBehaviour
    {
        public static List<Duck> DuckList = new List<Duck>();
        RectTransform _arrowRectTransform;
        RectTransform _parentRectTransform;
        RectTransform _rectTransform;
        DragonBones.UnityArmatureComponent _armature;
        [NonSerialized] public bool dead = false;
        float _direction = 1;
        public Action<Duck> onExit;
        public Action<Duck> onHitDead;
        public Action<Duck> onFallDonwStart;
        public Action<Duck> onFallDonwEnd;
        public DuckConfig config;

        void Start()
        {
            DuckList.Add(this);
            //获取基本组件
            _arrowRectTransform = transform.Find("Arrow") as RectTransform;
            _parentRectTransform = transform.parent as RectTransform;
            _rectTransform = transform as RectTransform;
            //初始化皮肤
            int useSkinIndex = config.type - 1;
            for (int i = 0; i < _rectTransform.childCount; i++)
            {
                GameObject skin = _rectTransform.GetChild(i).gameObject;
                bool needActive = i == useSkinIndex;
                skin.SetActive(needActive);
                //获取龙骨动画组件
                if (needActive) _armature = skin.GetComponent<DragonBones.UnityArmatureComponent>();
            }
            //初始化角度
            _flyAngle = config.flyAngle;
            //初始化速度
            _flySpeed = config.flySpeed;
            //初始化坐标
            _rectTransform.anchoredPosition = Vector2.right * config.positionX;
            //初始化动作
            StartActionCoroutine(Fly());
        }

        void OnDestroy()
        {
            DuckList.Remove(this);
        }

        void Update()
        {

        }

        Sequence _sequenceRotateForever;
        string _lastPlayAnimationName;
        void PlayAnimation(string animationName = null)
        {
            if (animationName == _lastPlayAnimationName) return;
            _lastPlayAnimationName = animationName;
            _armature.animation.Play(animationName, 0);
            if (_sequenceRotateForever != null)
            {
                _sequenceRotateForever.Kill();
                _sequenceRotateForever = null;
            }
            if (animationName == "03")
            {
                _arrowRectTransform.gameObject.SetActive(true);
                _arrowRectTransform.localPosition = new Vector3(-20, -55);
                _arrowRectTransform.localEulerAngles = new Vector3(0, 0, 145);
            }
            else if (animationName == "04")
            {
                _arrowRectTransform.gameObject.SetActive(true);
                _arrowRectTransform.localPosition = new Vector3(0, 35);
                _arrowRectTransform.localEulerAngles = new Vector3(0, 0, 0);
                _sequenceRotateForever = DOTween.Sequence();
                _sequenceRotateForever.Append(_arrowRectTransform.DOLocalRotate(Vector3.up * 180, 0.2f));
                _sequenceRotateForever.Append(_arrowRectTransform.DOLocalRotate(Vector3.up * 360, 0.2f));
                _sequenceRotateForever.SetLoops(-1);
            }
            else if (animationName == "05")
            {
                _arrowRectTransform.gameObject.SetActive(true);
                _arrowRectTransform.localPosition = new Vector3(34, -77);
                _arrowRectTransform.localEulerAngles = new Vector3(0, 0, 232);
            }
            else
            {
                _arrowRectTransform.gameObject.SetActive(false);
            };
        }

        static string Event_HitDead_Finish = "Event_HitDead_Finish";
        static string Event_FallDown_Finish = "Event_FallDown_Finish";
        static string Event_FlyTouchBound = "Event_FlyTouchBound";
        static string Event_FlyAway = "Event_FlyAway";
        void OnEvent(string eventName)
        {
            if (eventName == Event_HitDead_Finish)
            {
                StartActionCoroutine(FallDown());
            }
            else if (eventName == Event_FallDown_Finish)
            {
                onExit?.Invoke(this);
            }
            else if (eventName == Event_FlyTouchBound)
            {
                if (_touchBoundCount >= config.touchBoundCount)
                {
                    StartActionCoroutine(FlyAway());
                }
                else
                {
                    _flyAngle = CalculateTurnbackAngle();
                    StartActionCoroutine(Fly());
                }
            }
            else if (eventName == Event_FlyAway)
            {
                Destroy(gameObject);
                onExit?.Invoke(this);
            }
        }

        Coroutine _actionCoroutine = null;
        void StartActionCoroutine(IEnumerator routine)
        {
            StopActionCoroutine();
            _actionCoroutine = StartCoroutine(routine);
        }
        void StopActionCoroutine()
        {
            if (_actionCoroutine != null)
            {
                StopCoroutine(_actionCoroutine);
                _actionCoroutine = null;
            }
        }



        float _flyAngle = 60;
        float _flySpeed = 60;
        Vector2 _flyVelocity;
        /// <summary>
        /// 计算飞行速度
        /// </summary>
        Vector2 CalculateFlyVelocity()
        {
            return new Vector2(Mathf.Cos(_flyAngle * Mathf.Deg2Rad), Mathf.Sin(_flyAngle * Mathf.Deg2Rad)) * _flySpeed;
        }
        /// <summary>
        /// 计算折返后的角度
        /// </summary>
        float CalculateTurnbackAngle()
        {
            Vector2 dc = _BoundChangeVelocityDirections[_touchBoundType];
            Vector3 v = _flyVelocity;
            Vector3 v_dc = v * dc;
            Vector3 c = Vector3.Cross(v, v_dc);
            return _flyAngle + 180 + (c.z > 0 ? -1 : 1) * 90;
        }
        /// <summary>
        /// 飞行动作表现 
        /// </summary>
        IEnumerator Fly()
        {
            _flyVelocity = CalculateFlyVelocity();
            if (_flyVelocity.y > 0) _armature.animation.Play("01", 0);
            else _armature.animation.Play("02", 0);
            Vector2 ap = _rectTransform.anchoredPosition;
            UpdateTouchBoundType();
            int firstTouchBoundType = _touchBoundType;
            float t = 0;
            while (_touchBoundType == firstTouchBoundType || _touchBoundType == 0)
            {
                t += Time.deltaTime;
                _rectTransform.anchoredPosition = ap + _flyVelocity * t;
                _direction = _flyVelocity.x > 0 ? 1 : -1;
                UpdateAnglesByDirection();
                UpdateTouchBoundType();
                yield return null;
            }
            CorrectWithinTheBound();
            _touchBoundCount++;
            OnEvent(Event_FlyTouchBound);
        }

        /// <summary>
        /// 碰到边界后用它来改变速度方向
        /// </summary>
        static Vector2[] _BoundChangeVelocityDirections =
        {
        Vector2.one,
        new Vector2(-1, 1),
        new Vector2(1, -1),
        new Vector2(-1, 1),
        new Vector2(1, -1),
    };

        int _touchBoundCount;
        int _touchBoundType;
        /// <summary>
        /// 更新触碰边界的标志
        /// </summary>
        void UpdateTouchBoundType()
        {
            Vector2 ap = _rectTransform.anchoredPosition;
            Rect mr = _rectTransform.rect;
            Rect pr = _parentRectTransform.rect;
            Vector2 mrMin = ap + mr.min;
            Vector2 mrMax = ap + mr.max;
            bool hitBottom = false;
            Collider2D[] hitColliders = Physics2D.OverlapPointAll(transform.position);
            foreach (var item in hitColliders)
            {
                if (item.name.StartsWith("BottomCollider"))
                {
                    hitBottom = true;
                    break;
                }
            }
            if (hitBottom) _touchBoundType = 2;
            else if (mrMin.x <= 0) _touchBoundType = 1; //left
            else if (mrMin.y <= 0) _touchBoundType = 2; //bottom
            else if (mrMax.x >= pr.width) _touchBoundType = 3; //right
            else if (mrMax.y >= pr.height) _touchBoundType = 4; //top
            else _touchBoundType = 0; //within
        }

        /// <summary>
        /// 把自己纠正回边界内，避免下一次边界检测可能会出问题
        /// </summary>
        void CorrectWithinTheBound()
        {
            Vector2 ap = _rectTransform.anchoredPosition;
            Rect mr = _rectTransform.rect;
            Rect pr = _parentRectTransform.rect;
            Vector2 mrMin = ap + mr.min;
            Vector2 mrMax = ap + mr.max;
            if (mrMin.x <= 0) ap.x = -mr.min.x + 0.1f;
            if (mrMin.y <= 0) ap.y = -mr.min.y + 0.1f;
            if (mrMax.x >= pr.width) ap.x = pr.width - mr.max.x - 0.1f;
            if (mrMax.y >= pr.height) ap.y = pr.height - mr.max.y - 0.1f;
            _rectTransform.anchoredPosition = ap;
        }

        void UpdateAnglesByDirection()
        {
            var ag = _rectTransform.localEulerAngles;
            ag.y = _direction < 0 ? -180 : 0;
            _rectTransform.localEulerAngles = ag;
        }

        IEnumerator HitDead()
        {
            PlayAnimation("03");
            UpdateAnglesByDirection();
            onHitDead?.Invoke(this);
            yield return new WaitForSeconds(0.1f);
            AudioManager.Instance.PlayDuckHit(gameObject);
            yield return new WaitForSeconds(0.4f);
            OnEvent(Event_HitDead_Finish);
        }

        IEnumerator FallDown()
        {
            onFallDonwStart?.Invoke(this);
            PlayAnimation("04");
            UpdateAnglesByDirection();
            Vector2 speed = Vector2.zero;
            while (_rectTransform.anchoredPosition.y > 0)
            {
                speed += Vector2.down * 500f * Time.deltaTime;
                _rectTransform.anchoredPosition += speed * Time.deltaTime;
                yield return null;
            }
            OnEvent(Event_FallDown_Finish);
            onFallDonwEnd?.Invoke(this);
        }

        bool _hasFlyAway = false;
        public Action onStartFlyAway;
        IEnumerator FlyAway()
        {
            _hasFlyAway = true;
            onStartFlyAway?.Invoke();
            bool intersect = true;
            while (intersect)
            {
                _rectTransform.anchoredPosition += _flyVelocity * Time.deltaTime;
                Rect mr = _rectTransform.rect;
                mr.position = _rectTransform.anchoredPosition + mr.min;
                Rect pr = _parentRectTransform.rect;
                pr.position = Vector2.zero;
                intersect = Intersects(mr, pr);
                yield return null;
            }
            OnEvent(Event_FlyAway);
        }

        bool Intersects(Rect a, Rect b)
        {
            float maxax = a.x + a.width,
                maxay = a.y + a.height,
                maxbx = b.x + b.width,
                maxby = b.y + b.height;
            return !(maxax < b.x || maxbx < a.x || maxay < b.y || maxby < a.y);
        }

        //活着的时候击中才会返回ture
        public bool Hit()
        {
            if (_hasFlyAway) return false;
            if (dead) return false;
            dead = true;
            StartActionCoroutine(HitDead());
            return true;
        }

        public void PlayDeadForDogHand(int direction)
        {
            _direction = direction;
            UpdateAnglesByDirection();
            PlayAnimation("05");
        }

        public void NotifyFlyAway()
        {
            if (_hasFlyAway) return;
            if (dead) return;
            _flyVelocity *= 1000f / _flyVelocity.magnitude;
            StartActionCoroutine(FlyAway());
        }
    }
}
