#include "options.hpp"

#include <fstream>
#include <iostream>
#include <string>
#include <unordered_map>

#include "core/defaults.hpp"
#include "external/fkyaml_node.hpp"
#include "project.h"

namespace Options {

// ========== FUNCIONS AUXILIARS PER CONVERSIÓ DE CONTROLES ==========

// Mapa de SDL_Scancode a string
static const std::unordered_map<SDL_Scancode, std::string> SCANCODE_TO_STRING = {
    {SDL_SCANCODE_A, "A"},
    {SDL_SCANCODE_B, "B"},
    {SDL_SCANCODE_C, "C"},
    {SDL_SCANCODE_D, "D"},
    {SDL_SCANCODE_E, "E"},
    {SDL_SCANCODE_F, "F"},
    {SDL_SCANCODE_G, "G"},
    {SDL_SCANCODE_H, "H"},
    {SDL_SCANCODE_I, "I"},
    {SDL_SCANCODE_J, "J"},
    {SDL_SCANCODE_K, "K"},
    {SDL_SCANCODE_L, "L"},
    {SDL_SCANCODE_M, "M"},
    {SDL_SCANCODE_N, "N"},
    {SDL_SCANCODE_O, "O"},
    {SDL_SCANCODE_P, "P"},
    {SDL_SCANCODE_Q, "Q"},
    {SDL_SCANCODE_R, "R"},
    {SDL_SCANCODE_S, "S"},
    {SDL_SCANCODE_T, "T"},
    {SDL_SCANCODE_U, "U"},
    {SDL_SCANCODE_V, "V"},
    {SDL_SCANCODE_W, "W"},
    {SDL_SCANCODE_X, "X"},
    {SDL_SCANCODE_Y, "Y"},
    {SDL_SCANCODE_Z, "Z"},
    {SDL_SCANCODE_1, "1"},
    {SDL_SCANCODE_2, "2"},
    {SDL_SCANCODE_3, "3"},
    {SDL_SCANCODE_4, "4"},
    {SDL_SCANCODE_5, "5"},
    {SDL_SCANCODE_6, "6"},
    {SDL_SCANCODE_7, "7"},
    {SDL_SCANCODE_8, "8"},
    {SDL_SCANCODE_9, "9"},
    {SDL_SCANCODE_0, "0"},
    {SDL_SCANCODE_RETURN, "RETURN"},
    {SDL_SCANCODE_ESCAPE, "ESCAPE"},
    {SDL_SCANCODE_BACKSPACE, "BACKSPACE"},
    {SDL_SCANCODE_TAB, "TAB"},
    {SDL_SCANCODE_SPACE, "SPACE"},
    {SDL_SCANCODE_UP, "UP"},
    {SDL_SCANCODE_DOWN, "DOWN"},
    {SDL_SCANCODE_LEFT, "LEFT"},
    {SDL_SCANCODE_RIGHT, "RIGHT"},
    {SDL_SCANCODE_LSHIFT, "LSHIFT"},
    {SDL_SCANCODE_RSHIFT, "RSHIFT"},
    {SDL_SCANCODE_LCTRL, "LCTRL"},
    {SDL_SCANCODE_RCTRL, "RCTRL"},
    {SDL_SCANCODE_LALT, "LALT"},
    {SDL_SCANCODE_RALT, "RALT"}};

// Mapa invers: string a SDL_Scancode
static const std::unordered_map<std::string, SDL_Scancode> STRING_TO_SCANCODE = {
    {"A", SDL_SCANCODE_A},
    {"B", SDL_SCANCODE_B},
    {"C", SDL_SCANCODE_C},
    {"D", SDL_SCANCODE_D},
    {"E", SDL_SCANCODE_E},
    {"F", SDL_SCANCODE_F},
    {"G", SDL_SCANCODE_G},
    {"H", SDL_SCANCODE_H},
    {"I", SDL_SCANCODE_I},
    {"J", SDL_SCANCODE_J},
    {"K", SDL_SCANCODE_K},
    {"L", SDL_SCANCODE_L},
    {"M", SDL_SCANCODE_M},
    {"N", SDL_SCANCODE_N},
    {"O", SDL_SCANCODE_O},
    {"P", SDL_SCANCODE_P},
    {"Q", SDL_SCANCODE_Q},
    {"R", SDL_SCANCODE_R},
    {"S", SDL_SCANCODE_S},
    {"T", SDL_SCANCODE_T},
    {"U", SDL_SCANCODE_U},
    {"V", SDL_SCANCODE_V},
    {"W", SDL_SCANCODE_W},
    {"X", SDL_SCANCODE_X},
    {"Y", SDL_SCANCODE_Y},
    {"Z", SDL_SCANCODE_Z},
    {"1", SDL_SCANCODE_1},
    {"2", SDL_SCANCODE_2},
    {"3", SDL_SCANCODE_3},
    {"4", SDL_SCANCODE_4},
    {"5", SDL_SCANCODE_5},
    {"6", SDL_SCANCODE_6},
    {"7", SDL_SCANCODE_7},
    {"8", SDL_SCANCODE_8},
    {"9", SDL_SCANCODE_9},
    {"0", SDL_SCANCODE_0},
    {"RETURN", SDL_SCANCODE_RETURN},
    {"ESCAPE", SDL_SCANCODE_ESCAPE},
    {"BACKSPACE", SDL_SCANCODE_BACKSPACE},
    {"TAB", SDL_SCANCODE_TAB},
    {"SPACE", SDL_SCANCODE_SPACE},
    {"UP", SDL_SCANCODE_UP},
    {"DOWN", SDL_SCANCODE_DOWN},
    {"LEFT", SDL_SCANCODE_LEFT},
    {"RIGHT", SDL_SCANCODE_RIGHT},
    {"LSHIFT", SDL_SCANCODE_LSHIFT},
    {"RSHIFT", SDL_SCANCODE_RSHIFT},
    {"LCTRL", SDL_SCANCODE_LCTRL},
    {"RCTRL", SDL_SCANCODE_RCTRL},
    {"LALT", SDL_SCANCODE_LALT},
    {"RALT", SDL_SCANCODE_RALT}};

// Mapa de botó de gamepad (int) a string
static const std::unordered_map<int, std::string> BUTTON_TO_STRING = {
    {SDL_GAMEPAD_BUTTON_SOUTH, "SOUTH"},  // A (Xbox), Cross (PS)
    {SDL_GAMEPAD_BUTTON_EAST, "EAST"},    // B (Xbox), Circle (PS)
    {SDL_GAMEPAD_BUTTON_WEST, "WEST"},    // X (Xbox), Square (PS)
    {SDL_GAMEPAD_BUTTON_NORTH, "NORTH"},  // Y (Xbox), Triangle (PS)
    {SDL_GAMEPAD_BUTTON_BACK, "BACK"},
    {SDL_GAMEPAD_BUTTON_START, "START"},
    {SDL_GAMEPAD_BUTTON_LEFT_SHOULDER, "LEFT_SHOULDER"},
    {SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, "RIGHT_SHOULDER"},
    {SDL_GAMEPAD_BUTTON_DPAD_UP, "DPAD_UP"},
    {SDL_GAMEPAD_BUTTON_DPAD_DOWN, "DPAD_DOWN"},
    {SDL_GAMEPAD_BUTTON_DPAD_LEFT, "DPAD_LEFT"},
    {SDL_GAMEPAD_BUTTON_DPAD_RIGHT, "DPAD_RIGHT"},
    {100, "L2_AS_BUTTON"},  // Trigger L2 com a botó digital
    {101, "R2_AS_BUTTON"}   // Trigger R2 com a botó digital
};

// Mapa invers: string a botó de gamepad
static const std::unordered_map<std::string, int> STRING_TO_BUTTON = {
    {"SOUTH", SDL_GAMEPAD_BUTTON_SOUTH},
    {"EAST", SDL_GAMEPAD_BUTTON_EAST},
    {"WEST", SDL_GAMEPAD_BUTTON_WEST},
    {"NORTH", SDL_GAMEPAD_BUTTON_NORTH},
    {"BACK", SDL_GAMEPAD_BUTTON_BACK},
    {"START", SDL_GAMEPAD_BUTTON_START},
    {"LEFT_SHOULDER", SDL_GAMEPAD_BUTTON_LEFT_SHOULDER},
    {"RIGHT_SHOULDER", SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER},
    {"DPAD_UP", SDL_GAMEPAD_BUTTON_DPAD_UP},
    {"DPAD_DOWN", SDL_GAMEPAD_BUTTON_DPAD_DOWN},
    {"DPAD_LEFT", SDL_GAMEPAD_BUTTON_DPAD_LEFT},
    {"DPAD_RIGHT", SDL_GAMEPAD_BUTTON_DPAD_RIGHT},
    {"L2_AS_BUTTON", 100},
    {"R2_AS_BUTTON", 101}};

static auto scancodeToString(SDL_Scancode code) -> std::string {
    auto it = SCANCODE_TO_STRING.find(code);
    return (it != SCANCODE_TO_STRING.end()) ? it->second : "UNKNOWN";
}

static auto stringToScancode(const std::string& str) -> SDL_Scancode {
    auto it = STRING_TO_SCANCODE.find(str);
    return (it != STRING_TO_SCANCODE.end()) ? it->second : SDL_SCANCODE_UNKNOWN;
}

static auto buttonToString(int button) -> std::string {
    auto it = BUTTON_TO_STRING.find(button);
    return (it != BUTTON_TO_STRING.end()) ? it->second : "UNKNOWN";
}

static auto stringToButton(const std::string& str) -> int {
    auto it = STRING_TO_BUTTON.find(str);
    return (it != STRING_TO_BUTTON.end()) ? it->second : SDL_GAMEPAD_BUTTON_INVALID;
}

// ========== FI FUNCIONS AUXILIARS ==========

// Inicialitzar opcions amb valors per defecte de Defaults::
void init() {
#ifdef _DEBUG
    console = true;
#else
    console = false;
#endif

    // Window
    window.width = Defaults::Window::WIDTH;
    window.height = Defaults::Window::HEIGHT;
    window.fullscreen = false;
    window.zoom_factor = Defaults::Window::BASE_ZOOM;

    // Physics
    physics.rotation_speed = Defaults::Physics::ROTATION_SPEED;
    physics.acceleration = Defaults::Physics::ACCELERATION;
    physics.max_velocity = Defaults::Physics::MAX_VELOCITY;
    physics.friction = Defaults::Physics::FRICTION;
    physics.enemy_speed = Defaults::Physics::ENEMY_SPEED;
    physics.bullet_speed = Defaults::Physics::BULLET_SPEED;

    // Gameplay
    gameplay.max_enemies = Defaults::Entities::MAX_ORNIS;
    gameplay.max_bullets = Defaults::Entities::MAX_BALES;

    // Rendering
    rendering.vsync = Defaults::Rendering::VSYNC_DEFAULT;

    // Audio
    audio.enabled = Defaults::Audio::ENABLED;
    audio.volume = Defaults::Audio::VOLUME;
    audio.music.enabled = Defaults::Music::ENABLED;
    audio.music.volume = Defaults::Music::VOLUME;
    audio.sound.enabled = Defaults::Sound::ENABLED;
    audio.sound.volume = Defaults::Sound::VOLUME;

    // Version
    version = std::string(Project::VERSION);
}

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

// Funcions auxiliars per carregar seccions del YAML

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

