#pragma once

#include <SDL2/SDL_gamecontroller.h> // for SDL_GameControllerButton
#include <SDL2/SDL_rect.h>			 // for SDL_Rect, SDL_Point
#include <SDL2/SDL_render.h>		 // for SDL_Renderer
#include <SDL2/SDL_stdinc.h>		 // for Uint8, Uint32
#include <stdint.h>					 // for int32_t
#include <string>					 // for string, basic_string
#include <vector>					 // for vector
#include "input.h"					 // for inputs_e
struct JA_Music_t;
struct JA_Sound_t;
enum class ScreenFilter;
enum class ScreenVideoMode;

// Dificultad del juego
enum class GameDifficulty
{
	EASY = 0,
	NORMAL = 1,
	HARD = 2,
};

// Tamaño de bloque
#define BLOCK 8

// Estructura para definir un circulo
struct Circle
{
	int x, y, r;
};

// Estructura para definir un color
struct Color
{
	Uint8 r, g, b;
};

// Posiciones de las notificaciones
enum class NotifyPosition
{
	TOP,
	BOTTOM,
	LEFT,
	MIDDLE,
	RIGHT,
};

// Estructura para saber la seccion y subseccion del programa
struct Section
{
	Uint8 name;
	Uint8 options;
};

// Estructura para las entradas de la tabla de recirds
struct HiScoreEntry
{
	std::string name; // Nombre
	int score;		  // Puntuación
};

// Estructura para mapear el teclado usado en la demo
struct DemoKeys
{
	Uint8 left;
	Uint8 right;
	Uint8 no_input;
	Uint8 fire;
	Uint8 fire_left;
	Uint8 fire_right;
};

// Estructura para las opciones de la ventana
struct OptionsWindow
{
	int size; // Contiene el valor por el que se multiplica el tamaño de la ventana
};

// Estructura con opciones para el video
struct OptionsVideo
{
	OptionsWindow window; // Opciones para la ventana del programa
	ScreenVideoMode mode; // Contiene el valor del modo de pantalla completa
	ScreenFilter filter;  // Filtro usado para el escalado de la imagen
	bool v_sync;		  // Indica si se quiere usar vsync o no
	bool shaders;		  // Indica si se van a usar shaders para los filtros de video
};

// Estructura para las opciones de musica
struct OptionsMusic
{
	bool enabled; // Indica si la musica suena o no
	int volume;	  // Volumen al que suena la música
};

// Estructura para las opciones de sonido
struct OptionsSound
{
	bool enabled; // Indica si los sonidos suenan o no
	int volume;	  // Volumen al que suenan los sonidos
};

// Estructura para las opciones de audio
struct OptionsAudio
{
	OptionsMusic music; // Opciones para la música
	OptionsSound sound; // Opciones para los efectos de sonido
};

// Estructura para las opciones del juego
struct OptionsGame
{
	GameDifficulty difficulty;				  // Dificultad del juego
	Uint8 language;							  // Idioma usado en el juego
	bool autofire;							  // Indica si el jugador ha de pulsar repetidamente para disparar o basta con mantener pulsado
	std::vector<HiScoreEntry> hi_score_table; // Tabla con las mejores puntuaciones
};

// Estructura para los controles del juego
struct OptionsController
{
	int index;									   // Indice en el vector de mandos
	int player_id;								   // Jugador asociado al mando
	Uint8 device_type;							   // Indica si se utilizará teclado o mando o ambos
	std::string name;							   // Nombre del dispositivo
	bool plugged;								   // Indica si el mando se encuentra conectado
	std::vector<inputs_e> inputs;				   // Listado de inputs
	std::vector<SDL_GameControllerButton> buttons; // Listado de botones asignados a cada input
};

// Estructura para las opciones de las notificaciones
struct OptionsNotification
{
	NotifyPosition pos_h; // Ubicación de las notificaciones en pantalla
	NotifyPosition pos_v; // Ubicación de las notificaciones en pantalla
	bool sound;			  // Indica si las notificaciones suenan
	Color color;		  // Color de las notificaciones
};

// Estructura con todas las opciones de configuración del programa
struct Options
{
	OptionsGame game;						   // Opciones para el propio juego
	OptionsVideo video;						   // Opciones relativas a la clase screen
	OptionsAudio audio;						   // Opciones para el audio
	OptionsNotification notification;		   // Opciones para las notificaciones
	std::vector<OptionsController> controller; // Opciones con las asignaciones del mando para cada jugador
};

// Posiciones dentro de un rectangulo
struct Zone
{
	SDL_Rect rect;		 // Rectangulo que define la zona
	int center_x;		 // Anclaje al 50% del eje X
	int first_quarter_x; // Anclaje al 25% del eje X
	int third_quarter_x; // Anclaje al 75% del eje X
	int center_y;		 // Anclaje al 50% del eje Y
	int first_quarter_y; // Anclaje al 25% del eje Y
	int third_quarter_y; // Anclaje al 75% del eje X
};

