#include "lang.h"
#include <fstream>
#include <unordered_map>
#include "external/json.hpp"
#include "options.h"
#include "asset.h"

using json = nlohmann::json;

namespace Lang
{
    std::unordered_map<std::string, std::string> texts;

    // Vector con los idiomas soportados
    std::vector<Language> languages = {
        {Code::SPANISH, "Castellano", "es_ES.json"},
        {Code::VALENCIAN, "Balooncia", "ba_BA.json"},
        {Code::ENGLISH, "Ingles", "en_UK.json"}};

    // Inicializa los textos del juego en el idioma seleccionado
    bool loadFromFile(const std::string &file_path)
    {
        texts.clear();

        std::ifstream rfile(file_path);
        if (!rfile.is_open())
            return false;

        try
        {
            json j;
            rfile >> j;

            for (auto &el : j.items())
            {
                texts[el.key()] = el.value();
            }
        }
        catch (const std::exception &e)
        {
            // Puedes loguear el error si quieres
            return false;
        }

        return true;
    }

    // Obtiene el texto por clave
    std::string getText(const std::string &key)
    {
        auto it = texts.find(key);
        if (it != texts.end())
            return it->second;
        else
            return "[missing text: " + key + "]";
    }

    // Obtiene el código del siguiente idioma disponible
    Code getNextLangCode(Code lang)
    {
        for (size_t i = 0; i < languages.size(); ++i)
        {
            if (languages[i].code == lang)
            {
                return languages[(i + 1) % languages.size()].code;
            }
        }
        // Si no se encuentra, devuelve el primero por defecto
        return languages[0].code;
    }

    // Obtiene un idioma del vector de idiomas a partir de un código
    Language getLanguage(Code code)
    {
        for (const auto &lang : languages)
        {
            if (lang.code == code)
                return lang;
        }
        // Si no se encuentra, devuelve el primero por defecto
        return languages[0];
    }

    // Devuelve el código de un idioma a partir de un nombre
    Code getCodeFromName(const std::string& name)
    {
        for (const auto& lang : languages)
        {
            if (lang.name == name)
                return lang.code;
        }
        // Si no se encuentra, devuelve el primero por defecto
        return languages[0].code;
    }

    // Devuelve el nombre de un idioma a partir de un código
    std::string getNameFromCode(Code code)
    {
        for (const auto& lang : languages)
        {
            if (lang.code == code)
                return lang.name;
        }
        // Si no se encuentra, devuelve el nombre del primer idioma por defecto
        return languages[0].name;
    }

    // Actualiza los nombres de los idiomas
    void updateLanguageNames()
    {
        for (auto &lang : languages)
        {
            switch (lang.code)
            {
            case Code::SPANISH:
                lang.name = Lang::getText("[SERVICE_MENU] LANG_ES");
                break;
            case Code::VALENCIAN:
                lang.name = Lang::getText("[SERVICE_MENU] LANG_BA");
                break;
            case Code::ENGLISH:
                lang.name = Lang::getText("[SERVICE_MENU] LANG_EN");
                break;
            default:
                lang.name = "Unknown";
                break;
            }
        }
    }

    // Actualiza los nombres de las dificultades
    void updateDifficultyNames()
    {
        for (auto &difficulty : Options::difficulties)
        {
            switch (difficulty.code)
            {
            case Options::DifficultyCode::EASY:
                difficulty.name = Lang::getText("[SERVICE_MENU] EASY");
                break;
            case Options::DifficultyCode::NORMAL:
                difficulty.name = Lang::getText("[SERVICE_MENU] NORMAL");
                break;
            case Options::DifficultyCode::HARD:
                difficulty.name = Lang::getText("[SERVICE_MENU] HARD");
                break;
            default:
                difficulty.name = "Unknown";
                break;
            }
        }
    }

     // Obtiene una fichero a partir de un lang::Code
    std::string getLanguageFileName(Lang::Code code)
    {
        for (const auto &lang : languages)
        {
            if (lang.code == code)
                return Asset::get()->get(lang.file_name);
        }
        // Si no se encuentra, devuelve el fichero del primer idioma por defecto
        return Asset::get()->get(languages[0].file_name);
    }

    // Establece el idioma
    void setLanguage(Code lang)
    {
        Options::settings.language = lang;
        loadFromFile(Asset::get()->get(getLanguage(lang).file_name));
        updateLanguageNames();
        updateDifficultyNames();
    }
}