        if (win.contains("width")) {
            try {
                auto val = win["width"].get_value<int>();
                window.width = (val >= Defaults::Window::MIN_WIDTH)
                    ? val
                    : Defaults::Window::WIDTH;
            } catch (...) {
                window.width = Defaults::Window::WIDTH;
            }
        }

        if (win.contains("height")) {
            try {
                auto val = win["height"].get_value<int>();
                window.height = (val >= Defaults::Window::MIN_HEIGHT)
                    ? val
                    : Defaults::Window::HEIGHT;
            } catch (...) {
                window.height = Defaults::Window::HEIGHT;
            }
        }

        if (win.contains("fullscreen")) {
            try {
                window.fullscreen = win["fullscreen"].get_value<bool>();
            } catch (...) {
                window.fullscreen = false;
            }
        }

        if (win.contains("zoom_factor")) {
            try {
                auto val = win["zoom_factor"].get_value<float>();
                window.zoom_factor = (val >= Defaults::Window::MIN_ZOOM && val <= 10.0F)
                    ? val
                    : Defaults::Window::BASE_ZOOM;
            } catch (...) {
                window.zoom_factor = Defaults::Window::BASE_ZOOM;
            }
        } else {
            // Legacy config: infer zoom from width
            window.zoom_factor = static_cast<float>(window.width) / Defaults::Window::WIDTH;
            window.zoom_factor = std::max(Defaults::Window::MIN_ZOOM, window.zoom_factor);
        }
    }
}

