//
// Created by sebastian on 10.02.26.
//

#include "Font.h"

#include <iostream>
#include <stdexcept>

Font::Font(const std::string &fontPath, unsigned int fontSize) {
    if (FT_Init_FreeType(&ft)) throw std::runtime_error("Could not init FreeType");
    if (FT_New_Face(ft, fontPath.c_str(), 0, &face)) throw std::runtime_error("Failed to load font");

    FT_Set_Pixel_Sizes(face, 0, fontSize);

    glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // 1 byte per pixel

    for (unsigned char c = 0; c < 128; c++) {
        if (FT_Load_Char(face, c, FT_LOAD_RENDER)) {
            std::cerr << "Failed to load char: " << (int)c << "\n";
            continue;
        }

        GLuint texture;
        glGenTextures(1, &texture);
        glBindTexture(GL_TEXTURE_2D, texture);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RED,
                     face->glyph->bitmap.width,
                     face->glyph->bitmap.rows,
                     0, GL_RED, GL_UNSIGNED_BYTE,
                     face->glyph->bitmap.buffer);

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

        Character character = {
            texture,
            {face->glyph->bitmap.width, face->glyph->bitmap.rows},
            {face->glyph->bitmap_left, face->glyph->bitmap_top},
            static_cast<unsigned int>(face->glyph->advance.x)
        };
        characters.insert({c, character});
    }

    ascent = static_cast<float>(face->size->metrics.ascender) / 64.0f;
    descent = static_cast<float>(face->size->metrics.descender) / 64.0f;
    lineHeight = static_cast<float>(face->size->metrics.height) / 64.0f;


    FT_Done_Face(face);
    FT_Done_FreeType(ft);
}

float Font::getTextWidth(const std::string &text, float scale) const {
    float width = 0.0f;
    for (char c : text) {
        const Character& ch = getCharacter(c);
        width += static_cast<float>(ch.advance >> 6) *scale;
    }
    return width;
}

Font::Character Font::getCharacter(char c) const {
    unsigned char uc = static_cast<unsigned char>(c);
    auto it = characters.find(uc);
    if (it != characters.end())
        return it->second;
    else
        throw std::runtime_error("Character not loaded: " + std::to_string(uc));
}
