using System.Collections;
using UnityEngine;

namespace Shooter.Gameplay
{
    /// <summary>
    /// Босс уровня. Появляется, опускаясь сверху, затем ведёт бой в три фазы по остатку
    /// здоровья (чем меньше HP — тем плотнее атаки): чередует «веер» пуль по кругу и
    /// прицельные очереди, параллельно перемещаясь между точками. При гибели проигрывает
    /// серию взрывов и роняет крупный лут.
    /// </summary>
    public class Boss_A : Enemy
    {
        [Header("Стрельба босса")]
        public GameObject m_BulletPrefab1;
        public Transform[] m_FirePoints;
        [Tooltip("Угол между пулями кругового веера, градусы")]
        public float m_RingAngleStep = 20f;

        [Header("Гибель")]
        public Transform[] m_DeathParticlePoints;
        [SerializeField] protected GameObject m_DeathParticlePrefab2;

        [Header("Фазы по здоровью")]
        [Tooltip("Доля HP, выше которой — фаза 0 (самая лёгкая)")]
        public float m_Phase1Hp = .6f;
        [Tooltip("Доля HP, выше которой — фаза 1 (ниже — фаза 2)")]
        public float m_Phase2Hp = .3f;

        [HideInInspector] public int m_AttackLevel = 0;

        void Start()
        {
            InitPosition = transform.position;
            m_DamageControl.m_NoDamage = true;                          // неуязвим, пока не появился
            transform.position = InitPosition + new Vector3(0, 0, 20);  // ждёт выше по уровню
            m_AttackLevel = 0;
        }

        void Update()
        {
            // Фаза боя зависит от остатка здоровья.
            float hp = m_DamageControl.Damage / m_DamageControl.MaxDamage;
            if (hp > m_Phase1Hp)
                m_AttackLevel = 0;
            else if (hp > m_Phase2Hp)
                m_AttackLevel = 1;
            else
                m_AttackLevel = 2;

            HandleFacePlayer();
            HandleDeath();
        }

        IEnumerator Co_AttackLoop()
        {
            while (true)
            {
                switch (m_AttackLevel)
                {
                    case 0:
                        yield return new WaitForSeconds(1f);
                        ShootRingBullet(2);
                        yield return new WaitForSeconds(2f);
                        for (int i = 0; i < 5; i++)
                        {
                            ShootBullet();
                            yield return new WaitForSeconds(.3f);
                        }
                        yield return new WaitForSeconds(2f);
                        break;

                    case 1:
                        yield return new WaitForSeconds(1f);
                        ShootRingBullet(3);
                        yield return new WaitForSeconds(.7f);
                        ShootRingBullet(3);
                        yield return new WaitForSeconds(2f);
                        for (int i = 0; i < 10; i++)
                        {
                            ShootBullet();
                            yield return new WaitForSeconds(.2f);
                        }
                        yield return new WaitForSeconds(1f);
                        break;

                    case 2:
                        yield return new WaitForSeconds(1f);
                        ShootRingBullet(4);
                        yield return new WaitForSeconds(.6f);
                        ShootRingBullet(4);
                        yield return new WaitForSeconds(.6f);
                        ShootRingBullet(4);
                        yield return new WaitForSeconds(2f);
                        for (int i = 0; i < 15; i++)
                        {
                            ShootBullet();
                            yield return new WaitForSeconds(.3f);
                        }
                        yield return new WaitForSeconds(1f);
                        break;
                }
            }
        }

        IEnumerator Co_MoveLoop()
        {
            EnemyMovement movement = GetComponent<EnemyMovement>();
            movement.m_FaceMoveDirection = false;
            m_FacePlayer = true;

            Vector3[] points =
            {
                InitPosition + new Vector3(-3, 0, 0),
                InitPosition + new Vector3(3, 0, 0),
                InitPosition + new Vector3(-3, 0, 2),
                InitPosition + new Vector3(3, 0, 2),
            };

            int pointNum = 0;
            while (true)
            {
                movement.SetMoveTargetPosition(points[pointNum]);
                while (!movement.m_ReachedTargetPosition)
                    yield return null;

                pointNum = Random.Range(0, 4);
                yield return new WaitForSeconds(1);
            }
        }