static void loadPhysicsConfigFromYaml(const fkyaml::node& yaml) {
    if (yaml.contains("physics")) {
        const auto& phys = yaml["physics"];

        if (phys.contains("rotation_speed")) {
            try {
                auto val = phys["rotation_speed"].get_value<float>();
                physics.rotation_speed =
                    (val > 0) ? val : Defaults::Physics::ROTATION_SPEED;
            } catch (...) {
                physics.rotation_speed = Defaults::Physics::ROTATION_SPEED;
            }
        }

        if (phys.contains("acceleration")) {
            try {
                auto val = phys["acceleration"].get_value<float>();
                physics.acceleration =
                    (val > 0) ? val : Defaults::Physics::ACCELERATION;
            } catch (...) {
                physics.acceleration = Defaults::Physics::ACCELERATION;
            }
        }

        if (phys.contains("max_velocity")) {
            try {
                auto val = phys["max_velocity"].get_value<float>();
                physics.max_velocity =
                    (val > 0) ? val : Defaults::Physics::MAX_VELOCITY;
            } catch (...) {
                physics.max_velocity = Defaults::Physics::MAX_VELOCITY;
            }
        }

        if (phys.contains("friction")) {
            try {
                auto val = phys["friction"].get_value<float>();
                physics.friction = (val > 0) ? val : Defaults::Physics::FRICTION;
            } catch (...) {
                physics.friction = Defaults::Physics::FRICTION;
            }
        }

        if (phys.contains("enemy_speed")) {
            try {
                auto val = phys["enemy_speed"].get_value<float>();
                physics.enemy_speed = (val > 0) ? val : Defaults::Physics::ENEMY_SPEED;
            } catch (...) {
                physics.enemy_speed = Defaults::Physics::ENEMY_SPEED;
            }
        }

        if (phys.contains("bullet_speed")) {
            try {
                auto val = phys["bullet_speed"].get_value<float>();
                physics.bullet_speed =
                    (val > 0) ? val : Defaults::Physics::BULLET_SPEED;
            } catch (...) {
                physics.bullet_speed = Defaults::Physics::BULLET_SPEED;
            }
        }
    }
}

