using ActionGame.GameArtifacts.Factories;
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 Newtonsoft.Json;
using System;
using System.Collections.Generic;
using static ActionGame.GameResources.Models.NonPlayerCharacterDefinition;


namespace ActionGame.GameArtifacts.Models.Characters
{
    public class NonPlayerCharacter : ICharacter
    {
        public WorldPosition WorldPosition { get; set; }
        public CharacterSet CharacterSet { get; set; }
        public MovementPhysics MovementPhysics { get; set; }
        public INonPlayerCharacterMovement Movement { get; set; }
        public IList<PlotItem> Plot { get; set; }
        public Activation ActivationType { get; set; }
        public String HideIfVariableTrue { get; set; }
        public String ShowIfVariableTrue { get; set; }

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


        private NonPlayerCharacter()
        {

        }


        public NonPlayerCharacter(NonPlayerCharacterDefinition definition, IGameContentManager gameContentManager, WorldPosition cell, GameData gameData)
        {
            this.gameData = gameData;
            this.MovementPhysics = new MovementPhysics();
            this.CharacterSet = gameContentManager.CharacterSetRepository.GetContent(definition.CharacterSetKey).Copy();
            this.WorldPosition = new WorldPosition()
            {
                PositionX = definition.TileX * TileSet.DRAW_WIDTH,
                PositionY = (definition.TileY * TileSet.DRAW_HEIGHT) + TileSet.DRAW_HEIGHT,
                WorldMapKey = cell.WorldMapKey,
                WorldCellX = cell.WorldCellX,
                WorldCellY = cell.WorldCellY
            };

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

            this.Plot = JsonConvert.DeserializeObject<List<PlotItem>>(definition.PlotScriptText);

            this.ActivationType = (Activation)definition.ActivationKey;
            this.HideIfVariableTrue = definition.HideIfVariableTrue;
            this.ShowIfVariableTrue = definition.ShowIfVariableTrue;
        }


        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();
            }

            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();
        }


        public Rectangle GetActivationCollisionArea()
        {
            Int32 x = this.WorldPosition.PositionX;
            Int32 y = this.WorldPosition.PositionY;
            Int32 tile = TileSet.DRAW_WIDTH;

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

            return area;
        }


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

            return GetCollisionAreaAtPosition(x, y);
        }


        public Rectangle GetCollisionAreaAtPosition(Int32 x, Int32 y)
        {
            Int32 tile = TileSet.DRAW_WIDTH;
            Int32 width = (Int32)(tile * (8.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 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 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);
        }


    }
}
