#include "options.h"
#include "const.h"
#include "screen.h"
#include <fstream>  // Para basic_ofstream, basic_ifstream
#include <iostream> // Para basic_ostream, operator<<, cout

// Variables
Options options;

bool setOptions(const std::string &var, const std::string &value);

// Crea e inicializa las opciones del programa
void initOptions()
{
    options = Options();

#ifdef DEBUG
    options.section = SectionState(Section::TITLE, Subsection::NONE);
    options.console = true;
#else
    options.section = SectionState(Section::LOGO, Subsection::LOGO_TO_INTRO);
    options.console = false;
#endif
}

// Carga las opciones desde un fichero
bool loadOptionsFromFile(const std::string &file_path)
{
    // Indicador de éxito en la carga
    bool success = true;

    // Versión actual del fichero
    const std::string configVersion = options.version;
    options.version = "";

    // Variables para manejar el fichero
    std::string line;
    std::ifstream file(file_path);

    // Si el fichero se puede abrir
    if (file.good())
    {
        // Procesa el fichero linea a linea
        if (options.console)
        {
            std::cout << "Reading file config.txt\n";
        }
        while (std::getline(file, line))
        {
            // Comprueba que la linea no sea un comentario
            if (line.substr(0, 1) != "#")
            {
                // Encuentra la posición del caracter '='
                int pos = line.find("=");
                // Procesa las dos subcadenas
                if (!setOptions(line.substr(0, pos), line.substr(pos + 1, line.length())))
                {
                    if (options.console)
                    {
                        std::cout << "Warning: file config.txt\n";
                        std::cout << "unknown parameter " << line.substr(0, pos).c_str() << std::endl;
                    }
                    success = false;
                }
            }
        }

        // Cierra el fichero
        if (options.console)
        {
            std::cout << "Closing file config.txt\n\n";
        }
        file.close();
    }

    // El fichero no existe
    else
    {
        // Crea el fichero con los valores por defecto
        saveOptionsToFile(file_path);
    }

    // Si la versión de fichero no coincide, crea un fichero nuevo con los valores por defecto
    if (configVersion != options.version)
    {
        initOptions();
        saveOptionsToFile(file_path);
    }

    // Normaliza los valores
    if (options.video.mode != 0 &&
        options.video.mode != SDL_WINDOW_FULLSCREEN &&
        options.video.mode != SDL_WINDOW_FULLSCREEN_DESKTOP)
    {
        options.video.mode = 0;
    }

    return success;
}

// Guarda las opciones en un fichero
bool saveOptionsToFile(const std::string &file_path)
{
    // Crea y abre el fichero de texto
    std::ofstream file(file_path);
    bool success = file.is_open(); // Verifica si el archivo se abrió correctamente

    if (!success) // Si no se pudo abrir el archivo, muestra un mensaje de error y devuelve false
    {
        if (options.console)
        {
            std::cerr << "Error: Unable to open file " << file_path << " for writing." << std::endl;
        }
        return false;
    }

    if (options.console)
    {
        std::cout << file_path << " open for writing" << std::endl;
    }

    // Escribe en el fichero
    file << "version=" << options.version << "\n";

    file << "\n## CONTROL\n";
    file << "keys=" << static_cast<int>(options.keys) << "\n";

    file << "\n## WINDOW\n";
    file << "window.zoom=" << options.window.zoom << "\n";

    file << "\n## VIDEO\n";
    file << "video.mode=" << options.video.mode << "\n";
    file << "video.filter=" << static_cast<int>(options.video.filter) << "\n";
    file << "video.shaders=" << boolToString(options.video.shaders) << "\n";
    file << "video.vertical_sync=" << boolToString(options.video.vertical_sync) << "\n";
    file << "video.integer_scale=" << boolToString(options.video.integer_scale) << "\n";
    file << "video.keep_aspect=" << boolToString(options.video.keep_aspect) << "\n";
    file << "video.border.enabled=" << boolToString(options.video.border.enabled) << "\n";
    file << "video.border.width=" << options.video.border.width << "\n";
    file << "video.border.height=" << options.video.border.height << "\n";
    file << "video.palette=" << static_cast<int>(options.video.palette) << "\n";

    // Cierra el fichero
    file.close();

    return success;
}

// Establece las opciones
bool setOptions(const std::string &var, const std::string &value) {
    static const std::unordered_map<std::string, std::function<void(std::string)>> optionHandlers = {
        {"version", [](std::string v) { options.version = v; }},
        {"keys", [](std::string v) { options.keys = static_cast<ControlScheme>(safeStoi(v, static_cast<int>(ControlScheme::CURSOR))); }},
        {"video.mode", [](std::string v) { options.video.mode = safeStoi(v, 0); }},
        {"window.zoom", [](std::string v) { options.window.zoom = safeStoi(v, 1); }},
        {"video.shaders", [](std::string v) { options.video.shaders = stringToBool(v); }},
        {"video.vertical_sync", [](std::string v) { options.video.vertical_sync = stringToBool(v); }},
        {"video.integer_scale", [](std::string v) { options.video.integer_scale = stringToBool(v); }},
        {"video.keep_aspect", [](std::string v) { options.video.keep_aspect = stringToBool(v); }},
        {"video.border.enabled", [](std::string v) { options.video.border.enabled = stringToBool(v); }},
        {"video.border.width", [](std::string v) { options.video.border.width = safeStoi(v, 32); }},
        {"video.border.height", [](std::string v) { options.video.border.height = safeStoi(v, 24); }},
        {"video.palette", [](std::string v) { options.video.palette = static_cast<Palette>(safeStoi(v, static_cast<int>(DEFAULT_PALETTE))); }}
    };
    
    auto it = optionHandlers.find(var);
    if (it != optionHandlers.end()) {
        it->second(value);
        return true;
    }
    return false;
}