static void loadGameplayConfigFromYaml(const fkyaml::node& yaml) {
    if (yaml.contains("gameplay")) {
        const auto& game = yaml["gameplay"];

        if (game.contains("max_enemies")) {
            try {
                auto val = game["max_enemies"].get_value<int>();
                gameplay.max_enemies =
                    (val > 0 && val <= 50) ? val : Defaults::Entities::MAX_ORNIS;
            } catch (...) {
                gameplay.max_enemies = Defaults::Entities::MAX_ORNIS;
            }
        }

        if (game.contains("max_bullets")) {
            try {
                auto val = game["max_bullets"].get_value<int>();
                gameplay.max_bullets =
                    (val > 0 && val <= 10) ? val : Defaults::Entities::MAX_BALES;
            } catch (...) {
                gameplay.max_bullets = Defaults::Entities::MAX_BALES;
            }
        }
    }
}

static void loadRenderingConfigFromYaml(const fkyaml::node& yaml) {
    if (yaml.contains("rendering")) {
        const auto& rend = yaml["rendering"];

        if (rend.contains("vsync")) {
            try {
                int val = rend["vsync"].get_value<int>();
                // Validar: només 0 o 1
                rendering.vsync = (val == 0 || val == 1) ? val : Defaults::Rendering::VSYNC_DEFAULT;
            } catch (...) {
                rendering.vsync = Defaults::Rendering::VSYNC_DEFAULT;
            }
        }
    }
}

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

        if (aud.contains("enabled")) {
            try {
                audio.enabled = aud["enabled"].get_value<bool>();
            } catch (...) {
                audio.enabled = Defaults::Audio::ENABLED;
            }
        }

        if (aud.contains("volume")) {
            try {
                auto val = aud["volume"].get_value<float>();
                audio.volume = (val >= 0.0F && val <= 1.0F) ? val : Defaults::Audio::VOLUME;
            } catch (...) {
                audio.volume = Defaults::Audio::VOLUME;
            }
        }

        if (aud.contains("music")) {
            const auto& mus = aud["music"];

            if (mus.contains("enabled")) {
                try {
                    audio.music.enabled = mus["enabled"].get_value<bool>();
                } catch (...) {
                    audio.music.enabled = Defaults::Music::ENABLED;
                }
            }

            if (mus.contains("volume")) {
                try {
                    auto val = mus["volume"].get_value<float>();
                    audio.music.volume = (val >= 0.0F && val <= 1.0F) ? val : Defaults::Music::VOLUME;
                } catch (...) {
                    audio.music.volume = Defaults::Music::VOLUME;
                }
            }
        }

        if (aud.contains("sound")) {
            const auto& snd = aud["sound"];

            if (snd.contains("enabled")) {
                try {
                    audio.sound.enabled = snd["enabled"].get_value<bool>();
                } catch (...) {
                    audio.sound.enabled = Defaults::Sound::ENABLED;
                }
            }

            if (snd.contains("volume")) {
                try {
                    auto val = snd["volume"].get_value<float>();
                    audio.sound.volume = (val >= 0.0F && val <= 1.0F) ? val : Defaults::Sound::VOLUME;
                } catch (...) {
                    audio.sound.volume = Defaults::Sound::VOLUME;
                }
            }
        }
    }
}

