#include "core/locale/locale.hpp"

#include <fstream>
#include <iostream>
#include <sstream>
#include <string>

#include "external/fkyaml_node.hpp"  // Para fkyaml::node

// [SINGLETON]
Locale* Locale::instance = nullptr;

// [SINGLETON] Crea el objeto con esta función estática
void Locale::init(const std::string& file_path) {
    Locale::instance = new Locale();
    Locale::instance->loadFromFile(file_path);
}

// [SINGLETON] Crea el objeto desde contenido en memoria (para release con pack)
void Locale::initFromContent(const std::string& content) {
    Locale::instance = new Locale();
    Locale::instance->loadFromContent(content);
}

// [SINGLETON] Destruye el objeto con esta función estática
void Locale::destroy() {
    delete Locale::instance;
    Locale::instance = nullptr;
}

// [SINGLETON] Con este método obtenemos el objeto y podemos trabajar con él
auto Locale::get() -> Locale* {
    return Locale::instance;
}

// Devuelve la traducción de la clave o la clave como fallback
auto Locale::get(const std::string& key) const -> std::string {
    auto it = strings_.find(key);
    if (it != strings_.end()) {
        return it->second;
    }

    std::cerr << "Locale: clave no encontrada: " << key << '\n';
    return key;
}

// Aplana un nodo YAML de forma recursiva: {a: {b: "val"}} -> {"a.b" -> "val"}
void Locale::flatten(const void* node_ptr, const std::string& prefix) {
    const auto& node = *static_cast<const fkyaml::node*>(node_ptr);

    for (auto itr = node.begin(); itr != node.end(); ++itr) {
        const std::string KEY = prefix.empty()
            ? itr.key().get_value<std::string>()
            : prefix + "." + itr.key().get_value<std::string>();

        const auto& value = itr.value();
        if (value.is_mapping()) {
            flatten(&value, KEY);
        } else if (value.is_string()) {
            strings_[KEY] = value.get_value<std::string>();
        }
    }
}

// Carga las traducciones desde contenido YAML en memoria
void Locale::loadFromContent(const std::string& content) {
    if (content.empty()) {
        std::cerr << "Locale: contenido vacío, sin traducciones cargadas\n";
        return;
    }

    try {
        std::istringstream stream(content);
        auto yaml = fkyaml::node::deserialize(stream);
        flatten(&yaml, "");

        std::cout << "Locale: " << strings_.size() << " traducciones cargadas desde pack\n";
    } catch (const fkyaml::exception& e) {
        std::cerr << "Locale: error al parsear YAML: " << e.what() << '\n';
    }
}

// Carga las traducciones desde el fichero YAML indicado
void Locale::loadFromFile(const std::string& file_path) {
    if (file_path.empty()) {
        std::cerr << "Locale: ruta de fichero vacía, sin traducciones cargadas\n";
        return;
    }

    std::ifstream file(file_path);
    if (!file.is_open()) {
        std::cerr << "Locale: no se puede abrir " << file_path << '\n';
        return;
    }

    try {
        auto yaml = fkyaml::node::deserialize(file);
        flatten(&yaml, "");

        std::cout << "Locale: " << strings_.size() << " traducciones cargadas desde " << file_path << '\n';
    } catch (const fkyaml::exception& e) {
        std::cerr << "Locale: error al parsear YAML: " << e.what() << '\n';
    }
}
