#pragma once

#include <SDL3/SDL.h>

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

#include "core/rendering/screen.hpp"          // Para Screen::Filter
#include "core/rendering/shader_backend.hpp"  // Para Rendering::ShaderType
#include "game/defaults.hpp"
#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 {

    // Estructura para las opciones de control de teclado
    struct KeyboardControls {
        SDL_Scancode key_left{Defaults::Controls::KEY_LEFT};    // Tecla para mover a la izquierda
        SDL_Scancode key_right{Defaults::Controls::KEY_RIGHT};  // Tecla para mover a la derecha
        SDL_Scancode key_jump{Defaults::Controls::KEY_JUMP};    // Tecla para saltar
    };

    // Estructura para las opciones de control del gamepad/joystick
    struct GamepadControls {
        int button_left{Defaults::Controls::GAMEPAD_BUTTON_LEFT};    // Botón para mover a la izquierda (por defecto: DPAD_LEFT)
        int button_right{Defaults::Controls::GAMEPAD_BUTTON_RIGHT};  // Botón para mover a la derecha (por defecto: DPAD_RIGHT)
        int button_jump{Defaults::Controls::GAMEPAD_BUTTON_JUMP};    // Botón para saltar (por defecto: WEST/X button)
    };

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

        State infinite_lives{Defaults::Cheat::INFINITE_LIVES ? State::ENABLED : State::DISABLED};  // Indica si el jugador dispone de vidas infinitas
        State invincible{Defaults::Cheat::INVINCIBLE ? State::ENABLED : State::DISABLED};          // Indica si el jugador puede morir

        // Método para comprobar si algún truco está activo
        [[nodiscard]] auto enabled() const -> bool {
            return infinite_lives == State::ENABLED || invincible == State::ENABLED;
        }
    };

    // Estructura para almacenar estadísticas
    struct Stats {
        int rooms{Defaults::Stats::ROOMS};  // Cantidad de habitaciones visitadas
        int items{Defaults::Stats::ITEMS};  // Cantidad de items obtenidos
    };

    // Estructura para el modo kiosko
    struct Kiosk {
        bool enabled{Defaults::Kiosk::ENABLED};                // Indica si el modo kiosko está activo
        std::string text{Defaults::Kiosk::TEXT};               // Texto a mostrar en el modo kiosko
        bool infinite_lives{Defaults::Kiosk::INFINITE_LIVES};  // Indica si el jugador tiene vidas infinitas en modo kiosko
    };

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

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

    // Estructura para las opciones de GPU
    struct GPU {
        bool acceleration{Defaults::Video::GPU_ACCELERATION};  // Usar aceleración GPU; false = path SDL fallback directo
        std::string preferred_driver;                          // Driver GPU preferido; vacío = auto. Aplica en el próximo arranque.
    };

    // Estructura para las opciones de supersampling
    struct Supersampling {
        bool enabled{Defaults::Video::SUPERSAMPLING};          // Indica si el supersampling 3× está activo
        bool linear_upscale{Defaults::Video::LINEAR_UPSCALE};  // Upscale LINEAR (true) o NEAREST (false)
        int downscale_algo{Defaults::Video::DOWNSCALE_ALGO};   // 0=bilinear, 1=Lanczos2, 2=Lanczos3
    };

    // Estructura para las opciones de shader (dentro de Video)
    struct ShaderConfig {
        bool enabled{Defaults::Video::SHADER_ENABLED};                        // Indica si se usan shaders de post-procesado
        Rendering::ShaderType current_shader{Rendering::ShaderType::POSTFX};  // Shader de post-procesado activo
        std::string current_postfx_preset_name;                               // Nombre del preset PostFX leído del config
        std::string current_crtpi_preset_name;                                // Nombre del preset CrtPi leído del config
        int current_postfx_preset{0};                                         // Índice resuelto del preset PostFX
        int current_crtpi_preset{0};                                          // Índice resuelto del preset CrtPi
    };

    // Estructura para las opciones de video
    struct Video {
        bool fullscreen{Defaults::Video::FULLSCREEN};             // Contiene el valor del modo de pantalla completa
        Screen::Filter filter{Defaults::Video::FILTER};           // Filtro usado para el escalado de la imagen
        bool vertical_sync{Defaults::Video::VERTICAL_SYNC};       // Indica si se quiere usar vsync o no
        bool integer_scale{Defaults::Video::INTEGER_SCALE};       // Indica si el escalado de la imagen ha de ser entero en el modo a pantalla completa
        bool keep_aspect{Defaults::Video::KEEP_ASPECT};           // Indica si se ha de mantener la relación de aspecto al poner el modo a pantalla completa
        std::string palette{Defaults::Video::PALETTE_NAME};       // Paleta de colores a usar en el juego
        std::string palette_sort{Defaults::Video::PALETTE_SORT};  // Modo de ordenación de la paleta (original/optimal/reference)
        std::string info;                                         // Información sobre el modo de vídeo
        Border border{};                                          // Borde de la pantalla
        GPU gpu{};                                                // Opciones de aceleración GPU
        Supersampling supersampling{};                            // Opciones de supersampling
        ShaderConfig shader{};                                    // Opciones de shader post-procesado
    };

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

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

    // 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{Defaults::Audio::ENABLED};  // Indica si el audio está activo o no
        float volume{Defaults::Audio::VOLUME};   // Volumen al que suenan el audio (0-128 internamente)
    };

    // Estructura para las opciones de juego
    struct Game {
        float width{Defaults::Canvas::WIDTH};    // Ancho de la resolucion del juego
        float height{Defaults::Canvas::HEIGHT};  // Alto de la resolucion del juego
    };

    // Estructura para las opciones de la pantalla de carga de recursos
    struct Loading {
        bool show_progress{Defaults::Loading::SHOW_PROGRESS};  // Mostrar barra de progreso al cargar recursos
    };

    // Estructura para las opciones visuales de la consola en pantalla
    struct Console {
        bool transparent{Defaults::Console::TRANSPARENT};     // true = sin fondo, false = sólida
        int bg_color{Defaults::Console::BG_COLOR};            // Índice de paleta del fondo (sólo si !transparent)
        int msg_color{Defaults::Console::MSG_COLOR};          // Índice de paleta de las líneas de mensaje
        int prompt_color{Defaults::Console::PROMPT_COLOR};    // Índice de paleta del prompt y del borde
        int command_color{Defaults::Console::COMMAND_COLOR};  // Índice de paleta del texto escrito por el usuario
    };

    // Estructura para un preset de PostFX
    struct PostFXPreset {
        std::string name;       // Nombre del preset
        float vignette{0.6F};   // Intensidad de la viñeta (0.0 = ninguna, 1.0 = máxima)
        float scanlines{0.7F};  // Intensidad de las scanlines (0.0 = desactivadas, 1.0 = máximas)
        float chroma{0.15F};    // Intensidad de la aberración cromática (0.0 = ninguna, 1.0 = máxima)
        float mask{0.0F};       // Intensidad de la máscara de fósforo RGB (0.0 = desactivada, 1.0 = máxima)
        float gamma{0.0F};      // Corrección gamma input 2.4 / output 2.2 (0.0 = off, 1.0 = plena)
        float curvature{0.0F};  // Distorsión barrel CRT (0.0 = plana, 1.0 = máxima curvatura)
        float bleeding{0.0F};   // Sangrado de color NTSC horizontal Y/C (0.0 = off, 1.0 = máximo)
        float flicker{0.0F};    // Parpadeo de fósforo CRT ~50 Hz (0.0 = off, 1.0 = máximo)
    };

    // Estructura para un preset del shader CRT-Pi
    struct CrtPiPreset {
        std::string name;
        float scanline_weight{6.0F};           // Ajuste gaussiano (mayor = scanlines más estrechas)
        float scanline_gap_brightness{0.12F};  // Brillo mínimo en las ranuras entre scanlines
        float bloom_factor{3.5F};              // Factor de brillo para zonas iluminadas
        float input_gamma{2.4F};               // Gamma de entrada (linealización)
        float output_gamma{2.2F};              // Gamma de salida (codificación)
        float mask_brightness{0.80F};          // Brillo sub-píxeles en la máscara de fósforo
        float curvature_x{0.05F};              // Distorsión barrel eje X
        float curvature_y{0.10F};              // Distorsión barrel eje Y
        int mask_type{2};                      // 0=ninguna, 1=verde/magenta, 2=RGB fósforo
        bool enable_scanlines{true};           // Activar efecto de scanlines
        bool enable_multisample{true};         // Antialiasing analítico de scanlines
        bool enable_gamma{true};               // Corrección gamma
        bool enable_curvature{false};          // Distorsión barrel CRT
        bool enable_sharper{false};            // Submuestreo más nítido (modo SHARPER)
    };

    // --- Variables globales ---
    inline std::string version{};                 // Versión del fichero de configuración. Sirve para saber si las opciones son compatibles
    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 Window window{};                       // Opciones relativas a la ventana
    inline Audio audio{};                         // Opciones relativas al audio
    inline KeyboardControls keyboard_controls{};  // Teclas usadas para jugar
    inline GamepadControls gamepad_controls{};    // Botones del gamepad usados para jugar
    inline Kiosk kiosk{};                         // Opciones del modo kiosko
    inline Console console{};                     // Opciones visuales de la consola en pantalla
    inline Loading loading{};                     // Opciones de la pantalla de carga de recursos

    // Idioma del juego (establecido al inicio, sin cambio en caliente)
    inline std::string language{Defaults::Localization::LANGUAGE};

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

    // --- Variables PostFX ---
    inline std::vector<PostFXPreset> postfx_presets{};  // Lista de presets de PostFX
    inline std::string postfx_file_path{};              // Ruta del fichero postfx.yaml

    // --- Variables CrtPi ---
    inline std::vector<CrtPiPreset> crtpi_presets{};  // Lista de presets del shader CRT-Pi
    inline std::string crtpi_file_path{};             // Ruta del fichero crtpi.yaml

    // --- Funciones públicas ---
    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
    void setPostFXFile(const std::string& path);  // Establece la ruta del fichero de PostFX
    auto loadPostFXFromFile() -> bool;            // Carga los presets de PostFX desde el fichero
    auto savePostFXToFile() -> bool;              // Guarda los presets de PostFX por defecto
    void setCrtPiFile(const std::string& path);   // Establece la ruta del fichero de CrtPi
    auto loadCrtPiFromFile() -> bool;             // Carga los presets de CrtPi desde el fichero (crea defaults si no existe)

    void resolvePostFXPresetName();  // Resuelve el nombre del preset PostFX a índice
    void resolveCrtPiPresetName();   // Resuelve el nombre del preset CrtPi a índice

}  // namespace Options