#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;
}

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

	// --- Estructura que representa un nivel de dificultad
	struct Difficulty
	{
		DifficultyCode code; // Código que identifica la dificultad
		std::string name;	 // Nombre que identifica la dificultad

		Difficulty(DifficultyCode c, const std::string &n)
			: code(c), name(n) {}
	};

	// --- Opciones de la ventana ---
	struct WindowOptions
	{
		std::string caption; // Texto que aparece en la barra de título de la ventana
		int size = 1;		 // Valor por el que se multiplica el tamaño de la ventana
		int max_size = 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 de configuracion ---
	struct SettingsOptions
	{
		DifficultyCode difficulty;						 // Dificultad del juego
		Lang::Code language;							 // Idioma usado en el juego
		bool autofire;									 // Indicador de autofire
		bool shutdown_enabled;							 // Especifica si se puede apagar el sistema
		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
		std::string config_file;						 // Ruta al fichero donde guardar la configuracion y las opciones del juego

		// Reinicia las últimas entradas de puntuación
		void clearLastHiScoreEntries()
		{
			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 pendientes de aplicar ---
	struct PendingChanges
	{
		Lang::Code new_language;		  // Idioma en espera de aplicar
		DifficultyCode new_difficulty;	  // Dificultad en espera de aplicar
		bool has_pending_changes = false; // Indica si hay cambios pendientes
	};

	// --- Variables globales ---
	extern WindowOptions window;					// Opciones de la ventana
	extern SettingsOptions settings;				// Opciones del juego
	extern VideoOptions video;						// Opciones de vídeo
	extern AudioOptions audio;						// Opciones de audio
	extern std::vector<GamepadOptions> controllers; // Opciones de mando para cada jugador
	extern PendingChanges pending_changes;			// Opciones que se aplican al cerrar
	extern std::vector<Difficulty> difficulties;

	// --- Funciones de configuración ---
	void init();							 // Inicializa las opciones del programa
	bool loadFromFile();					 // Carga el fichero de configuración
	bool saveToFile();						 // Guarda el fichero de configuración
	void setKeyboardToPlayer(int player_id); // Asigna el teclado al jugador
	void swapKeyboard();					 // Intercambia el teclado de jugador
	void swapControllers();					 // Intercambia los jugadores asignados a los dos primeros mandos
	int getPlayerWhoUsesKeyboard();			 // Averigua quién está usando el teclado
	void applyPendingChanges();				 // Aplica los cambios pendientes copiando los valores a sus variables
	void checkPendingChanges();
	DifficultyCode getDifficultyCodeFromName(const std::string& name);
	std::string getDifficultyNameFromCode(DifficultyCode code);
} // namespace Options