#pragma once

#include <SDL3/SDL.h>

#include <algorithm>
#include <string>  // Para string, basic_string
#include <utility>

#include "core/rendering/screen.hpp"  // Para Screen::Filter
#include "utils/defines.hpp"          // Para WINDOW_CAPTION
#include "utils/utils.hpp"            // Para Color, Palette

// --- Namespace Options: gestión de configuración y opciones del juego ---
namespace Options {
// Tipos de control de teclado
/*
enum class ControlScheme {
    CURSOR,
    OPQA,
    WASD
};
*/

}  // namespace Options

// Incluir constantes por defecto después de declarar los enums
#include "game/defaults.hpp"

namespace Options {

// Estructura para las opciones de las notificaciones
struct Notification {
        bool sound{GameDefaults::NOTIFICATION_SOUND};   // Indica si las notificaciones suenan
        Uint8 color{GameDefaults::NOTIFICATION_COLOR};  // Color de las notificaciones

        // Constructor por defecto
        Notification() = default;

        // Constructor
        Notification(bool s, Uint8 c)
            : sound(s),
              color(c) {}
};

// Estructura para las opciones de control de teclado
struct ControlScheme {
        SDL_Scancode key_left{SDL_SCANCODE_LEFT};    // Tecla para mover a la izquierda
        SDL_Scancode key_right{SDL_SCANCODE_RIGHT};  // Tecla para mover a la derecha
        SDL_Scancode key_jump{SDL_SCANCODE_UP};      // Tecla para saltar

        // Constructor por defecto
        ControlScheme() = default;

        // Constructor
        ControlScheme(SDL_Scancode left, SDL_Scancode right, SDL_Scancode jump)
            : key_left(left),
              key_right(right),
              key_jump(jump) {}
};

// Estructura para las opciones de control del gamepad/joystick
// Los valores pueden ser:
// - 0-20+: Botones SDL_GamepadButton (DPAD, face buttons, shoulders, etc.)
// - 100: L2 trigger
// - 101: R2 trigger
// - 200: Left stick X axis (negativo = izquierda)
// - 201: Left stick X axis (positivo = derecha)
struct GamepadControlScheme {
        int button_left{static_cast<int>(SDL_GAMEPAD_BUTTON_DPAD_LEFT)};    // Botón para mover a la izquierda (por defecto: DPAD_LEFT)
        int button_right{static_cast<int>(SDL_GAMEPAD_BUTTON_DPAD_RIGHT)};  // Botón para mover a la derecha (por defecto: DPAD_RIGHT)
        int button_jump{static_cast<int>(SDL_GAMEPAD_BUTTON_WEST)};         // Botón para saltar (por defecto: WEST/X button)

        // Constructor por defecto
        GamepadControlScheme() = default;

        // Constructor
        GamepadControlScheme(int left, int right, int jump)
            : button_left(left),
              button_right(right),
              button_jump(jump) {}
};

// Estructura para albergar trucos
struct Cheat {
        enum class State : bool {
            DISABLED = false,
            ENABLED = true
        };

        State infinite_lives{State::DISABLED};  // Indica si el jugador dispone de vidas infinitas
        State invincible{State::DISABLED};      // Indica si el jugador puede morir
        State jail_is_open{State::DISABLED};    // Indica si la Jail está abierta
        State alternate_skin{State::DISABLED};  // Indica si se usa una skin diferente para el jugador

        // Constructor por defecto
        Cheat() = default;

        // Constructor
        Cheat(State inf_lives, State is_invincible, State jail_enabled, State alt_skin)
            : infinite_lives(inf_lives),
              invincible(is_invincible),
              jail_is_open(jail_enabled),
              alternate_skin(alt_skin) {}

        // Método para comprobar si alguno de los tres primeros trucos está activo
        [[nodiscard]] auto enabled() const -> bool {
            return infinite_lives == State::ENABLED ||
                invincible == State::ENABLED ||
                jail_is_open == State::ENABLED;
        }
};

// Estructura para almacenar estadísticas
struct Stats {
        int rooms{0};                 // Cantidad de habitaciones visitadas
        int items{0};                 // Cantidad de items obtenidos
        std::string worst_nightmare;  // Habitación con más muertes acumuladas

        // Constructor por defecto
        Stats() = default;

        // Constructor
        Stats(int room_count, int item_count, std::string worst_nightmare_room)
            : rooms(room_count),
              items(item_count),
              worst_nightmare(std::move(worst_nightmare_room)) {}
};

// Estructura con opciones de la ventana
struct Window {
        std::string caption{WINDOW_CAPTION};      // Texto que aparece en la barra de título de la ventana
        int zoom{GameDefaults::WINDOW_ZOOM};      // Zoom de la ventana
        int max_zoom{GameDefaults::WINDOW_ZOOM};  // Máximo tamaño de zoom para la ventana

        // Constructor por defecto
        Window() = default;

        // Constructor
        Window(int window_zoom, int maximum_zoom)
            : caption(WINDOW_CAPTION),
              zoom(window_zoom),
              max_zoom(maximum_zoom) {}
};

// Estructura para gestionar el borde de la pantalla
struct Border {
        bool enabled{GameDefaults::BORDER_ENABLED};  // Indica si se ha de mostrar el borde
        float width{GameDefaults::BORDER_WIDTH};     // Ancho del borde
        float height{GameDefaults::BORDER_HEIGHT};   // Alto del borde