// param.game
struct ParamGame
{
	int width;		// Ancho de la resolucion nativa del juego
	int height;		// Alto de la resolucion nativa del juego
	int item_size;	// Tamaño de los items del juego
	Zone play_area; // Rectangulo con la posición de la zona de juego
	Zone game_area; // Rectangulo con las dimensiones del juego
};

// param.fade
struct ParamFade
{
	int num_squares_width;	  // Cantidad total de cuadraditos en horizontal para el FadeType::RANDOM_SQUARE
	int num_squares_height;	  // Cantidad total de cuadraditos en vertical para el FadeType::RANDOM_SQUARE
	int random_squares_delay; // Duración entre cada pintado de cuadrados
	int random_squares_mult;  // Cantidad de cuadrados que se pintaran cada vez
	int post_duration;		  // Duración final del fade
	int venetian_size;		  // Altura de los rectangulos para FadeType::VENETIAN
};

// param.title
struct ParamTitle
{
	int press_start_position;	 // Posición del texto para empezar a jugar
	int title_duration;			 // Tiempo de inactividad del titulo
	int arcade_edition_position; // Posición del bitmap
	int title_c_c_position;		 // Posición del bitmap
};

// param.background
struct ParamBackground
{
	Color attenuate_color;
	int attenuate_alpha;
};

// Estructura para guardar los parametros de un globo
struct ParamBalloon
{
	float grav; // Aceleración en el eje Y. Modifica la velocidad
	float vel;	// Velocidad inicial que tienen al rebotar contra el suelo
};

// Estructura para almacenar todos los parámetros del juego
struct Param
{
	ParamGame game;											 // Parametros relacionados con el juego
	ParamFade fade;											 // Parametros para ajustar el fade
	SDL_Rect scoreboard;									 // Posición y tamaño del marcador
	ParamTitle title;										 // Parametros con ajustes para la sección Title
	ParamBackground background;								 // Parametros que afectan a la clase Background
	ParamBalloon balloon_1, balloon_2, balloon_3, balloon_4; // Parametros de velocidad y gravedad de cada tipo de globo
};

// Estructura para almacenar ficheros de sonido y su nombre
struct SoundFile
{
	std::string name; // Nombre del sonido
	JA_Sound_t *file; // Fichero con el sonido
};

// Estructura para almacenar ficheros musicales y su nombre
struct MusicFile
{
	std::string name; // Nombre de la musica
	JA_Music_t *file; // Fichero con la música
};

// Calcula el cuadrado de la distancia entre dos puntos
double distanceSquared(int x1, int y1, int x2, int y2);

// Detector de colisiones entre dos circulos
bool checkCollision(Circle &a, Circle &b);

// Detector de colisiones entre un circulo y un rectangulo
bool checkCollision(Circle &a, SDL_Rect &b);

// Detector de colisiones entre un dos rectangulos
bool checkCollision(SDL_Rect &a, SDL_Rect &b);

// Detector de colisiones entre un punto y un rectangulo
bool checkCollision(SDL_Point &p, SDL_Rect &r);

// Convierte una cadena en un valor booleano
bool stringToBool(std::string str);

// Convierte un valor booleano en una cadena
std::string boolToString(bool value);

// Convierte un valor booleano en una cadena "on" o "off"
std::string boolToOnOff(bool value);

// Convierte una cadena a minusculas
std::string toLower(std::string str);

// Obtiene el fichero de sonido a partir de un nombre
JA_Sound_t *getSound(std::vector<SoundFile> sounds, std::string name);

// Obtiene el fichero de música a partir de un nombre
JA_Music_t *getMusic(std::vector<MusicFile> music, std::string name);

// Ordena las entradas de la tabla de records
HiScoreEntry sortHiScoreTable(HiScoreEntry entry1, HiScoreEntry entry2);

// Dibuja un circulo
void DrawCircle(SDL_Renderer *renderer, int32_t centerX, int32_t centerY, int32_t radius);

// Aclara el color
Color lightenColor(Color color, int amount);

// Oscurece el color
Color DarkenColor(Color color, int amount);

// Quita los espacioes en un string
std::string trim(const std::string &str);

// Función de suavizado
double easeOutQuint(double t);

// Función de suavizado
double easeInOutSine(double t);

// Colores
extern const Color bg_color;
extern const Color no_color;
extern const Color shdw_txt_color;
extern const Color separator_color;
extern const Color scoreboard_color;
extern const Color difficulty_easy_color;
extern const Color difficulty_normal_color;
extern const Color difficulty_hard_color;
extern const Color flash_color;
extern const Color fade_color;
extern const Color orange_color;