#pragma once

#include <SDL3/SDL.h>

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

#include "core/rendering/screen.hpp"  // Para ScreenFilter
#include "utils/utils.hpp"            // Para Color, Palette

// --- Namespace Options: gestión de configuración y opciones del juego ---
namespace Options {

// =============================================================================
// VOLUME HELPERS - Conversión de volumen 0-100 a 0-128
// =============================================================================
namespace VolumeHelpers {
constexpr auto convertVolume(int volume_percent) -> int {
    return (volume_percent * 128) / 100;
}
}  // namespace VolumeHelpers

// 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;   // Indica si las notificaciones suenan
        Uint8 color;  // Color de las notificaciones

        // Constructor por defecto
        Notification()
            : sound(GameDefaults::NOTIFICATION_SOUND),
              color(GameDefaults::NOTIFICATION_COLOR) {}

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

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

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

        // Constructor por defecto
        Cheat()
            : infinite_lives(State::DISABLED),
              invincible(State::DISABLED),
              jail_is_open(State::DISABLED),
              alternate_skin(State::DISABLED) {}

        // 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;                    // Cantidad de habitaciones visitadas
        int items;                    // Cantidad de items obtenidos
        std::string worst_nightmare;  // Habitación con más muertes acumuladas

        // Constructor por defecto
        Stats()
            : rooms(0),
              items(0) {}

        // 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;  // Texto que aparece en la barra de título de la ventana
        int zoom;             // Zoom de la ventana
        int max_zoom;         // Máximo tamaño de zoom para la ventana

        // Constructor por defecto
        Window()
            : caption("JailDoctor's Dilemma"),
              zoom(GameDefaults::WINDOW_ZOOM),
              max_zoom(GameDefaults::WINDOW_ZOOM) {}

        // Constructor
        Window(int window_zoom, int maximum_zoom)
            : caption("JailDoctor's Dilemma"),
              zoom(window_zoom),
              max_zoom(maximum_zoom) {}
};

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

        // Constructor por defecto
        Border()
            : enabled(GameDefaults::BORDER_ENABLED),
              width(GameDefaults::BORDER_WIDTH),
              height(GameDefaults::BORDER_HEIGHT) {}

        // 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;      // Contiene el valor del modo de pantalla completa
        ScreenFilter filter;  // Filtro usado para el escalado de la imagen
        bool vertical_sync;   // Indica si se quiere usar vsync o no
        bool shaders;         // Indica si se van a usar shaders o no
        bool integer_scale;   // Indica si el escalado de la imagen ha de ser entero en el modo a pantalla completa
        bool 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;  // Paleta de colores a usar en el juego
        std::string info;     // Información sobre el modo de vídeo

        // Constructor por defecto
        Video()
            : fullscreen(GameDefaults::VIDEO_MODE),
              filter(GameDefaults::VIDEO_FILTER),
              vertical_sync(GameDefaults::VIDEO_VERTICAL_SYNC),
              shaders(GameDefaults::VIDEO_SHADERS),
              integer_scale(GameDefaults::VIDEO_INTEGER_SCALE),
              keep_aspect(GameDefaults::VIDEO_KEEP_ASPECT),

              palette(GameDefaults::PALETTE_NAME) {}

        // Constructor
        Video(bool is_fullscreen, ScreenFilter 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;  // Indica si la música suena o no
        int volume;    // Volumen al que suena la música (0 a 128 internamente)

        // Constructor por defecto
        Music()
            : enabled(GameDefaults::MUSIC_ENABLED),
              volume(VolumeHelpers::convertVolume(GameDefaults::MUSIC_VOLUME)) {}

        // Constructor con parámetros
        Music(bool is_enabled, int volume_percent)
            : enabled(is_enabled),
              volume(VolumeHelpers::convertVolume(volume_percent)) {}

        // Método para establecer el volumen
        void setVolume(int volume_percent) {
            volume_percent = std::clamp(volume_percent, 0, 100);
            volume = VolumeHelpers::convertVolume(volume_percent);
        }
};

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

        // Constructor por defecto
        Sound()
            : enabled(GameDefaults::SOUND_ENABLED),
              volume(VolumeHelpers::convertVolume(GameDefaults::SOUND_VOLUME)) {}

        // Constructor con parámetros
        Sound(bool is_enabled, int volume_percent)
            : enabled(is_enabled),
              volume(VolumeHelpers::convertVolume(volume_percent)) {}

        // Método para establecer el volumen
        void setVolume(int volume_percent) {
            volume_percent = std::clamp(volume_percent, 0, 100);
            volume = VolumeHelpers::convertVolume(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;  // Indica si el audio está activo o no
        int volume;    // Volumen al que suenan el audio (0-128 internamente)

        // Constructor por defecto
        Audio()
            : enabled(GameDefaults::AUDIO_ENABLED),
              volume(VolumeHelpers::convertVolume(GameDefaults::AUDIO_VOLUME)) {}

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

// Estructura para las opciones de juego
struct Game {
        float width;   // Ancho de la resolucion del juego
        float height;  // Alto de la resolucion del juego

        // Constructor por defecto
        Game()
            : width(GameDefaults::GAME_WIDTH),
              height(GameDefaults::GAME_HEIGHT) {}

        // 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 keys{GameDefaults::CONTROL_SCHEME};  // Teclas usadas para jugar

// --- Funciones ---
void init();                                      // Crea e inicializa las opciones del programa
auto loadFromFile(const std::string& file_path) -> bool;  // Carga las opciones desde un fichero
auto saveToFile(const std::string& file_path) -> bool;    // Guarda las opciones a un fichero

}  // namespace Options