// vector_text.cpp - Implementació del sistema de text vectorial
// © 2026 JailDesigner

#include "core/graphics/vector_text.hpp"

#include <iostream>

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

namespace Graphics {

    // Constants para mides base dels caràcters
    constexpr float BASE_CHAR_WIDTH = 20.0F;   // Amplada base del caràcter
    constexpr float BASE_CHAR_HEIGHT = 40.0F;  // Altura base del caràcter

    VectorText::VectorText(Rendering::Renderer* renderer)
        : renderer_(renderer) {
        loadCharset();
    }

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

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

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

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

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

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

        // Cargar símbolo de copyright (©) - UTF-8 U+00A9.
        // Usamos el segundo byte (0xA9, 169 decimal) como key interna del map.
        {
            const std::string FILENAME = "font/char_copyright.shp";
            auto shape = ShapeLoader::load(FILENAME);

            if (shape && shape->isValid()) {
                chars_['\xA9'] = shape;
            } else {
                std::cerr << "[VectorText] Warning: no s'ha pogut load " << FILENAME
                          << '\n';
            }
        }

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

    auto VectorText::getShapeFilename(char c) -> std::string {
        // Mapeo carácter → nombre de archivo (con prefix "font/").
        // Dígitos 0-9 y mayúsculas A-Z comparten el mismo path: la shape se llama
        // como el caracter mismo, así que se agrupan en un único case.
        switch (c) {
            case '0':
            case '1':
            case '2':
            case '3':
            case '4':
            case '5':
            case '6':
            case '7':
            case '8':
            case '9':
            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 sin load shape

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

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

    auto VectorText::isSupported(char c) const -> bool {
        return chars_.contains(c);
    }

    void VectorText::render(const std::string& text, const Vec2& position, float scale, float spacing, float brightness, SDL_Color color) const {
        if (renderer_ == nullptr) {
            return;
        }

        // Ancho de un carácter base (20 px a scale 1.0)
        const float CHAR_WIDTH_SCALED = BASE_CHAR_WIDTH * scale;

        // Spacing escalado
        const float SPACING_SCALED = spacing * scale;

        // Altura de un carácter escalado (necesario para ajustar Y)
        const float CHAR_HEIGHT_SCALED = BASE_CHAR_HEIGHT * scale;

        // Posición X del borde izquierdo del carácter actual
        // (se ajustará +BASE_CHAR_WIDTH/2 para obtener el centro al renderizar)
        float current_x = position.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 como 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 position represente esquina superior izquierda
                // (render_shape espera el centro, así que sumamos la mitad de ancho y altura)
                Vec2 char_pos = {.x = current_x + (CHAR_WIDTH_SCALED / 2.0F), .y = position.y + (CHAR_HEIGHT_SCALED / 2.0F)};
                // Text opt-out del glow: HUD/marker s'ha de mantenir net.
                Rendering::renderShape(renderer_, it->second, char_pos, 0.0F, scale, 1.0F, brightness, color, 0.0F, 1.0F, /*glow=*/false);

                // 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 << "'"
                          << '\n';
                current_x += CHAR_WIDTH_SCALED + SPACING_SCALED;
            }
        }
    }

    void VectorText::renderCentered(const std::string& text, const Vec2& centre_punt, float scale, float spacing, float brightness, SDL_Color color) const {
        // Calcular dimensions del text
        float text_width = getTextWidth(text, scale, spacing);
        float text_height = getTextHeight(scale);

        // Calcular posición de l'esquina superior izquierda
        // restant la meitat de las dimensions del point central
        Vec2 posicio_esquerra = {
            .x = centre_punt.x - (text_width / 2.0F),
            .y = centre_punt.y - (text_height / 2.0F)};

        // Delegar al método render() existent
        render(text, posicio_esquerra, scale, spacing, brightness, color);
    }

    auto VectorText::getTextWidth(const std::string& text, float scale, float spacing) -> float {
        if (text.empty()) {
            return 0.0F;
        }

        const float CHAR_WIDTH_SCALED = BASE_CHAR_WIDTH * scale;
        const float SPACING_SCALED = spacing * scale;

        // 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);
    }

    auto VectorText::getTextHeight(float scale) -> float {
        return BASE_CHAR_HEIGHT * scale;
    }

}  // namespace Graphics
