using UnityEngine;

public class PlayerColliderManager : ColliderManager
{
    // After death immunity variables
    public float immunityTimer;
    private float _immunityCurrentTick;
    public float dyingTime;
    private TimerHelper _dyingTimer;
    private bool _dying = false;
    public float deadlyTime;
    private TimerHelper _deadlyTimer;
    private bool _deadly = false;

    public float flashTick;
    private float _currentFlashTick;
    private bool _flashed;

    private MeshRenderer _currentMeshRenderer;
    public Color immunityColorFlash;
    private Color _originalColor;

    public AudioClip shipDeathSFX;
    public AudioClip playerImmunitySFX;

    private PlayerHoverMovement _currentMovement;

    public ParticleSystem effectA;
    public ParticleSystem effectB;
    private TimerHelper _particleTimer;

    public bool Dying
    {
        get
        {
            return _dying;
        }
    }

    public bool Deadly
    {
        get
        {
            return _deadly;
        }
    }

    /// <summary>
    /// Method to handle awake tasks for the player collider.
    /// </summary>
    public override void DoAwakeTasks()
    {
        _currentMovement = gameObject.GetComponent<PlayerHoverMovement>();
        _currentMeshRenderer = shipModel.GetComponent<MeshRenderer>();
        _originalColor = _currentMeshRenderer.material.color;
        base.DoAwakeTasks();
    }

    public void SetImmune(float length)
    {
        _immunityCurrentTick += length;
    }

    /// <summary>
    /// Method for firing the core pick up method.
    /// </summary>
    /// <param name="coreGO">Core game object.</param>
    private void PickUpCore(GameObject coreGO)
    {
        CoreColliderManager coreColliderManager = coreGO.GetComponent<CoreColliderManager>();
        if (coreColliderManager)
        {
            coreColliderManager.PickupCore();
        }
    }

    private void Start()
    {
        _dyingTimer = new TimerHelper(dyingTime, false);
        _deadlyTimer = new TimerHelper(deadlyTime, false);
        _particleTimer = new TimerHelper(0.3f);
    }

    /// <summary>
    /// Method for killing the player without a collision, used for the debug console mainly
    /// </summary>
    public override void TriggerDeath()
    {
        PlayerHit(true);
        base.TriggerDeath();
    }

