using ActionGame.GameArtifacts.Factories;
using ActionGame.GameArtifacts.Intelligence.EnemyAttack;
using ActionGame.GameArtifacts.Intelligence.NonPlayerCharacterMovement;
using ActionGame.GameArtifacts.Models.Game;
using ActionGame.GameArtifacts.Operators;
using ActionGame.GameResources.Manager;
using ActionGame.GameResources.Models;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections.Generic;


namespace ActionGame.GameArtifacts.Models.Characters
{
    public class Enemy : IBattleObject
    {
        public CharacterSet CharacterSet { get; set; }
        public WorldPosition WorldPosition { get; set; }
        public MovementPhysics MovementPhysics { get; set; }
        public CharacterStats CharacterStats { get; set; }
        public INonPlayerCharacterMovement Movement { get; set; }
        public IEnemyAttack Attack { get; set; }

        public IList<ItemContainer> Inventory { get; set; }
        public String VariableToSetTrueUponDeath { get; set; }
        public String HideIfVariableTrue { get; set; }

        private GameData gameData;
        private TimeSpan lastAnimationUpdate;
        private TimeSpan lastMoveUpdate;


        public Enemy(EnemyDefinition definition, IGameContentManager gameContentManager, WorldPosition cell, GameData gameData)
        {
            this.gameData = gameData;
            this.MovementPhysics = new MovementPhysics();
            this.CharacterSet = gameContentManager.CharacterSetRepository.GetContent(definition.CharacterSetKey).Copy();
            this.WorldPosition = cell.Copy();

            MovementFactory movementFactory = new MovementFactory(gameData);
            this.Movement = movementFactory.GetMovement(definition.MovementKey, this);

            EnemyAttackFactory enemyAttackFactory = new EnemyAttackFactory(gameData.RawContentManager, gameData);
            this.Attack = enemyAttackFactory.GetAttack(definition.AttackKey, this, definition.AttackSpeed);

            this.VariableToSetTrueUponDeath = definition.VariableToSetTrueUponDeath;
            this.HideIfVariableTrue = definition.HideIfVariableTrue;

            this.CharacterStats = new CharacterStats()
            {
                Health = definition.Health,
                MaximumHealth = definition.Health,
                Attack = definition.Attack,
                Defence = definition.Defence
            };

            this.Inventory = definition.Inventory;
        }


        public void Draw(SpriteBatch spriteBatch)
        {
            Rectangle screenDrawRect = new Rectangle(this.WorldPosition.PositionX, this.WorldPosition.PositionY - CharacterSet.DRAW_HEIGHT, CharacterSet.DRAW_WIDTH, CharacterSet.DRAW_HEIGHT);

            spriteBatch.Draw(this.CharacterSet.CurrentTexture, screenDrawRect, Color.White);
        }


        public Rectangle GetCollisionAreaAtPosition(int x, int y)
        {
            Int32 tile = TileSet.DRAW_WIDTH;
            Int32 width = (Int32)(tile * (7.0 / 8.0));
            Int32 height = (Int32)(tile * (2.0 / 4.0));

            Rectangle area = new Rectangle(x + ((tile - width) / 2), y - height, width, height);

            return area;
        }


        public Rectangle GetCurrentCollisionArea()
        {
            Int32 x = this.WorldPosition.PositionX;
            Int32 y = this.WorldPosition.PositionY;

            return GetCollisionAreaAtPosition(x, y);
        }


        public Rectangle GetDamageCollisionArea()
        {
            Int32 x = this.WorldPosition.PositionX;
            Int32 y = this.WorldPosition.PositionY;
            Int32 tile = TileSet.DRAW_WIDTH;
            Int32 width = (Int32)(tile * (8.0 / 8.0));
            Int32 height = (Int32)(tile * (4.0 / 4.0));

            Rectangle area = new Rectangle(x + ((tile - width) / 2), y - height, width, height);

            return area;
        }


        public Rectangle GetDrawArea()
        {
            Int32 x = this.WorldPosition.PositionX;
            Int32 y = this.WorldPosition.PositionY;
            Int32 tile = TileSet.DRAW_WIDTH;
            Int32 width = (Int32)(tile * (8.0 / 8.0));
            Int32 height = (Int32)(tile * (8.0 / 4.0));

            Rectangle area = new Rectangle(x + (tile - width), y - height, width, height);

            return area;
        }


        public void Update(GameTime gameTime)
        {
            Boolean refreshAnimation = false;
            Boolean toMove = false;

            if (lastAnimationUpdate == null) lastAnimationUpdate = gameTime.TotalGameTime;
            if (lastMoveUpdate == null) lastMoveUpdate = gameTime.TotalGameTime;


            if ((gameTime.TotalGameTime - lastAnimationUpdate).TotalSeconds > 0.10)
            {
                refreshAnimation = true;
                lastAnimationUpdate = gameTime.TotalGameTime;
            }

            if ((gameTime.TotalGameTime - lastMoveUpdate).TotalSeconds > 0.01)
            {
                toMove = true;
                lastMoveUpdate = gameTime.TotalGameTime;
            }

            this.Movement?.Act(gameTime);

            if (toMove)
            {
                MoveCharacter();
            }

            this.Movement?.PostMovementAct(gameTime);

            this.Attack?.Act(gameTime);

            if (refreshAnimation)
            {
                UpdateAnimation();
            }
        }


        private void UpdateAnimation()
        {
            CharacterSetAnimator animator = new CharacterSetAnimator(this);
            animator.Update();
        }


        private void MoveCharacter()
        {
            WorldMapCell worldMapCell = gameData.GetWorldMapCell(this.WorldPosition);
            PhysicsEngine physics = new PhysicsEngine(this, worldMapCell, gameData.GameState);
            physics.Update();
        }


    }
}
