#pragma once
#include <SDL2/SDL.h>

#include "utils.h"
#include "asset.h"
#include "room.h"
#include "animatedsprite.h"
#include "input.h"
#include "const.h"
#include "debug.h"
#include <string>
#include <vector>

#ifndef PLAYER_H
#define PLAYER_H

enum state_e
{
	s_standing,
	s_jumping,
	s_falling
};

struct player_t
{
	float x;
	float y;
	float vx;
	float vy;
	int jump_ini;
	state_e state;
	SDL_RendererFlip flip;
};

// Clase Player
class Player
{
public:
	float x;							   // Posición del jugador en el eje X
	float y;							   // Posición del jugador en el eje Y
	float vx;							   // Velocidad/desplazamiento del jugador en el eje X
	float vy;							   // Velocidad/desplazamiento del jugador en el eje Y
	int w;								   // Ancho del jugador
	int h;								   // ALto del jugador
	SDL_Renderer *renderer;				   // El renderizador de la ventana
	Input *input;						   // Objeto para gestionar la entrada
	Asset *asset;						   // Objeto con la ruta a todos los ficheros de recursos
	Room *room;							   // Objeto encargado de gestionar cada habitación del juego
	LTexture *texture;					   // Textura con los graficos del enemigo
	AnimatedSprite *sprite;				   // Sprite del enemigo
	Debug *debug;						   // Objeto para gestionar la información de debug
	color_t color;						   // Color del jugador
	SDL_Rect colliderBox;				   // Caja de colisión con los enemigos u objetos
	std::vector<SDL_Point> colliderPoints; // Puntos de colisión con el mapa
	std::vector<SDL_Point> underFeet;	   // Contiene los puntos que hay bajo cada pie del jugador
	std::vector<SDL_Point> feet;		   // Contiene los puntos que hay en el pie del jugador
	state_e state;						   // Estado en el que se encuentra el jugador. Util apara saber si está saltando o cayendo
	bool onBorder;						   // Indica si el jugador esta en uno de los cuatro bordes de la pantalla
	int border;							   // Indica en cual de los cuatro bordes se encuentra
	bool invincible;					   // Si es invencible, no puede morir
	SDL_Rect lastPosition;				   // Contiene la ultima posición del jugador, por si hay que deshacer algun movimiento
	int jump_ini;						   // Valor del eje Y en el que se inicia el salto
	float maxVY;						   // Velocidad máxima que puede alcanzar al desplazarse en vertical

	// Comprueba las entradas y modifica variables
	void checkInput();

	// Comprueba si se halla en alguno de los cuatro bordes
	void checkBorders();

	// Comprueba el estado del jugador
	void checkState();

	// Asigna velocidad negativa en el eje Y al jugador
	void jump();

	// Aplica gravedad al jugador
	void applyGravity();

	// Recalcula la posición del jugador y su animación
	void move();

	// Establece la animación del jugador
	void animate();

	// Comprueba si ha finalizado el salto al alcanzar la altura de inicio
	void checkJumpEnd();

	// Comprueba si el jugador tiene suelo debajo de los pies
	bool isOnFloor();

	// Comprueba que el jugador no atraviese ninguna pared
	bool checkWalls();

	// Comprueba si el jugador está en una rampa
	tile_e checkSlopes();

	// Comprueba si el jugador está en una rampa
	tile_e checkSlopes2();

	// Actualiza los puntos de colisión
	void updateColliderPoints();

	// Actualiza los puntos de los pies
	void updateFeet();

public:
	// Constructor
	Player(player_t ini, std::string tileset, std::string animation, SDL_Renderer *renderer, Asset *asset, Input *input, Room *room, Debug *debug);

	// Destructor
	~Player();

	// Pinta el enemigo en pantalla
	void render();

	// Actualiza las variables del objeto
	void update();

	// Indica si el jugador esta en uno de los cuatro bordes de la pantalla
	bool getOnBorder();

	// Indica en cual de los cuatro bordes se encuentra
	int getBorder();

	// Cambia al jugador de un borde al opuesto. Util para el cambio de pantalla
	void switchBorders();

	// Obtiene el rectangulo que delimita al jugador
	SDL_Rect getRect();

	// Obtiene el rectangulo de colision del jugador
	SDL_Rect &getCollider();

	// Obtiene algunos parametros del jugador
	player_t getSpawnParams();

	// Recarga la textura
	void reLoadTexture();

	// Establece el valor de la variable
	void setRoom(Room *room);

	// Obtiene el valor de la variable
	bool getInvincible();

	// Establece el valor de la variable
	void setInvincible(bool value);
};

#endif