        public override void EnableEnemy()
        {
            base.EnableEnemy();
            StartCoroutine(Co_EnableEnemy());
        }

        IEnumerator Co_EnableEnemy()
        {
            // Плавно опускаемся на боевую позицию.
            float lerp = 0;
            while (lerp <= 1)
            {
                lerp += 0.2f * Time.deltaTime;
                transform.position = Vector3.Lerp(InitPosition + new Vector3(0, 0, 20), InitPosition, lerp);
                yield return null;
            }
            transform.position = InitPosition;

            yield return new WaitForSeconds(1f);
            m_DamageControl.m_NoDamage = false; // теперь уязвим
            m_FacePlayer = true;
            StartCoroutine(Co_MoveLoop());
            yield return new WaitForSeconds(1f);
            StartCoroutine(Co_AttackLoop());
        }

        /// <summary>Прицельная очередь: по пуле из двух стволов в сторону игрока.</summary>
        public void ShootBullet()
        {
            SpawnAimedBullet(m_FirePoints[1]);
            SpawnAimedBullet(m_FirePoints[2]);
        }

        void SpawnAimedBullet(Transform firePoint)
        {
            GameObject obj = Instantiate(m_BulletPrefab1);
            obj.transform.position = firePoint.position;
            Vector3 dir = PlayerChar.m_Current.transform.position - firePoint.position;
            dir.y = 0;
            obj.transform.forward = dir;
            obj.GetComponent<ProjectileCollision>().m_Creator = gameObject;
            obj.GetComponent<ProjectileMovement>().m_TurnSpeed = 0;
            Destroy(obj, 10);
        }

        /// <summary>Веер по кругу: 2*halfCount+1 пуль с шагом <see cref="m_RingAngleStep"/>.</summary>
        public void ShootRingBullet(int halfCount)
        {
            for (int i = -halfCount; i <= halfCount; i++)
            {
                GameObject obj = Instantiate(m_BulletPrefab1);
                obj.transform.position = m_FirePoints[0].position;
                obj.transform.forward = Quaternion.Euler(0, i * m_RingAngleStep, 0) * m_RotationBase.forward;
                obj.GetComponent<ProjectileCollision>().m_Creator = gameObject;
                Destroy(obj, 10);
            }
        }

        public override void HandleDeath()
        {
            if (!m_IsDead && m_DamageControl.Damage <= 0)
            {
                StopAllCoroutines();
                StartCoroutine(Co_HandleDeath());
                m_IsDead = true;
            }
        }

        IEnumerator Co_HandleDeath()
        {
            // Серия взрывов по точкам, всё чаще.
            float delay = .2f;
            for (int i = 0; i < 10; i++)
            {
                GameObject obj = Instantiate(m_DeathParticlePrefab);
                obj.transform.position = m_DeathParticlePoints[i % 5].position;
                Destroy(obj, 10);
                yield return new WaitForSeconds(delay);
                delay -= .01f;
            }

            yield return new WaitForSeconds(.5f);

            // Финальный взрыв, тряска и крупный лут.
            GameObject obj1 = Instantiate(m_DeathParticlePrefab2);
            obj1.transform.position = transform.position;
            Destroy(obj1, 6);
            CameraControl.m_Current.StartShake(.6f, .2f);
            DropItem(20);

            Destroy(gameObject);
        }

        public override void DropItem(int count)
        {
            // Два кольца кристаллов, разлетающихся вверх (count не используется — у босса фиксированный дроп).
            for (int i = 0; i < 20; i++)
            {
                GameObject obj1 = Instantiate(m_ItemPrefabs[0]);
                obj1.transform.position = transform.position;
                obj1.GetComponent<Rigidbody>().linearVelocity = Helper.RotatedLenght(i * 18, 10) + new Vector3(0, 15, 0);
            }
            for (int i = 0; i < 20; i++)
            {
                GameObject obj1 = Instantiate(m_ItemPrefabs[0]);
                obj1.transform.position = transform.position;
                obj1.GetComponent<Rigidbody>().linearVelocity = Helper.RotatedLenght(i * 18, 15) + new Vector3(0, 20, 0);
            }
        }
    }
}