    /// <summary>
    /// Process the Player 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.gameObject.transform.parent.gameObject;
        }
        else
        {
            collisionGO = collision.gameObject;
        }

        if (!Dying)
        {
            switch (direction)
            {
                case CollisionDirection.Top:
                    switch (collisionGO.tag)
                    {
                        case "Mine":
                            MineColliderManager mineColliderManager = collisionGO.GetComponent<MineColliderManager>();
                            if (mineColliderManager)
                            {
                                mineColliderManager.HitMine();
                            }
                            break;
                        case "Enemy":
                            // Enemy hit players top.
                            EnemyColliderManager enemyColliderManager = collisionGO.GetComponent<EnemyColliderManager>();
                            if (enemyColliderManager)
                            {
                                if (!enemyColliderManager.Dying)
                                {
                                    if (Deadly)
                                    {
                                        enemyColliderManager.DestoryEnemy(true);
                                    }
                                    else
                                    {
                                        PlayerHit();
                                    }
                                }
                            }
                            break;
                        case "Core":
                            // Collected a core.
                            PickUpCore(collisionGO);
                            break;
                        case "Dead":
                            // Now handled by the layer NoCollide
                            // Ignore dead enemies collision
                            //Physics.IgnoreCollision(collision.collider, gameObject.GetComponent<Collider>());
                            break;
                    }
                    break;
                case CollisionDirection.Bottom:
                    switch (collisionGO.tag)
                    {
                        case "Mine":
                            MineColliderManager mineColliderManager = collisionGO.GetComponent<MineColliderManager>();
                            if (mineColliderManager)
                            {
                                mineColliderManager.HitMine();
                            }
                            break;
                        case "Enemy":
                            // Kill the collided enemy
                            EnemyColliderManager enemyColliderManager = collisionGO.GetComponent<EnemyColliderManager>();
                            if (enemyColliderManager)
                            {
                                enemyColliderManager.DestoryEnemy(true);
                            }
                            break;
                        case "Core":
                            // Pick up core
                            PickUpCore(collisionGO);
                            break;
                        case "Dead":
                            // Now handled by the layer NoCollide
                            //Physics.IgnoreCollision(collision.collider, gameObject.GetComponent<Collider>());
                            break;
                    }
                    break;
                default:
                    switch (collisionGO.tag)
                    {
                        case "Enemy":
                            EnemyColliderManager enemyColliderManager = collisionGO.GetComponent<EnemyColliderManager>();
                            if (enemyColliderManager)
                            {
                                if (Deadly)
                                {
                                    // Kill the collided enemy
                                    enemyColliderManager.DestoryEnemy(true);
                                }
                                else
                                {
                                    enemyColliderManager.BounceAway(-collision.contacts[0].normal);
                                }
                            }                            
                            break;
                        case "Mine":
                            MineColliderManager mineColliderManager = collisionGO.GetComponent<MineColliderManager>();
                            if (mineColliderManager)
                            {
                                mineColliderManager.HitMine();
                            }
                            break;
                        case "Asteroid":
                            // Player hit an asteroid from any direction, get bounced
                            AsteroidColliderManager asteroidColliderManager = collisionGO.GetComponent<AsteroidColliderManager>();
                            if (asteroidColliderManager)
                            {
                                asteroidColliderManager.BounceAway(gameObject, -collision.contacts[0].normal);
                            }
                            break;
                        case "Core":
                            PickUpCore(collisionGO);
                            break;
                    }
                    break;
            }
        }
    }

    public void SetDeadly()
    {
        _deadly = true;
        _deadlyTimer.RestartTimer();
    }

    /// <summary>
    /// Method for dealing with the player being hit and losing a life
    /// </summary>
    /// <param name="blackHoleDeath">If the player was hit by the black hole, this ignores immunity.</param>
    public void PlayerHit(bool blackHoleDeath = false)
    {
        if (_dying || GameManager.Instance.godMode)
        {
            return;
        }

        // Check if we are currently in immunity.
        if (_immunityCurrentTick == 0.0f || blackHoleDeath)
        {
            if (_attachedAudioSource)
            {
                _attachedAudioSource.PlayOneShot(shipDeathSFX);
            }
            // Remove a life from the game manager
            _dying = true;
            _dyingTimer.RestartTimer();
            Rigidbody currentRigidBody = gameObject.GetComponent<Rigidbody>();
            if (currentRigidBody != null)
            {
                currentRigidBody.velocity = Vector3.zero;
            }
            GameEngine.playerPaused = true;
            if (shipModel != null)
            {
                shipModel.SetActive(false);
            }
            _particleTimer.RestartTimer();
            Time.timeScale = 0.2f;
        }
    }

    /// <summary>
    /// Method for dealing with the immunity flashing.
    /// </summary>
    /// <param name="forceReset">Force the flash to end.</param>
    private void FlashToggle(bool forceReset = false)
    {
        if (_flashed || forceReset)
        {
            _currentMeshRenderer.material.color = _originalColor;
            _flashed = false;
        }
        else
        {
            _currentMeshRenderer.material.color = immunityColorFlash;
            if (_attachedAudioSource)
            {
                _attachedAudioSource.PlayOneShot(playerImmunitySFX);
            }
            _flashed = true;
        }
    }

    public void Update()
    {
        if (!GameEngine.isPaused)
        {
            if (Deadly)
            {
                if (_deadlyTimer.HasTicked(Time.deltaTime))
                {
                    _deadly = false;
                }
            }

            if (Dying)
            {
                if (_dyingTimer.HasTicked(Time.deltaTime))
                {
                    GameManager.Instance.LostLife();
                    if (GameManager.Instance.CurrentLives > -1)
                    {                        
                        _currentMovement.ForceStartLocationReset();
                        _immunityCurrentTick = 0.0f;

                        SetImmune(immunityTimer);
                        //_immunityCurrentTick = immunityTimer;
                        _flashed = false;

                        if (shipModel != null)
                        {
                            shipModel.SetActive(true);
                        }
                        GameEngine.playerPaused = false;
                        _dying = false;
                    }                    
                    Time.timeScale = 1.0f;
                }
                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 = gameObject.transform.position + offsetDir;
                        boomboom2.transform.position = gameObject.transform.position + offsetDir;
                        if (_attachedAudioSource)
                        {
                            _attachedAudioSource.PlayOneShot(shipDeathSFX);
                        }

                        if (!_particleTimer.Started)
                        {
                            _particleTimer.HasTicked(Time.deltaTime);
                        }
                    }
                }
            }


            // If we are immune flash the player to show it.
            if (_immunityCurrentTick > 0.0f)
            {
                if (_currentFlashTick >= flashTick)
                {
                    FlashToggle();
                    _currentFlashTick = 0.0f;
                }
                else
                {
                    _currentFlashTick += Time.deltaTime;
                }

                _immunityCurrentTick -= Time.deltaTime;
                if (_immunityCurrentTick < 0.0f)
                {
                    _immunityCurrentTick = 0.0f;
                }
            }
            else
            {
                _immunityCurrentTick = 0.0f;
                FlashToggle(true);
                _flashed = false;
            }
        }
    }
}
