#pragma once

#include <SDL3/SDL_gamepad.h>	  // Para SDL_GamepadButton
#include <SDL3/SDL_surface.h>	  // Para SDL_ScaleMode
#include <string>				  // Para std::string
#include <vector>				  // Para std::vector
#include "input.h"				  // Para InputAction, InputDeviceToUse
#include "manage_hiscore_table.h" // Para HiScoreEntry

namespace lang
{
	enum class Code : int;
}

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

// --- Opciones de la ventana ---
struct WindowOptions
{
	std::string caption; // Texto que aparece en la barra de título de la ventana
	int zoom = 1;		 // Valor por el que se multiplica el tamaño de la ventana
	int max_zoom = 1;	 // Tamaño máximo para que la ventana no sea mayor que la pantalla
};

// --- Opciones de vídeo ---
struct VideoOptions
{
	SDL_ScaleMode scale_mode; // Filtro usado para el escalado de la imagen
	bool fullscreen;		  // Indica si se usa pantalla completa
	bool v_sync;			  // Indica si se usa vsync
	bool integer_scale;		  // Indica si se usa escalado entero
	bool shaders;			  // Indica si se usan shaders para los filtros de vídeo
	std::string info;		  // Información sobre el modo de vídeo
};

// --- Opciones de música ---
struct MusicOptions
{
	bool enabled; // Indica si la música suena o no
	int volume;	  // Volumen de la música
};

// --- Opciones de sonido ---
struct SoundOptions
{
	bool enabled; // Indica si los sonidos suenan o no
	int volume;	  // Volumen de los sonidos
};

// --- Opciones de audio ---
struct AudioOptions
{
	MusicOptions music; // Opciones para la música
	SoundOptions sound; // Opciones para los efectos de sonido
	bool enabled;		// Indica si el audio está activo o no
	int volume;			// Volumen general del audio
};

// --- Opciones del juego ---
struct GameOptions
{
	GameDifficulty difficulty;						 // Dificultad del juego
	lang::Code language;							 // Idioma usado en el juego
	bool autofire;									 // Indicador de autofire
	std::vector<HiScoreEntry> hi_score_table;		 // Tabla de mejores puntuaciones
	std::vector<int> last_hi_score_entry = {-1, -1}; // Últimas posiciones de entrada en la tabla

	// Reinicia las últimas entradas de puntuación
	void clear_last_hi_score_entries()
	{
		last_hi_score_entry[0] = -1;
		last_hi_score_entry[1] = -1;
	}
};

// --- Opciones de mando ---
struct GamepadOptions
{
	int index;								// Índice en el vector de mandos
	int player_id;							// Jugador asociado al mando
	InputDeviceToUse type;					// Indica si se usará teclado, mando o ambos
	std::string name;						// Nombre del dispositivo
	bool plugged;							// Indica si el mando está conectado
	std::vector<InputAction> inputs;		// Listado de acciones asignadas
	std::vector<SDL_GamepadButton> buttons; // Listado de botones asignados a cada acción

	// Constructor por defecto
	GamepadOptions()
		: index(-1), player_id(-1), type(InputDeviceToUse::CONTROLLER), name(""), plugged(false),
		  inputs{InputAction::FIRE_LEFT, InputAction::FIRE_CENTER, InputAction::FIRE_RIGHT, InputAction::START, InputAction::SERVICE},
		  buttons{SDL_GAMEPAD_BUTTON_WEST, SDL_GAMEPAD_BUTTON_NORTH, SDL_GAMEPAD_BUTTON_EAST, SDL_GAMEPAD_BUTTON_START, SDL_GAMEPAD_BUTTON_BACK} {}
};

// --- Opciones generales del programa ---
struct Options
{
	WindowOptions window;					 // Opciones de la ventana
	GameOptions game;						 // Opciones del juego
	VideoOptions video;						 // Opciones de vídeo
	AudioOptions audio;						 // Opciones de audio
	std::vector<GamepadOptions> controllers; // Opciones de mando para cada jugador
};

// --- Variables globales ---
extern Options options;

// --- Funciones de configuración ---
void initOptions();							 // Inicializa las opciones del programa
bool loadOptionsFile(std::string file_path); // Carga el fichero de configuración
bool saveOptionsFile(std::string file_path); // Guarda el fichero de configuración
void setKeyboardToPlayer(int player_id);	 // Asigna el teclado al jugador
void swapOptionsKeyboard();					 // Intercambia el teclado de jugador
void swapOptionsControllers();				 // Intercambia los jugadores asignados a los dos primeros mandos
int getPlayerWhoUsesKeyboard();				 // Averigua quién está usando el teclado