// vector_text.cpp - Implementació del sistema de text vectorial
// © 2025 Port a C++20 amb SDL3

#include "core/graphics/vector_text.hpp"

#include <iostream>

#include "core/graphics/shape_loader.hpp"
#include "core/rendering/shape_renderer.hpp"

namespace Graphics {

// Constants per a mides base dels caràcters
constexpr float char_width = 20.0F;   // Amplada base del caràcter
constexpr float char_height = 40.0F;  // Altura base del caràcter

VectorText::VectorText(SDL_Renderer* renderer)
    : renderer_(renderer) {
    load_charset();
}

void VectorText::load_charset() {
    // Cargar dígitos 0-9
    for (char c = '0'; c <= '9'; c++) {
        std::string filename = get_shape_filename(c);
        auto shape = ShapeLoader::load(filename);

        if (shape && shape->es_valida()) {
            chars_[c] = shape;
        } else {
            std::cerr << "[VectorText] Warning: no s'ha pogut carregar " << filename
                      << std::endl;
        }
    }

    // Cargar lletres A-Z (majúscules)
    for (char c = 'A'; c <= 'Z'; c++) {
        std::string filename = get_shape_filename(c);
        auto shape = ShapeLoader::load(filename);

        if (shape && shape->es_valida()) {
            chars_[c] = shape;
        } else {
            std::cerr << "[VectorText] Warning: no s'ha pogut carregar " << filename
                      << std::endl;
        }
    }

    // Cargar símbolos
    const std::string symbols[] = {".", ",", "-", ":", "!", "?"};
    for (const auto& sym : symbols) {
        char c = sym[0];
        std::string filename = get_shape_filename(c);
        auto shape = ShapeLoader::load(filename);

        if (shape && shape->es_valida()) {
            chars_[c] = shape;
        } else {
            std::cerr << "[VectorText] Warning: no s'ha pogut carregar " << filename
                      << std::endl;
        }
    }

    // Cargar símbolo de copyright (©) - UTF-8 U+00A9
    // Usem el segon byte (0xA9) com a key interna
    {
        char c = '\xA9';  // 169 decimal
        std::string filename = "font/char_copyright.shp";
        auto shape = ShapeLoader::load(filename);

        if (shape && shape->es_valida()) {
            chars_[c] = shape;
        } else {
            std::cerr << "[VectorText] Warning: no s'ha pogut carregar " << filename
                      << std::endl;
        }
    }

    std::cout << "[VectorText] Carregats " << chars_.size() << " caràcters"
              << std::endl;
}

std::string VectorText::get_shape_filename(char c) const {
    // Mapeo carácter → nombre de archivo (amb prefix "font/")
    switch (c) {
        case '0':
        case '1':
        case '2':
        case '3':
        case '4':
        case '5':
        case '6':
        case '7':
        case '8':
        case '9':
            return std::string("font/char_") + c + ".shp";

        // Lletres majúscules A-Z
        case 'A':
        case 'B':
        case 'C':
        case 'D':
        case 'E':
        case 'F':
        case 'G':
        case 'H':
        case 'I':
        case 'J':
        case 'K':
        case 'L':
        case 'M':
        case 'N':
        case 'O':
        case 'P':
        case 'Q':
        case 'R':
        case 'S':
        case 'T':
        case 'U':
        case 'V':
        case 'W':
        case 'X':
        case 'Y':
        case 'Z':
            return std::string("font/char_") + c + ".shp";

        // Lletres minúscules a-z (convertir a majúscules)
        case 'a':
        case 'b':
        case 'c':
        case 'd':
        case 'e':
        case 'f':
        case 'g':
        case 'h':
        case 'i':
        case 'j':
        case 'k':
        case 'l':
        case 'm':
        case 'n':
        case 'o':
        case 'p':
        case 'q':
        case 'r':
        case 's':
        case 't':
        case 'u':
        case 'v':
        case 'w':
        case 'x':
        case 'y':
        case 'z':
            return std::string("font/char_") + char(c - 32) + ".shp";

        // Símbols
        case '.':
            return "font/char_dot.shp";
        case ',':
            return "font/char_comma.shp";
        case '-':
            return "font/char_minus.shp";
        case ':':
            return "font/char_colon.shp";
        case '!':
            return "font/char_exclamation.shp";
        case '?':
            return "font/char_question.shp";
        case ' ':
            return "";  // Espai es maneja sense carregar shape

        case '\xA9':  // Copyright symbol (©) - UTF-8 U+00A9
            return "font/char_copyright.shp";

        default:
            return "";  // Caràcter no suportat
    }
}

bool VectorText::is_supported(char c) const {
    return chars_.contains(c);
}

void VectorText::render(const std::string& text, const Punt& posicio, float escala, float spacing, float brightness) {
    if (renderer_ == nullptr) {
        return;
    }

    // Ancho de un carácter base (20 px a escala 1.0)
    const float char_width_scaled = char_width * escala;

    // Spacing escalado
    const float spacing_scaled = spacing * escala;

    // Altura de un carácter escalado (necesario para ajustar Y)
    const float char_height_scaled = char_height * escala;

    // Posición X del borde izquierdo del carácter actual
    // (se ajustará +char_width/2 para obtener el centro al renderizar)
    float current_x = posicio.x;

    // Iterar sobre cada byte del string (con detecció UTF-8)
    for (size_t i = 0; i < text.length(); i++) {
        auto c = static_cast<unsigned char>(text[i]);

        // Detectar copyright UTF-8 (0xC2 0xA9)
        if (c == 0xC2 && i + 1 < text.length() &&
            static_cast<unsigned char>(text[i + 1]) == 0xA9) {
            c = 0xA9;  // Usar segon byte com a key
            i++;       // Saltar el següent byte
        }

        // Manejar espacios (avanzar sin dibujar)
        if (c == ' ') {
            current_x += char_width_scaled + spacing_scaled;
            continue;
        }

        // Verificar si el carácter está soportado
        auto it = chars_.find(c);
        if (it != chars_.end()) {
            // Renderizar carácter
            // Ajustar X e Y para que posicio represente esquina superior izquierda
            // (render_shape espera el centro, así que sumamos la mitad de ancho y altura)
            Punt char_pos = {.x = current_x + (char_width_scaled / 2.0F), .y = posicio.y + (char_height_scaled / 2.0F)};
            Rendering::render_shape(renderer_, it->second, char_pos, 0.0F, escala, true, 1.0F, brightness);

            // Avanzar posición
            current_x += char_width_scaled + spacing_scaled;
        } else {
            // Carácter no soportado: saltar (o renderizar '?' en el futuro)
            std::cerr << "[VectorText] Warning: caràcter no suportat '" << c << "'"
                      << std::endl;
            current_x += char_width_scaled + spacing_scaled;
        }
    }
}

void VectorText::render_centered(const std::string& text, const Punt& centre_punt, float escala, float spacing, float brightness) {
    // Calcular dimensions del text
    float text_width = get_text_width(text, escala, spacing);
    float text_height = get_text_height(escala);

    // Calcular posició de l'esquina superior esquerra
    // restant la meitat de les dimensions del punt central
    Punt posicio_esquerra = {
        .x = centre_punt.x - (text_width / 2.0F),
        .y = centre_punt.y - (text_height / 2.0F)};

    // Delegar al mètode render() existent
    render(text, posicio_esquerra, escala, spacing, brightness);
}

float VectorText::get_text_width(const std::string& text, float escala, float spacing) const {
    if (text.empty()) {
        return 0.0F;
    }

    const float char_width_scaled = char_width * escala;
    const float spacing_scaled = spacing * escala;

    // Contar caracteres visuals (no bytes) - manejar UTF-8
    size_t visual_chars = 0;
    for (size_t i = 0; i < text.length(); i++) {
        auto c = static_cast<unsigned char>(text[i]);

        // Detectar copyright UTF-8 (0xC2 0xA9) - igual que render()
        if (c == 0xC2 && i + 1 < text.length() &&
            static_cast<unsigned char>(text[i + 1]) == 0xA9) {
            visual_chars++;  // Un caràcter visual (©)
            i++;             // Saltar el següent byte
        } else {
            visual_chars++;  // Caràcter normal
        }
    }

    // Ancho total = todos los caracteres VISUALES + spacing entre ellos
    return (visual_chars * char_width_scaled) + ((visual_chars - 1) * spacing_scaled);
}

float VectorText::get_text_height(float escala) const {
    return char_height * escala;
}

}  // namespace Graphics
