using ActionGame.GameArtifacts.Models.Game;
using ActionGame.GameArtifacts.Models.Items;
using ActionGame.GameArtifacts.Models.Maps;
using ActionGame.GameArtifacts.Operators;
using ActionGame.GameResources.Models;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;


namespace ActionGame.GameArtifacts.Models.Characters
{
    public class Player : IBattleObject
    {
        public CharacterSet CharacterSet { get; set; }
        public WorldPosition WorldPosition { get; set; }
        public MovementPhysics MovementPhysics { get; set; }
        public CharacterStats CharacterStats { get; set; }
        public Inventory Inventory { get; private set; }

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


        public Player(GameData gameData)
        {
            this.Inventory = new Inventory();
            this.gameData = gameData;
        }


        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.001)
            {
                toMove = true;
                lastMoveUpdate = gameTime.TotalGameTime;
            }

            if (refreshAnimation)
            {
                UpdateAnimation();
            }

            if (toMove)
            {
                MovePlayer();

                CheckForCellTransport();

                CheckForDoorTransport();
            }
        }


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


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


        private void CheckForCellTransport()
        {
            const Int32 NONE = 0, TOP = 1, BOTTOM = 2, LEFT = 3, RIGHT = 4;
            Int32 direction = 0;
            Int32 cellMaxX = (gameData.GetWorldMapCell(this.WorldPosition).GetMaxTileX() * TileSet.DRAW_WIDTH) - TileSet.DRAW_WIDTH;
            Int32 cellMaxY = (gameData.GetWorldMapCell(this.WorldPosition).GetMaxTileY() * TileSet.DRAW_HEIGHT);

            Boolean atEdge = false;
            Boolean transport = false;
            WorldPosition newPosition = new WorldPosition();

            //detect if player is on edge of screen
            if (WorldPosition.PositionX <= 4)
            {
                direction = LEFT;
            }
            else if(WorldPosition.PositionY <= 4)
            {
                direction = TOP;
            }
            else if(WorldPosition.PositionX >= (cellMaxX-4))
            {
                direction = RIGHT;
            }
            else if (WorldPosition.PositionY >= (cellMaxY-4))
            {
                direction = BOTTOM;
            }

            if (direction != NONE)
            {
                //if player is on edge of screen and moving in same direction, transport them to cell if it exists
                if ((direction == TOP) && (MovementPhysics.VelocityY < 0))
                {
                    newPosition.WorldMapKey = this.WorldPosition.WorldMapKey;
                    newPosition.WorldCellX = this.WorldPosition.WorldCellX;
                    newPosition.WorldCellY = this.WorldPosition.WorldCellY - 1;
                    newPosition.PositionX = this.WorldPosition.PositionX;
                    newPosition.PositionY = cellMaxY;
                    atEdge = true;
                }
                else if ((direction == BOTTOM) && (MovementPhysics.VelocityY > 0))
                {
                    newPosition.WorldMapKey = this.WorldPosition.WorldMapKey;
                    newPosition.WorldCellX = this.WorldPosition.WorldCellX;
                    newPosition.WorldCellY = this.WorldPosition.WorldCellY + 1;
                    newPosition.PositionX = this.WorldPosition.PositionX;
                    newPosition.PositionY = TileSet.DRAW_HEIGHT;
                    atEdge = true;
                }
                else if ((direction == LEFT) && (MovementPhysics.VelocityX < 0))
                {
                    newPosition.WorldMapKey = this.WorldPosition.WorldMapKey;
                    newPosition.WorldCellX = this.WorldPosition.WorldCellX - 1;
                    newPosition.WorldCellY = this.WorldPosition.WorldCellY;
                    newPosition.PositionX = cellMaxX;
                    newPosition.PositionY = this.WorldPosition.PositionY;
                    atEdge = true;
                }
                else if ((direction == RIGHT) && (MovementPhysics.VelocityX > 0))
                {
                    newPosition.WorldMapKey = this.WorldPosition.WorldMapKey;
                    newPosition.WorldCellX = this.WorldPosition.WorldCellX + 1;
                    newPosition.WorldCellY = this.WorldPosition.WorldCellY;
                    newPosition.PositionX = 0;
                    newPosition.PositionY = this.WorldPosition.PositionY;
                    atEdge = true;
                }

                //check for cell existance
                if (atEdge)
                {
                    if(gameData.DoesWorldMapCellExist(newPosition))
                    {
                        transport = true;
                    }
                }

                if(transport)
                {
                    ObjectTransporter transporter = new ObjectTransporter(this, gameData);
                    transporter.Transport(newPosition);

                    WorldMapCellActivator cellActivator = new WorldMapCellActivator(gameData);
                    cellActivator.ActivateWorldMapCell(gameData.GetWorldMapCell(newPosition), newPosition);
                }
            }
        }


        private void CheckForDoorTransport() 
        {
            WorldMapCell worldMapCell = gameData.GetWorldMapCell(this.WorldPosition);
            Rectangle playerBounds = GetCurrentCollisionArea();
            Boolean transport = false;
            WorldPosition newPosition = null;

            foreach(Door door in gameData.GameState.ActiveDoors) 
            {
                if(playerBounds.Intersects(door.Location)) 
                {
                    newPosition = door.TransportPosition;
                    transport = true;
                }
            }

            if(transport)
            {
                ObjectTransporter transporter = new ObjectTransporter(this, gameData);
                transporter.Transport(newPosition);

                WorldMapCellActivator cellActivator = new WorldMapCellActivator(gameData);
                cellActivator.ActivateWorldMapCell(gameData.GetWorldMapCell(newPosition), newPosition);
            }
        }


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



    }
}