// Carregar controls del jugador 1 des de YAML
static void loadPlayer1ControlsFromYaml(const fkyaml::node& yaml) {
    if (!yaml.contains("player1")) {
        return;
    }

    const auto& p1 = yaml["player1"];

    // Carregar controls de teclat
    if (p1.contains("keyboard")) {
        const auto& kb = p1["keyboard"];
        if (kb.contains("key_left")) {
            player1.keyboard.key_left = stringToScancode(kb["key_left"].get_value<std::string>());
        }
        if (kb.contains("key_right")) {
            player1.keyboard.key_right = stringToScancode(kb["key_right"].get_value<std::string>());
        }
        if (kb.contains("key_thrust")) {
            player1.keyboard.key_thrust = stringToScancode(kb["key_thrust"].get_value<std::string>());
        }
        if (kb.contains("key_shoot")) {
            player1.keyboard.key_shoot = stringToScancode(kb["key_shoot"].get_value<std::string>());
        }
    }

    // Carregar controls de gamepad
    if (p1.contains("gamepad")) {
        const auto& gp = p1["gamepad"];
        if (gp.contains("button_left")) {
            player1.gamepad.button_left = stringToButton(gp["button_left"].get_value<std::string>());
        }
        if (gp.contains("button_right")) {
            player1.gamepad.button_right = stringToButton(gp["button_right"].get_value<std::string>());
        }
        if (gp.contains("button_thrust")) {
            player1.gamepad.button_thrust = stringToButton(gp["button_thrust"].get_value<std::string>());
        }
        if (gp.contains("button_shoot")) {
            player1.gamepad.button_shoot = stringToButton(gp["button_shoot"].get_value<std::string>());
        }
    }

    // Carregar nom del gamepad
    if (p1.contains("gamepad_name")) {
        player1.gamepad_name = p1["gamepad_name"].get_value<std::string>();
    }
}

