using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;

namespace MegaManRipoff.MainGameClasses
{
    /// <summary>
    /// The base class for all in-game enemies.
    /// </summary>
    class Enemy : HealthyEntity
    {
        #region Member Variables

        /// <summary>
        /// Amount of health the enemy currently has.
        /// </summary>
        protected int _health;

        /// <summary>
        /// The maximum amount of health the enemy can have.
        /// </summary>
        static int _maxHealth;

        /// <summary>
        /// The amount of damage this enemy deals upon collision..
        /// </summary>
        static int _damage;

        /// <summary>
        /// Determines if the enemy should deflect the player's bullets.
        /// </summary>
        protected bool _deflectBullets;

        /// <summary>
        /// Keeps track of how long the enemy should remain in the flashing,
        /// post-hit invincibility state.
        /// </summary>
        protected int _invincibiltyTimer;

        /// <summary>
        /// The length of time, in ticks, to be in the post-hit invincibility state upon
        /// recovering from being hurt.
        /// </summary>
        protected const int InvincibilityDuration = 6;

        /// <summary>
        /// Sound effect used when the enemy shoots.
        /// </summary>
        static SoundEffect _shootSound;

        /// <summary>
        /// Sound effect used when the enemy deflects a player's bullet.
        /// </summary>
        static SoundEffect _deflectSound;

        /// <summary>
        /// Sound effect used when the enemy gets hit by a player's bullet.
        /// </summary>
        static SoundEffect _hurtSound;

        #endregion

        #region Properties

        /// <summary>
        /// Accessor for the amount of health the enemy currently has.
        /// </summary>
        public override int Health
        {
            get { return _health; }
            set { _health = Math.Min(value, _maxHealth); }
        }

        /// <summary>
        /// Accessor for the maximum amount of health the enemy can have.
        /// </summary>
        public override int MaxHealth
        {
            get { return _maxHealth; }
        }

        /// <summary>
        /// Accessor for the amount of damage the enemy deals.
        /// </summary>
        public virtual int Damage
        {
            get { return _damage; }
        }

        /// <summary>
        /// Gets the sound effect used for when the enemy shoots.
        /// </summary>
        protected static SoundEffect ShootSound
        {
            get { return _shootSound; }
        }

        /// <summary>
        /// Gets the sound effect used for when the enemy deflects a player's bullet.
        /// </summary>
        protected static SoundEffect DeflectSound
        {
            get { return _deflectSound; }
        }

        /// <summary>
        /// Gets the sound effect used for when the enemy gets hit by a player's bullet.
        /// </summary>
        protected static SoundEffect HurtSound
        {
            get { return _hurtSound; }
        }


        #endregion

        protected Enemy(Room room, Vector2 position)
            : base(room, position)
        {
        }

        #region Methods

        /// <summary>
        /// Load some basic sound effects for enemies.
        /// </summary>
        /// <param name="content">The game's content manager.</param>
        new public static void LoadContent(ContentManager content)
        {
            _shootSound = content.Load<SoundEffect>("Sounds\\EnemyShoot");
            _deflectSound = content.Load<SoundEffect>("Sounds\\Deflect");
            _hurtSound = content.Load<SoundEffect>("Sounds\\EnemyHurt");
        }

        /// <summary>
        /// Makes the enemy faces the player, as long as the player exists.
        /// </summary>
        protected void FacePlayer()
        {
            //If the player exists, flip so that the Metool is facing him.
            if (_room.PlayerOne != null)
            {
                if (_room.PlayerOne.Hitbox.Center.X > Hitbox.Center.X)
                {
                    _direction = Direction.Right;
                }
                else
                {
                    _direction = Direction.Left;
                }
            }
        }

        /// <summary>
        /// Checks for any intersecting Player bullet hitboxes, and takes damage accordingly.
        /// </summary>
        protected void CollideWithBullets()
        {
            //If we're not in the post-hit invincibilty state...
            if (_invincibiltyTimer <= 0)
            {
                //Be ready to store references to the bullet upon collision so that it can be removed
                //once we have finished iterating through the list of bullets.
                Bullet bulletToDeflect = null;
                Bullet bulletToDestroy = null;

                //Iterate through the list of bullets.
                foreach (Bullet bullet in _room.Bullets)
                {
                    //If the enemy bullet is intersecting our hitbox...
                    if (bullet.BulletOwner is Player && bullet.Hitbox.Intersects(Hitbox))
                    {
                        //Check if we should deflect the bullet.
                        if (_deflectBullets)
                        {
                            //Store a reference to the bullet so we can deflect it once
                            //we're out of the foreach loop.
                            bulletToDeflect = bullet;

                            //Stop iteration.
                            break;
                        }
                        else
                        {
                            //Take some damage.
                            GetHurt(bullet.Damage);

                            //Store a reference to the bullet if it is supposed to be destroyed upon
                            //a collision.
                            if (bullet.DestroyOnCollision)
                            {
                                bulletToDestroy = bullet;
                            }

                            //Stop iteration.
                            break;
                        }
                    }
                }

                //Destroy the bullets that we're supposed to destroy.
                if (bulletToDestroy != null)
                {
                    bulletToDestroy.Remove();
                }

                //Deflect all bullets that we're supposed to deflect.
                if (bulletToDeflect != null)
                {
                    //Call the bullet's deflection method.
                    bulletToDeflect.Deflect();

                    //Play the deflection sound.
                    _deflectSound.Play();
                }
            }
        }

        /// <summary>
        /// Deals damage to the enemy. If the damage is enough to reduce the player's health
        /// to zero, this method will call Die().
        /// </summary>
        /// <param name="damage">The amount of damage to take.</param>
        protected override void GetHurt(int damage)
        {
            _health = Math.Max(0, _health - damage);

            //If the player dealt enough damage to bring our health to zero, then
            //kill the enemy.
            if (_health == 0)
            {
                Die();
            }
            //Otherwise, we've only been hurt.
            else
            {
                //Set the hurt timer.
                _invincibiltyTimer = InvincibilityDuration;

                //Play the sound effect.
                _hurtSound.Play();
            }
        }

        /// <summary>
        /// Kills the enemy.
        /// </summary>
        protected override void Die()
        {
            //Create an explosion effect.
            _room.Add(new ExplosionEffect(_room, new Vector2(Hitbox.Center.X, Hitbox.Center.Y), null));

            //Remove the reference to this enemy.
            _room.Remove(this);
        }

        /// <summary>
        /// Checks for bullet collisons and updates the enemy's post-hit invincibility timer.
        /// </summary>
        /// <param name="gameTime">The game's current snapshot of time.</param>
        public override void Update(GameTime gameTime)
        {
            //If we're in the post-hit flashing state, decrease the timer.
            if (_invincibiltyTimer > 0)
            {
                _invincibiltyTimer--;
            }
            //Otherwise, check for collisions with bullets.
            else
            {
                CollideWithBullets();
            }
        }

        #endregion
    }
}
