#include "game/options.hpp"

#include <algorithm>
#include <fstream>
#include <iostream>
#include <string>

#include "core/audio/audio.hpp"
#include "external/fkyaml_node.hpp"
#include "game/defaults.hpp"
#include "game/defines.hpp"

namespace Options {

    // Estableix la ruta del fitxer de configuració
    void setConfigFile(const std::string& path) {
        config_file_path = path;
    }

    void setDebugFile(const std::string& path) {
        debug_file_path = path;
    }

    auto saveDebugToFile() -> bool {
        std::ofstream file(debug_file_path);
        if (!file.is_open()) {
            std::cerr << "Error: Unable to open file " << debug_file_path << " for writing\n";
            return false;
        }

        std::cout << "Writing debug file: " << debug_file_path << '\n';

        file << "# Aventures En Egipte - Debug Configuration File\n";
        file << "#\n";
        file << "# Loaded only in debug builds. Override gameplay starting state for testing.\n";
        file << "\n";
        file << "game:\n";
        file << "  habitacio_inicial: " << game.habitacio_inicial << "\n";
        file << "  piramide_inicial: " << game.piramide_inicial << "\n";
        file << "  vides: " << game.vides << "\n";
        file << "  diamants_inicial: " << game.diamants_inicial << "\n";
        file << "  diners_inicial: " << game.diners_inicial << "\n";

        return true;
    }

