using ActionGame.GameArtifacts.Models.Characters;
using ActionGame.GameArtifacts.Models.Game;
using ActionGame.GameArtifacts.Operators;
using ActionGame.GameArtifacts.Operators.Characters;
using ActionGame.GameResources.Models;
using ActionGame.RawResources.Manager;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections.Generic;


namespace ActionGame.GameArtifacts.Models.WeaponSprites
{
    public class GunShot : IWeaponSprite
    {
        public WorldPosition WorldPosition { get; set; }
        public MovementPhysics MovementPhysics { get; set; }
        public Boolean IsExpired { get; set; }

        private IRawContentManager rawContentManager;
        private GameData gameData;
        private IBattleObject caster;
        private Int32 attack;
        private Boolean hasDamaged;

        private IList<Texture2D> textures;
        private Int32 frame;
        private TimeSpan lastFrameUpdateTime;

        private TimeSpan creationTime;
        private readonly Int32 size = 24;
        private TimeSpan lastMoveUpdate;

        private IList<IBattleObject> damaged;
        private IList<IBattleObject> ignoredObjects;


        public GunShot(IRawContentManager rawContentManager, GameData gameData, IBattleObject caster, WorldPosition worldPosition, Int32 attack, IList<IBattleObject> ignoredObjects)
        {
            this.IsExpired = false;
            this.rawContentManager = rawContentManager;
            this.gameData = gameData;

            this.caster = caster;
            this.WorldPosition = worldPosition.Copy();
            this.MovementPhysics = new MovementPhysics();

            this.textures = new List<Texture2D>();
            this.textures.Add(rawContentManager.TextureRepository.GetContent(@"textures\items\gunshot-1"));
            this.textures.Add(rawContentManager.TextureRepository.GetContent(@"textures\items\gunshot-2"));
            
            this.attack = attack;
            this.frame = 0;
            this.hasDamaged = false;
            
            this.ignoredObjects = ignoredObjects;
            if (this.ignoredObjects == null) this.ignoredObjects = new List<IBattleObject>();

            this.damaged = new List<IBattleObject>();
        }


        public Rectangle GetCurrentCollisionArea()
        {
            Rectangle rect = GetCollisionAreaAtPosition(this.WorldPosition.PositionX, this.WorldPosition.PositionY);

            return rect;
        }


        public Rectangle GetCollisionAreaAtPosition(int x, int y)
        {
            Rectangle rect = new Rectangle(x, y - size, size, size);

            return rect;
        }


        public Rectangle GetDrawArea()
        {
            return GetCurrentCollisionArea();
        }


        public void Update(GameTime gameTime)
        {
            if (lastMoveUpdate == null) lastMoveUpdate = gameTime.TotalGameTime;
            if (creationTime == default(TimeSpan)) creationTime = gameTime.TotalGameTime;
            if (lastFrameUpdateTime == default(TimeSpan)) lastFrameUpdateTime = gameTime.TotalGameTime;

            //move object
            if ((gameTime.TotalGameTime - lastMoveUpdate).TotalSeconds > 0.001)
            {
                WorldMapCell worldMapCell = gameData.GetWorldMapCell(this.WorldPosition);
                PhysicsEngine physics = new PhysicsEngine(this, worldMapCell, gameData.GameState);
                physics.IgnoreObjects.Add(caster);
                if(ignoredObjects != null) foreach (IBattleObject obj in ignoredObjects) physics.IgnoreObjects.Add(obj);
                physics.IgnoreAllCollisions = true;
                physics.Update();

                lastMoveUpdate = gameTime.TotalGameTime;
            }

            //frame update
            if ((gameTime.TotalGameTime - lastFrameUpdateTime).TotalSeconds > 0.1)
            {
                lastFrameUpdateTime = gameTime.TotalGameTime;

                frame++;
                if (frame >= this.textures.Count) frame = 0;
            }


            //detect hit and damage enemy
            DetectHitAndDoDamage();


            //expire sprite
            if (this.MovementPhysics.IsMoving() == false)
            {
                IsExpired = true;

                ImpactSprite impactSprite = new ImpactSprite(this.rawContentManager, this.WorldPosition);
                gameData.GameState.ActiveDisplaySprites.Add(impactSprite);
            }
            else if ((gameTime.TotalGameTime - creationTime).TotalSeconds > 5)
            {
                IsExpired = true;
            }
        }


        private void DetectHitAndDoDamage()
        {
            IList<IBattleObject> objectsInRange = gameData.GameState.GetBattleObjectsInArea(GetCurrentCollisionArea());

            foreach (IBattleObject target in objectsInRange)
            {
                if ((target != caster) && (ignoredObjects.Contains(target) == false) && (damaged.Contains(target) == false))
                {
                    Damager damager = new Damager();

                    Int32 damageDone = damager.Do(this.attack, target);

                    if (damageDone != 0)
                    {
                        DamageSprite damageSprite = new DamageSprite(rawContentManager, target, damageDone, target.WorldPosition);
                        gameData.GameState.ActiveDisplaySprites.Add(damageSprite);
                    }

                    damaged.Add(target);

                    hasDamaged = true;
                }
            }
        }


        public void Draw(SpriteBatch spriteBatch)
        {
            Rectangle rect = this.GetDrawArea();

            spriteBatch.Draw(this.textures[frame], rect, Color.White);
        }


    }
}