        // Constructor por defecto
        Border() = default;

        // Constructor
        Border(bool is_enabled, float border_width, float border_height)
            : enabled(is_enabled),
              width(border_width),
              height(border_height) {}
};

// Estructura para las opciones de video
struct Video {
        bool fullscreen{GameDefaults::VIDEO_MODE};              // Contiene el valor del modo de pantalla completa
        Screen::Filter filter{GameDefaults::VIDEO_FILTER};      // Filtro usado para el escalado de la imagen
        bool vertical_sync{GameDefaults::VIDEO_VERTICAL_SYNC};  // Indica si se quiere usar vsync o no
        bool shaders{GameDefaults::VIDEO_SHADERS};              // Indica si se van a usar shaders o no
        bool integer_scale{GameDefaults::VIDEO_INTEGER_SCALE};  // Indica si el escalado de la imagen ha de ser entero en el modo a pantalla completa
        bool keep_aspect{GameDefaults::VIDEO_KEEP_ASPECT};      // Indica si se ha de mantener la relación de aspecto al poner el modo a pantalla completa
        Border border;                                          // Borde de la pantalla
        std::string palette{GameDefaults::PALETTE_NAME};        // Paleta de colores a usar en el juego
        std::string info;                                       // Información sobre el modo de vídeo

        // Constructor por defecto
        Video() = default;

        // Constructor
        Video(bool is_fullscreen, Screen::Filter screen_filter, bool vsync, bool use_shaders, bool int_scale, bool keep_aspect_ratio, Border video_border, std::string palette_name)
            : fullscreen(is_fullscreen),
              filter(screen_filter),
              vertical_sync(vsync),
              shaders(use_shaders),
              integer_scale(int_scale),
              keep_aspect(keep_aspect_ratio),
              border(video_border),
              palette(std::move(palette_name)) {}
};

// Estructura para las opciones de musica
struct Music {
        bool enabled{GameDefaults::MUSIC_ENABLED};  // Indica si la música suena o no
        float volume{GameDefaults::MUSIC_VOLUME};   // Volumen al que suena la música

        // Constructor por defecto
        Music() = default;

        // Constructor con parámetros
        Music(bool is_enabled, float volume_percent)
            : enabled(is_enabled),
              volume(volume_percent) {}
};

// Estructura para las opciones de sonido
struct Sound {
        bool enabled{GameDefaults::SOUND_ENABLED};  // Indica si los sonidos suenan o no
        float volume{GameDefaults::SOUND_VOLUME};   // Volumen al que suenan los sonidos (0 a 128 internamente)

        // Constructor por defecto
        Sound() = default;

        // Constructor con parámetros
        Sound(bool is_enabled, float volume_percent)
            : enabled(is_enabled),
              volume(volume_percent) {}
};

// Estructura para las opciones de audio
struct Audio {
        Music music;                                // Opciones para la música
        Sound sound;                                // Opciones para los efectos de sonido
        bool enabled{GameDefaults::AUDIO_ENABLED};  // Indica si el audio está activo o no
        float volume{GameDefaults::AUDIO_VOLUME};   // Volumen al que suenan el audio (0-128 internamente)

        // Constructor por defecto
        Audio() = default;

        // Constructor
        Audio(Music audio_music, Sound audio_sound, bool is_enabled, float volume_percent)
            : music(audio_music),
              sound(audio_sound),
              enabled(is_enabled),
              volume(volume_percent) {}
};

// Estructura para las opciones de juego
struct Game {
        float width{GameDefaults::GAME_WIDTH};    // Ancho de la resolucion del juego
        float height{GameDefaults::GAME_HEIGHT};  // Alto de la resolucion del juego

        // Constructor por defecto
        Game() = default;

        // Constructor
        Game(float game_width, float game_height)
            : width(game_width),
              height(game_height) {}
};

// --- Variables globales (inline C++17+) ---
inline std::string version{};                    // Versión del fichero de configuración. Sirve para saber si las opciones son compatibles
inline bool console{false};                      // Indica si ha de mostrar información por la consola de texto
inline Cheat cheats{};                           // Contiene trucos y ventajas para el juego
inline Game game{};                              // Opciones de juego
inline Video video{};                            // Opciones de video
inline Stats stats{};                            // Datos con las estadisticas de juego
inline Notification notifications{};             // Opciones relativas a las notificaciones;
inline Window window{};                          // Opciones relativas a la ventana
inline Audio audio{};                            // Opciones relativas al audio
inline ControlScheme controls{};                 // Teclas usadas para jugar
inline GamepadControlScheme gamepad_controls{};  // Botones del gamepad usados para jugar

// Ruta completa del fichero de configuración (establecida mediante setConfigFile)
inline std::string config_file_path_{};

// --- Funciones ---
void init();                                    // Crea e inicializa las opciones del programa
void setConfigFile(const std::string& path);    // Establece la ruta del fichero de configuración
auto loadFromFile() -> bool;                    // Carga las opciones desde el fichero configurado
auto saveToFile() -> bool;                      // Guarda las opciones al fichero configurado

}  // namespace Options