// Carregar controls del jugador 2 des de YAML
static void loadPlayer2ControlsFromYaml(const fkyaml::node& yaml) {
    if (!yaml.contains("player2")) {
        return;
    }

    const auto& p2 = yaml["player2"];

    // Carregar controls de teclat
    if (p2.contains("keyboard")) {
        const auto& kb = p2["keyboard"];
        if (kb.contains("key_left")) {
            player2.keyboard.key_left = stringToScancode(kb["key_left"].get_value<std::string>());
        }
        if (kb.contains("key_right")) {
            player2.keyboard.key_right = stringToScancode(kb["key_right"].get_value<std::string>());
        }
        if (kb.contains("key_thrust")) {
            player2.keyboard.key_thrust = stringToScancode(kb["key_thrust"].get_value<std::string>());
        }
        if (kb.contains("key_shoot")) {
            player2.keyboard.key_shoot = stringToScancode(kb["key_shoot"].get_value<std::string>());
        }
    }

    // Carregar controls de gamepad
    if (p2.contains("gamepad")) {
        const auto& gp = p2["gamepad"];
        if (gp.contains("button_left")) {
            player2.gamepad.button_left = stringToButton(gp["button_left"].get_value<std::string>());
        }
        if (gp.contains("button_right")) {
            player2.gamepad.button_right = stringToButton(gp["button_right"].get_value<std::string>());
        }
        if (gp.contains("button_thrust")) {
            player2.gamepad.button_thrust = stringToButton(gp["button_thrust"].get_value<std::string>());
        }
        if (gp.contains("button_shoot")) {
            player2.gamepad.button_shoot = stringToButton(gp["button_shoot"].get_value<std::string>());
        }
    }

    // Carregar nom del gamepad
    if (p2.contains("gamepad_name")) {
        player2.gamepad_name = p2["gamepad_name"].get_value<std::string>();
    }
}

// Carregar configuració des del fitxer YAML
auto loadFromFile() -> bool {
    const std::string CONFIG_VERSION = std::string(Project::VERSION);

    std::ifstream file(config_file_path);
    if (!file.good()) {
        // El fitxer no existeix → crear-ne un de nou amb valors per defecte
        if (console) {
            std::cout << "Fitxer de config no trobat, creant-ne un de nou: "
                      << config_file_path << '\n';
        }
        saveToFile();
        return true;
    }

    // Llegir tot el contingut del fitxer
    std::string content((std::istreambuf_iterator<char>(file)),
        std::istreambuf_iterator<char>());
    file.close();

    try {
        // Parsejar YAML
        auto yaml = fkyaml::node::deserialize(content);

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

        if (CONFIG_VERSION != version) {
            // Versió incompatible → regenerar config
            if (console) {
                std::cout << "Versió de config incompatible (esperada: "
                          << CONFIG_VERSION << ", trobada: " << version
                          << "), regenerant config\n";
            }
            init();
            saveToFile();
            return true;
        }

        // Carregar seccions
        loadWindowConfigFromYaml(yaml);
        loadPhysicsConfigFromYaml(yaml);
        loadGameplayConfigFromYaml(yaml);
        loadRenderingConfigFromYaml(yaml);
        loadAudioConfigFromYaml(yaml);
        loadPlayer1ControlsFromYaml(yaml);
        loadPlayer2ControlsFromYaml(yaml);

        if (console) {
            std::cout << "Config carregada correctament des de: " << config_file_path
                      << '\n';
        }

        return true;

    } catch (const fkyaml::exception& e) {
        // Error de parsejat YAML → regenerar config
        if (console) {
            std::cerr << "Error parsejant YAML: " << e.what() << '\n';
            std::cerr << "Creant config nou amb valors per defecte\n";
        }
        init();
        saveToFile();
        return true;
    }
}

