using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class EnemyColliderManager : ColliderManager
{
    public GameObject shipCore;
    public float bounceForce;
    public float coreSpawnDelayTime;

    public ParticleSystem effectA;
    public ParticleSystem effectB;

    public AudioClip shipDeathSFX;
    public AudioClip coreSpawnedSFX;

    private bool _enemyDestroyed = false;
    private TimerHelper _deathTimer;
    private TimerHelper _particleTimer;

    // The position the enemy died
    private Vector3 _deathPos;
    private float _deathHeight;

    public List<GameObject> enemyLoot;
    public List<float> enemyLootChance;

    public float magnetizedTime;
    private bool _magnetHit = false;
    private TimerHelper _magnetizeTime;

    public bool Dying
    {
        get
        {
            return _enemyDestroyed;
        }
    }

    public bool Magnetized
    {
        get
        {
            return _magnetHit;
        }
    }

    private void Start()
    {
        _deathTimer = new TimerHelper(coreSpawnDelayTime, false);
        _magnetizeTime = new TimerHelper(magnetizedTime, false);
    }

    /// <summary>
    /// Trigger the enemy death without a collision, this is mostly for the debug menu and testing but could be called in a case where you need it to die.
    /// </summary>
    public override void TriggerDeath()
    {
        DestoryEnemy();
        base.TriggerDeath();
    }

    /// <summary>
    /// Process the Enemy collision.
    /// </summary>
    /// <param name="direction">Direction the collision happened, typically checking if hit from above or below.</param>
    /// <param name="collision">Collision object holding the details on the collided object.</param>
    /// <param name="wasChild">Was the hit collider a child of this game object.</param>
    public override void ProcessCollision(CollisionDirection direction, Collision collision, bool wasChild)
    {
        GameObject collisionGO;
        if (wasChild)
        {
            collisionGO = collision.transform.parent.gameObject;
        }
        else
        {
            collisionGO = collision.gameObject;
        }

        if (!Dying)
        {
            switch (direction)
            {
                // We were hit from the top
                case CollisionDirection.Top:
                    switch (collisionGO.tag)
                    {
                        case "Player":
                            // We were killed by the player above
                            PlayerColliderManager playerColliderManager = collisionGO.GetComponent<PlayerColliderManager>();
                            if (playerColliderManager)
                            {
                                if (!playerColliderManager.Dying)
                                {
                                    DestoryEnemy(true);
                                }
                            }
                            break;
                        case "Enemy":
                            // Bounce other enemies back
                            BounceAway(collision.contacts[0].normal);
                            break;
                        case "Core":
                        case "Dead":
                            // Now handled by the layer NoCollide
                            // Ignore the physics between this and the core or dead players
                            //Physics.IgnoreCollision(collision.collider, gameObject.GetComponent<Collider>());
                            break;
                    }
                    break;
                // We were hit from the bottom
                case CollisionDirection.Bottom:
                    switch (collisionGO.tag)
                    {
                        case "Player":
                            // Kill the player because we were on top
                            PlayerColliderManager playerColliderManager = collisionGO.GetComponent<PlayerColliderManager>();
                            if (playerColliderManager)
                            {
                                if (playerColliderManager.Deadly)
                                {
                                    DestoryEnemy(true);
                                }
                                else
                                {
                                    playerColliderManager.PlayerHit();
                                }
                            }
                            break;
                        case "Enemy":
                            // Bounce the enemy away
                            EnemyColliderManager enemyColliderManager = collisionGO.GetComponent<EnemyColliderManager>();
                            if (enemyColliderManager)
                            {
                                enemyColliderManager.BounceAway(-collision.contacts[0].normal);
                            }
                            break;
                        case "Core":
                        case "Dead":
                            // Now handled by the layer NoCollide
                            //Physics.IgnoreCollision(collision.collider, gameObject.GetComponent<Collider>());
                            break;
                    }
                    break;
                // Hits coming from any direction
                default:
                    switch (collisionGO.tag)
                    {
                        case "Mine":
                            MineColliderManager mineColliderManager = collisionGO.GetComponent<MineColliderManager>();
                            if (mineColliderManager)
                            {
                                mineColliderManager.HitMine();
                            }
                            break;
                        case "Asteroid":
                            AsteroidColliderManager asteroidColliderManager = collisionGO.GetComponent<AsteroidColliderManager>();
                            if (asteroidColliderManager)
                            {
                                asteroidColliderManager.BounceAway(gameObject, -collision.contacts[0].normal);
                            }
                            break;
                        case "Player":
                        case "Enemy":
                            EnemyColliderManager enemyColliderManager = collisionGO.GetComponent<EnemyColliderManager>();
                            if (enemyColliderManager)
                            {
                                enemyColliderManager.BounceAway(-collision.contacts[0].normal);
                            }
                            break;
                        case "Core":
                        case "Dead":
                            // Handled by the layers now
                            //Physics.IgnoreCollision(collision.collider, gameObject.GetComponent<Collider>());
                            break;
                    }
                    break;
            }
        }
    }

    /// <summary>
    /// Bounce away from the given position.
    /// </summary>
    /// <param name="collisionPos">Vector position the collision happened at.</param>
    public void BounceAway(Vector3 collisionPos)
    {        
        gameObject.GetComponent<Rigidbody>().AddForce(collisionPos * bounceForce, ForceMode.Impulse);
    }

    private void SpawnCore()
    {
        GameObject newCore = Instantiate(shipCore);
        CoreHoverMovement coreMovement = newCore.GetComponent<CoreHoverMovement>();
        if (coreMovement)
        {
            coreMovement.startPositionVector = _deathPos;
            coreMovement.startHeight = _deathHeight;
        }

        newCore.SetActive(true);
        AudioSource newCoreAS = newCore.GetComponent<AudioSource>();
        newCoreAS.PlayOneShot(coreSpawnedSFX);
        ObjectSpawning attachedShared = gameObject.GetComponent<EnemyObjectShared>().Spawner;
        if (attachedShared)
        {
            // Reduce the spawner objects count
            attachedShared.ReduceSpawnedCount();
        }
        Destroy(gameObject);
    }
    public void MagnetizeEnemy()
    {
        if (!_magnetHit)
        {
            _magnetHit = true;
            _magnetizeTime.RestartTimer();
        }
    }

    private void SpawnLoot()
    {
        int currentLootCount = 0;
        foreach (GameObject currentLoot in enemyLoot)
        {
            float currentRoll = Random.Range(0.0f, 1.0f) * 100.0f;

            if (currentRoll <= enemyLootChance[currentLootCount])
            {
                GameObject newLoot = Instantiate(currentLoot);
                PowerUpHoverMovement lootMovement = newLoot.GetComponent<PowerUpHoverMovement>();
                if (lootMovement)
                {
                    lootMovement.startPositionVector = _deathPos;
                    lootMovement.startHeight = _deathHeight;
                }

                newLoot.SetActive(true);
                AudioSource newLootAS = newLoot.GetComponent<AudioSource>();
                newLootAS.PlayOneShot(coreSpawnedSFX);
            }

            currentLootCount++;
        }
    }

    private void Update()
    {
        if (_enemyDestroyed)
        {
            if (_deathTimer.HasTicked(Time.deltaTime))
            {
                SpawnCore();
                SpawnLoot();
            }
            else
            {
                if (!_particleTimer.Started || _particleTimer.HasTicked(Time.deltaTime))
                {   
                    int randDir = Random.Range(0, 4);
                    float randOffset = Random.Range(0.0f, 2.0f);

                    Vector3 offsetDir;
                    switch (randDir)
                    {
                        case 1:
                            offsetDir = Vector3.down * randOffset;
                            break;
                        case 2:
                            offsetDir = Vector3.right * randOffset;
                            break;
                        case 3:
                            offsetDir = Vector3.left * randOffset;
                            break;
                        default:
                        case 0:
                            offsetDir = Vector3.up * randOffset;
                            break;
                    }

                    ParticleSystem boomboom = Instantiate(effectA);
                    ParticleSystem boomboom2 = Instantiate(effectB);
                    boomboom.transform.position = _deathPos + offsetDir;
                    boomboom2.transform.position = _deathPos + offsetDir;
                    if (_attachedAudioSource)
                    {
                        _attachedAudioSource.PlayOneShot(shipDeathSFX);
                    }

                    if (!_particleTimer.Started)
                    {
                        _particleTimer.HasTicked(Time.deltaTime);
                    }
                }
            }
        }
        if (_magnetHit)
        {
            if (_magnetizeTime.HasTicked(Time.deltaTime))
            {
                _magnetHit = false;
            }
        }
    }

    /// <summary>
    /// Method for destroying the enemy game object, it starts a coroutine to allow for an animation to be played.
    /// </summary>
    public void DestoryEnemy(bool addScore = false)
    {
        if (!_enemyDestroyed)
        {
            if (addScore)
            {
                EnemyObjectShared currentEnemyOS = gameObject.GetComponent<EnemyObjectShared>();
                if (currentEnemyOS != null)
                {
                    GameManager.Instance.AddScore(GameManager.Instance.GetCurrentLevelEnemyStats(currentEnemyOS.enemyTypeName).Score);
                }
            }

            // Store the position of death since the AI still moves after the models been deactivated.
            _deathPos = transform.position;
            HoverMovement currentHoverMovement = gameObject.GetComponent<HoverMovement>();
            currentHoverMovement.freezeMovement = true;
            _deathHeight = currentHoverMovement.GetCurrentHeight();
            shipModel.SetActive(false);
            _particleTimer = new TimerHelper(0.3f);
            gameObject.tag = "Dead";
            gameObject.layer = LayerMask.NameToLayer("NoCollide");
            _enemyDestroyed = true;
        }
    }
}