    auto loadDebugFromFile() -> bool {
        std::ifstream file(debug_file_path);
        if (!file.good()) {
            std::cout << "Debug file not found, creating default: " << debug_file_path << '\n';
            return saveDebugToFile();
        }

        std::string content((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
        file.close();

        try {
            std::cout << "Reading debug file: " << debug_file_path << '\n';
            auto yaml = fkyaml::node::deserialize(content);
            if (yaml.contains("game")) {
                const auto& node = yaml["game"];
                if (node.contains("habitacio_inicial")) {
                    game.habitacio_inicial = node["habitacio_inicial"].get_value<int>();
                }
                if (node.contains("piramide_inicial")) {
                    game.piramide_inicial = node["piramide_inicial"].get_value<int>();
                }
                if (node.contains("vides")) {
                    game.vides = node["vides"].get_value<int>();
                }
                if (node.contains("diamants_inicial")) {
                    game.diamants_inicial = node["diamants_inicial"].get_value<int>();
                }
                if (node.contains("diners_inicial")) {
                    game.diners_inicial = node["diners_inicial"].get_value<int>();
                }
            }
            return true;
        } catch (const fkyaml::exception& e) {
            std::cerr << "Error parsing YAML debug: " << e.what() << '\n';
            return saveDebugToFile();
        }
    }

    // Delega tots els canvis de l'estat d'àudio al wrapper Audio. Es manté
    // com a punt d'entrada únic per als callsites legacy del menú; el cos
    // ja no toca jail_audio directament.
    void applyAudio() {
        if (::Audio::get() == nullptr) {
            return;
        }
        ::Audio::get()->enable(audio.enabled);
        ::Audio::get()->enableMusic(audio.music.enabled);
        ::Audio::get()->enableSound(audio.sound.enabled);
        ::Audio::get()->setMusicVolume(audio.music.volume);
        ::Audio::get()->setSoundVolume(audio.sound.volume);
    }

    // --- Funcions helper de càrrega ---

    static void loadAudioConfigFromYaml(const fkyaml::node& yaml) {
        if (!yaml.contains("audio")) {
            return;
        }
        const auto& node = yaml["audio"];

        if (node.contains("enabled")) {
            audio.enabled = node["enabled"].get_value<bool>();
        }

        if (node.contains("volume")) {
            audio.volume = node["volume"].get_value<float>();
        }

        if (node.contains("music")) {
            const auto& music = node["music"];
            if (music.contains("enabled")) {
                audio.music.enabled = music["enabled"].get_value<bool>();
            }
            if (music.contains("volume")) {
                audio.music.volume = music["volume"].get_value<float>();
            }
        }

        if (node.contains("sound")) {
            const auto& sound = node["sound"];
            if (sound.contains("enabled")) {
                audio.sound.enabled = sound["enabled"].get_value<bool>();
            }
            if (sound.contains("volume")) {
                audio.sound.volume = sound["volume"].get_value<float>();
            }
        }
    }

    static void loadVideoConfigFromYaml(const fkyaml::node& yaml) {
        if (!yaml.contains("video")) {
            return;
        }
        const auto& node = yaml["video"];

        if (node.contains("gpu_acceleration")) {
            video.gpu_acceleration = node["gpu_acceleration"].get_value<bool>();
        }
        if (node.contains("shader_enabled")) {
            video.shader_enabled = node["shader_enabled"].get_value<bool>();
        }
        if (node.contains("supersampling")) {
            video.supersampling = node["supersampling"].get_value<bool>();
        }
        if (node.contains("scaling_mode")) {
            auto s = node["scaling_mode"].get_value<std::string>();
            if (s == "disabled") {
                video.scaling_mode = ScalingMode::DISABLED;
            } else if (s == "stretch") {
                video.scaling_mode = ScalingMode::STRETCH;
            } else if (s == "letterbox") {
                video.scaling_mode = ScalingMode::LETTERBOX;
            } else if (s == "overscan") {
                video.scaling_mode = ScalingMode::OVERSCAN;
            } else {
                video.scaling_mode = ScalingMode::INTEGER;
            }
        }
        if (node.contains("vsync")) {
            video.vsync = node["vsync"].get_value<bool>();
        }
        if (node.contains("aspect_ratio_4_3")) {
            video.aspect_ratio_4_3 = node["aspect_ratio_4_3"].get_value<bool>();
        }
        if (node.contains("texture_filter")) {
            auto s = node["texture_filter"].get_value<std::string>();
            video.texture_filter = (s == "linear") ? TextureFilter::LINEAR : TextureFilter::NEAREST;
        }
        if (node.contains("downscale_algo")) {
            video.downscale_algo = node["downscale_algo"].get_value<int>();
        }
        if (node.contains("internal_resolution")) {
            video.internal_resolution = node["internal_resolution"].get_value<int>();
            video.internal_resolution = std::max(video.internal_resolution, 1);
        }
        if (node.contains("current_shader")) {
            video.current_shader = node["current_shader"].get_value<std::string>();
        }
        if (node.contains("current_postfx_preset")) {
            video.current_postfx_preset = node["current_postfx_preset"].get_value<std::string>();
        }
        if (node.contains("current_crtpi_preset")) {
            video.current_crtpi_preset = node["current_crtpi_preset"].get_value<std::string>();
        }
    }

    static void loadRenderInfoFromYaml(const fkyaml::node& yaml) {
        if (!yaml.contains("render_info")) {
            return;
        }
        const auto& node = yaml["render_info"];

        if (node.contains("position")) {
            auto pos = node["position"].get_value<std::string>();
            if (pos == "top") {
                render_info.position = RenderInfoPosition::TOP;
            } else if (pos == "bottom") {
                render_info.position = RenderInfoPosition::BOTTOM;
            } else {
                render_info.position = RenderInfoPosition::OFF;
            }
        }
        if (node.contains("show_time")) {
            render_info.show_time = node["show_time"].get_value<bool>();
        }
        if (node.contains("text_color")) {
            render_info.text_color = static_cast<Uint32>(node["text_color"].get_value<uint64_t>());
        }
        if (node.contains("shadow_color")) {
            render_info.shadow_color = static_cast<Uint32>(node["shadow_color"].get_value<uint64_t>());
        }
    }

    static void loadWindowConfigFromYaml(const fkyaml::node& yaml) {
        if (!yaml.contains("window")) {
            return;
        }
        const auto& node = yaml["window"];

        if (node.contains("zoom")) {
            window.zoom = node["zoom"].get_value<int>();
        }
        if (node.contains("fullscreen")) {
            window.fullscreen = node["fullscreen"].get_value<bool>();
        }
    }

    // Helper: carrega una SDL_Scancode des d'un string (nom SDL de la tecla).
    static void loadScancodeField(const fkyaml::node& node, const std::string& key, SDL_Scancode& target) {
        if (!node.contains(key)) {
            return;
        }
        auto name = node[key].get_value<std::string>();
        SDL_Scancode sc = SDL_GetScancodeFromName(name.c_str());
        if (sc != SDL_SCANCODE_UNKNOWN) {
            target = sc;
        }
    }

    static void loadControlsFromYaml(const fkyaml::node& yaml) {
        if (yaml.contains("controls")) {
            const auto& node = yaml["controls"];
            loadScancodeField(node, "up", keys_game.up);
            loadScancodeField(node, "down", keys_game.down);
            loadScancodeField(node, "left", keys_game.left);
            loadScancodeField(node, "right", keys_game.right);
        }
    }

    static void loadGameConfigFromYaml(const fkyaml::node& yaml) {
        if (!yaml.contains("game")) {
            return;
        }
        const auto& node = yaml["game"];

        if (node.contains("use_new_logo")) {
            game.use_new_logo = node["use_new_logo"].get_value<bool>();
        }
        if (node.contains("show_title_credits")) {
            game.show_title_credits = node["show_title_credits"].get_value<bool>();
        }
        if (node.contains("show_preload")) {
            game.show_preload = node["show_preload"].get_value<bool>();
        }
    }

    // Carrega les opcions des del fitxer configurat
    auto loadFromFile() -> bool {
        const std::string CONFIG_VERSION = Texts::VERSION;
        version = "";

        std::ifstream file(config_file_path);
        if (!file.good()) {
            std::cout << "Config file not found, creating default: " << config_file_path << '\n';
            saveToFile();
            return true;
        }

        std::string content((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
        file.close();

        try {
            std::cout << "Reading config file: " << config_file_path << '\n';

            auto yaml = fkyaml::node::deserialize(content);

            if (yaml.contains("version")) {
                version = yaml["version"].get_value<std::string>();
            }

            if (CONFIG_VERSION != version) {
                std::cout << "Config version mismatch (expected: " << CONFIG_VERSION
                          << ", got: " << version << "), creating new config\n";
                saveToFile();
                return true;
            }

            loadVideoConfigFromYaml(yaml);
            loadRenderInfoFromYaml(yaml);
            loadWindowConfigFromYaml(yaml);
            loadAudioConfigFromYaml(yaml);
            loadGameConfigFromYaml(yaml);
            loadControlsFromYaml(yaml);

            std::cout << "Config file loaded successfully\n\n";
            return true;

        } catch (const fkyaml::exception& e) {
            std::cerr << "Error parsing YAML config: " << e.what() << '\n';
            std::cerr << "Creating new config with defaults\n";
            saveToFile();
            return true;
        }
    }

    // Guarda les opcions al fitxer configurat
    auto saveToFile() -> bool {
        std::ofstream file(config_file_path);
        if (!file.is_open()) {
            std::cerr << "Error: Unable to open file " << config_file_path << " for writing\n";
            return false;
        }

        std::cout << "Writing config file: " << config_file_path << '\n';

        file << "# Aventures En Egipte - Configuration File\n";
        file << "# \n";
        file << "# This file is automatically generated and managed by the game.\n";
        file << "# Manual edits are preserved if valid.\n";
        file << "\n";

        // VERSION
        file << "version: \"" << Texts::VERSION << "\"\n";
        file << "\n";

        // VIDEO
        file << "# VIDEO\n";
        file << "video:\n";
        file << "  gpu_acceleration: " << (video.gpu_acceleration ? "true" : "false") << "\n";
        file << "  shader_enabled: " << (video.shader_enabled ? "true" : "false") << "\n";
        file << "  supersampling: " << (video.supersampling ? "true" : "false") << "\n";
        {
            const char* m = nullptr;
            switch (video.scaling_mode) {
                case ScalingMode::DISABLED:
                    m = "disabled";
                    break;
                case ScalingMode::STRETCH:
                    m = "stretch";
                    break;
                case ScalingMode::LETTERBOX:
                    m = "letterbox";
                    break;
                case ScalingMode::OVERSCAN:
                    m = "overscan";
                    break;
                case ScalingMode::INTEGER:
                default:
                    m = "integer";
                    break;
            }
            file << "  scaling_mode: " << m << " # disabled|stretch|letterbox|overscan|integer\n";
        }
        file << "  vsync: " << (video.vsync ? "true" : "false") << "\n";
        file << "  aspect_ratio_4_3: " << (video.aspect_ratio_4_3 ? "true" : "false") << "\n";
        file << "  texture_filter: " << (video.texture_filter == TextureFilter::LINEAR ? "linear" : "nearest") << " # nearest|linear\n";
        file << "  downscale_algo: " << video.downscale_algo << " # 0=bilinear, 1=Lanczos2, 2=Lanczos3\n";
        file << "  internal_resolution: " << video.internal_resolution << " # multiplicador enter font, clampat a max_zoom\n";
        file << "  current_shader: " << video.current_shader << "\n";
        file << "  current_postfx_preset: " << video.current_postfx_preset << "\n";
        file << "  current_crtpi_preset: " << video.current_crtpi_preset << "\n";
        file << "\n";

        // RENDER INFO
        file << "# RENDER INFO\n";
        file << "render_info:\n";
        {
            const char* pos = "off";
            if (render_info.position == RenderInfoPosition::TOP) {
                pos = "top";
            } else if (render_info.position == RenderInfoPosition::BOTTOM) {
                pos = "bottom";
            }
            file << "  position: " << pos << " # off/top/bottom\n";
        }
        file << "  show_time: " << (render_info.show_time ? "true" : "false") << "\n";
        file << "  text_color: " << render_info.text_color << "\n";
        file << "  shadow_color: " << render_info.shadow_color << "\n";
        file << "\n";

        // WINDOW
        file << "# WINDOW\n";
        file << "window:\n";
        file << "  zoom: " << window.zoom << "\n";
        file << "  fullscreen: " << (window.fullscreen ? "true" : "false") << "\n";
        file << "\n";

        // AUDIO
        file << "# AUDIO\n";
        file << "audio:\n";
        file << "  enabled: " << (audio.enabled ? "true" : "false") << "\n";
        file << "  volume: " << audio.volume << "\n";
        file << "  music:\n";
        file << "    enabled: " << (audio.music.enabled ? "true" : "false") << "\n";
        file << "    volume: " << audio.music.volume << "\n";
        file << "  sound:\n";
        file << "    enabled: " << (audio.sound.enabled ? "true" : "false") << "\n";
        file << "    volume: " << audio.sound.volume << "\n";
        file << "\n";

        // GAME
        file << "# GAME\n";
        file << "game:\n";
        file << "  use_new_logo: " << (game.use_new_logo ? "true" : "false") << "\n";
        file << "  show_title_credits: " << (game.show_title_credits ? "true" : "false") << "\n";
        file << "  show_preload: " << (game.show_preload ? "true" : "false") << "\n";
        file << "\n";

        // CONTROLS — només moviment del jugador. Les tecles d'UI viuen a
        // data/input/keys.yaml (defaults) + ~/.config/jailgames/aee/keys.yaml (overrides).
        file << "# CONTROLS (noms SDL: \"Up\", \"Down\", \"W\", \"Space\", etc.)\n";
        file << "controls:\n";
        file << "  up: \"" << SDL_GetScancodeName(keys_game.up) << "\"\n";
        file << "  down: \"" << SDL_GetScancodeName(keys_game.down) << "\"\n";
        file << "  left: \"" << SDL_GetScancodeName(keys_game.left) << "\"\n";
        file << "  right: \"" << SDL_GetScancodeName(keys_game.right) << "\"\n";

        file.close();

        std::cout << "Config file saved successfully\n\n";
        return true;
    }

    // --- Helpers per a parsejar camps de YAML ---
    static void parseFloatField(const fkyaml::node& node, const std::string& key, float& target) {
        if (node.contains(key)) {
            try {
                target = node[key].get_value<float>();
            } catch (...) {
                // @INTENTIONAL: si el camp YAML no és float vàlid, mantenim el valor per defecte.
            }
        }
    }

    static void parseIntField(const fkyaml::node& node, const std::string& key, int& target) {
        if (node.contains(key)) {
            try {
                target = node[key].get_value<int>();
            } catch (...) {
                // @INTENTIONAL: camp YAML no és int vàlid, mantenim valor per defecte.
            }
        }
    }

    static void parseBoolField(const fkyaml::node& node, const std::string& key, bool& target) {
        if (node.contains(key)) {
            try {
                target = node[key].get_value<bool>();
            } catch (...) {
                // @INTENTIONAL: camp YAML no és bool vàlid, mantenim valor per defecte.
            }
        }
    }

    // --- Presets PostFX ---

    void setPostFXFile(const std::string& path) { postfx_file_path = path; }

    auto loadPostFXFromFile() -> bool {
        postfx_presets.clear();

        std::ifstream file(postfx_file_path);
        if (!file.good()) {
            std::cout << "PostFX file not found, creating defaults: " << postfx_file_path << '\n';
            // Escriure defaults
            std::ofstream out(postfx_file_path);
            if (out.is_open()) {
                out << "# Aventures En Egipte - PostFX Shader Presets\n\n";
                out << "presets:\n";
                out << "  - name: \"CRT\"\n    vignette: 0.6\n    scanlines: 0.7\n    chroma: 0.15\n    mask: 0.6\n    gamma: 0.8\n";
                out << "  - name: \"NTSC\"\n    vignette: 0.4\n    scanlines: 0.5\n    chroma: 0.2\n    mask: 0.4\n    gamma: 0.5\n    bleeding: 0.6\n";
                out << "  - name: \"CURVED\"\n    vignette: 0.5\n    scanlines: 0.6\n    chroma: 0.1\n    mask: 0.5\n    gamma: 0.7\n    curvature: 0.8\n";
                out << "  - name: \"SCANLINES\"\n    scanlines: 0.8\n    vignette: 0.0\n    chroma: 0.0\n";
                out << "  - name: \"SUBTLE\"\n    vignette: 0.3\n    scanlines: 0.4\n    chroma: 0.05\n    gamma: 0.3\n";
                out << "  - name: \"CRT LIVE\"\n    vignette: 0.5\n    scanlines: 0.6\n    chroma: 0.3\n    mask: 0.3\n    gamma: 0.4\n    curvature: 0.3\n    bleeding: 0.4\n    flicker: 0.8\n";
                out.close();
            }
            postfx_presets.push_back({"CRT", 0.6F, 0.7F, 0.15F, 0.6F, 0.8F});
            postfx_presets.push_back({"NTSC", 0.4F, 0.5F, 0.2F, 0.4F, 0.5F, 0.0F, 0.6F});
            postfx_presets.push_back({"CURVED", 0.5F, 0.6F, 0.1F, 0.5F, 0.7F, 0.8F});
            postfx_presets.push_back({"SCANLINES", 0.0F, 0.8F});
            postfx_presets.push_back({"SUBTLE", 0.3F, 0.4F, 0.05F, 0.0F, 0.3F});
            postfx_presets.push_back({"CRT LIVE", 0.5F, 0.6F, 0.3F, 0.3F, 0.4F, 0.3F, 0.4F, 0.8F});
            current_postfx_preset = 0;
            return true;
        }

        std::string content((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
        file.close();

        try {
            auto yaml = fkyaml::node::deserialize(content);
            if (yaml.contains("presets")) {
                for (const auto& p : yaml["presets"]) {
                    PostFXPreset preset;
                    if (p.contains("name")) {
                        preset.name = p["name"].get_value<std::string>();
                    }
                    parseFloatField(p, "vignette", preset.vignette);
                    parseFloatField(p, "scanlines", preset.scanlines);
                    parseFloatField(p, "chroma", preset.chroma);
                    parseFloatField(p, "mask", preset.mask);
                    parseFloatField(p, "gamma", preset.gamma);
                    parseFloatField(p, "curvature", preset.curvature);
                    parseFloatField(p, "bleeding", preset.bleeding);
                    parseFloatField(p, "flicker", preset.flicker);
                    postfx_presets.push_back(preset);
                }
            }
            current_postfx_preset = 0;
            std::cout << "PostFX loaded: " << postfx_presets.size() << " preset(s)\n";
            return true;
        } catch (const fkyaml::exception& e) {
            std::cerr << "Error parsing PostFX YAML: " << e.what() << '\n';
            postfx_presets.push_back({"CRT", 0.6F, 0.7F, 0.15F, 0.6F, 0.8F});
            current_postfx_preset = 0;
            return false;
        }
    }

    // --- Presets CrtPi ---

    void setCrtPiFile(const std::string& path) { crtpi_file_path = path; }

    auto loadCrtPiFromFile() -> bool {
        crtpi_presets.clear();

        std::ifstream file(crtpi_file_path);
        if (!file.good()) {
            std::cout << "CrtPi file not found, creating defaults: " << crtpi_file_path << '\n';
            std::ofstream out(crtpi_file_path);
            if (out.is_open()) {
                out << "# Aventures En Egipte - CrtPi Shader Presets\n\n";
                out << "presets:\n";
                out << "  - name: \"DEFAULT\"\n    scanline_weight: 6.0\n    scanline_gap_brightness: 0.12\n    bloom_factor: 3.5\n    input_gamma: 2.4\n    output_gamma: 2.2\n    mask_brightness: 0.80\n    curvature_x: 0.05\n    curvature_y: 0.10\n    mask_type: 2\n    enable_scanlines: true\n    enable_multisample: true\n    enable_gamma: true\n    enable_curvature: false\n    enable_sharper: false\n";
                out << "  - name: \"CURVED\"\n    scanline_weight: 6.0\n    scanline_gap_brightness: 0.12\n    bloom_factor: 3.5\n    input_gamma: 2.4\n    output_gamma: 2.2\n    mask_brightness: 0.80\n    curvature_x: 0.05\n    curvature_y: 0.10\n    mask_type: 2\n    enable_scanlines: true\n    enable_multisample: true\n    enable_gamma: true\n    enable_curvature: true\n    enable_sharper: false\n";
                out << "  - name: \"SHARP\"\n    scanline_weight: 6.0\n    scanline_gap_brightness: 0.12\n    bloom_factor: 3.5\n    input_gamma: 2.4\n    output_gamma: 2.2\n    mask_brightness: 0.80\n    curvature_x: 0.05\n    curvature_y: 0.10\n    mask_type: 2\n    enable_scanlines: true\n    enable_multisample: false\n    enable_gamma: true\n    enable_curvature: false\n    enable_sharper: true\n";
                out << "  - name: \"MINIMAL\"\n    scanline_weight: 8.0\n    scanline_gap_brightness: 0.05\n    bloom_factor: 2.0\n    input_gamma: 2.4\n    output_gamma: 2.2\n    mask_brightness: 1.00\n    curvature_x: 0.0\n    curvature_y: 0.0\n    mask_type: 0\n    enable_scanlines: true\n    enable_multisample: false\n    enable_gamma: false\n    enable_curvature: false\n    enable_sharper: false\n";
                out.close();
            }
            crtpi_presets.push_back({"DEFAULT", 6.0F, 0.12F, 3.5F, 2.4F, 2.2F, 0.80F, 0.05F, 0.10F, 2, true, true, true, false, false});
            crtpi_presets.push_back({"CURVED", 6.0F, 0.12F, 3.5F, 2.4F, 2.2F, 0.80F, 0.05F, 0.10F, 2, true, true, true, true, false});
            crtpi_presets.push_back({"SHARP", 6.0F, 0.12F, 3.5F, 2.4F, 2.2F, 0.80F, 0.05F, 0.10F, 2, true, false, true, false, true});
            crtpi_presets.push_back({"MINIMAL", 8.0F, 0.05F, 2.0F, 2.4F, 2.2F, 1.00F, 0.0F, 0.0F, 0, true, false, false, false, false});
            current_crtpi_preset = 0;
            return true;
        }

        std::string content((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
        file.close();

        try {
            auto yaml = fkyaml::node::deserialize(content);
            if (yaml.contains("presets")) {
                for (const auto& p : yaml["presets"]) {
                    CrtPiPreset preset;
                    if (p.contains("name")) {
                        preset.name = p["name"].get_value<std::string>();
                    }
                    parseFloatField(p, "scanline_weight", preset.scanline_weight);
                    parseFloatField(p, "scanline_gap_brightness", preset.scanline_gap_brightness);
                    parseFloatField(p, "bloom_factor", preset.bloom_factor);
                    parseFloatField(p, "input_gamma", preset.input_gamma);
                    parseFloatField(p, "output_gamma", preset.output_gamma);
                    parseFloatField(p, "mask_brightness", preset.mask_brightness);
                    parseFloatField(p, "curvature_x", preset.curvature_x);
                    parseFloatField(p, "curvature_y", preset.curvature_y);
                    parseIntField(p, "mask_type", preset.mask_type);
                    parseBoolField(p, "enable_scanlines", preset.enable_scanlines);
                    parseBoolField(p, "enable_multisample", preset.enable_multisample);
                    parseBoolField(p, "enable_gamma", preset.enable_gamma);
                    parseBoolField(p, "enable_curvature", preset.enable_curvature);
                    parseBoolField(p, "enable_sharper", preset.enable_sharper);
                    crtpi_presets.push_back(preset);
                }
            }
            current_crtpi_preset = 0;
            std::cout << "CrtPi loaded: " << crtpi_presets.size() << " preset(s)\n";
            return true;
        } catch (const fkyaml::exception& e) {
            std::cerr << "Error parsing CrtPi YAML: " << e.what() << '\n';
            crtpi_presets.push_back({"DEFAULT", 6.0F, 0.12F, 3.5F, 2.4F, 2.2F, 0.80F, 0.05F, 0.10F, 2, true, true, true, false, false});
            current_crtpi_preset = 0;
            return false;
        }
    }

}  // namespace Options