// Guardar controls del jugador 1 a YAML
static void savePlayer1ControlsToYaml(std::ofstream& file) {
    file << "# CONTROLS JUGADOR 1\n";
    file << "player1:\n";
    file << "  keyboard:\n";
    file << "    key_left: " << scancodeToString(player1.keyboard.key_left) << "\n";
    file << "    key_right: " << scancodeToString(player1.keyboard.key_right) << "\n";
    file << "    key_thrust: " << scancodeToString(player1.keyboard.key_thrust) << "\n";
    file << "    key_shoot: " << scancodeToString(player1.keyboard.key_shoot) << "\n";
    file << "  gamepad:\n";
    file << "    button_left: " << buttonToString(player1.gamepad.button_left) << "\n";
    file << "    button_right: " << buttonToString(player1.gamepad.button_right) << "\n";
    file << "    button_thrust: " << buttonToString(player1.gamepad.button_thrust) << "\n";
    file << "    button_shoot: " << buttonToString(player1.gamepad.button_shoot) << "\n";
    file << "  gamepad_name: \"" << player1.gamepad_name << "\"   # Buit = primer disponible\n\n";
}

// Guardar controls del jugador 2 a YAML
static void savePlayer2ControlsToYaml(std::ofstream& file) {
    file << "# CONTROLS JUGADOR 2\n";
    file << "player2:\n";
    file << "  keyboard:\n";
    file << "    key_left: " << scancodeToString(player2.keyboard.key_left) << "\n";
    file << "    key_right: " << scancodeToString(player2.keyboard.key_right) << "\n";
    file << "    key_thrust: " << scancodeToString(player2.keyboard.key_thrust) << "\n";
    file << "    key_shoot: " << scancodeToString(player2.keyboard.key_shoot) << "\n";
    file << "  gamepad:\n";
    file << "    button_left: " << buttonToString(player2.gamepad.button_left) << "\n";
    file << "    button_right: " << buttonToString(player2.gamepad.button_right) << "\n";
    file << "    button_thrust: " << buttonToString(player2.gamepad.button_thrust) << "\n";
    file << "    button_shoot: " << buttonToString(player2.gamepad.button_shoot) << "\n";
    file << "  gamepad_name: \"" << player2.gamepad_name << "\"   # Buit = segon disponible\n\n";
}

// Guardar configuració al fitxer YAML
auto saveToFile() -> bool {
    std::ofstream file(config_file_path);
    if (!file.is_open()) {
        if (console) {
            std::cerr << "No s'ha pogut obrir el fitxer de config per escriure: "
                      << config_file_path << '\n';
        }
        return false;
    }

    // Escriure manualment per controlar format i comentaris
    file << "# Orni Attack - Fitxer de Configuració\n";
    file << "# Auto-generat. Les edicions manuals es preserven si són "
            "vàlides.\n\n";

    file << "version: \"" << Project::VERSION << "\"\n\n";

    file << "# FINESTRA\n";
    file << "window:\n";
    file << "  width: " << window.width << "   # Calculated from zoom_factor\n";
    file << "  height: " << window.height << "   # Calculated from zoom_factor\n";
    file << "  fullscreen: " << (window.fullscreen ? "true" : "false") << "\n";
    file << "  zoom_factor: " << window.zoom_factor << "   # 0.5x-max (0.1 increments)\n\n";

    file << "# FÍSICA (tots els valors en px/s, rad/s, etc.)\n";
    file << "physics:\n";
    file << "  rotation_speed: " << physics.rotation_speed << "   # rad/s\n";
    file << "  acceleration: " << physics.acceleration << "     # px/s²\n";
    file << "  max_velocity: " << physics.max_velocity << "     # px/s\n";
    file << "  friction: " << physics.friction << "            # px/s²\n";
    file << "  enemy_speed: " << physics.enemy_speed
         << "       # unitats/frame\n";
    file << "  bullet_speed: " << physics.bullet_speed
         << "     # unitats/frame\n\n";

    file << "# GAMEPLAY\n";
    file << "gameplay:\n";
    file << "  max_enemies: " << gameplay.max_enemies << "\n";
    file << "  max_bullets: " << gameplay.max_bullets << "\n\n";

    file << "# RENDERITZACIÓ\n";
    file << "rendering:\n";
    file << "  vsync: " << rendering.vsync << "   # 0=disabled, 1=enabled\n\n";

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

    // Guardar controls de jugadors
    savePlayer1ControlsToYaml(file);
    savePlayer2ControlsToYaml(file);

    file.close();

    if (console) {
        std::cout << "Config guardada a: " << config_file_path << '\n';
    }

    return true;
}

}  // namespace Options
