//
// Created by sebastian on 11.02.26.
//

#include "TextRenderer.h"

#include "../core/Application.h"
#include "../core/Window.h"
#include "../core/gui/text/Font.h"
#include "glm/ext/matrix_clip_space.hpp"

void TextRenderer::renderTexts(const std::vector<UiText*> &textsToRender) {
    shader.start();
    shader.loadProjectionMatrix(calculateOrthographicProjectionMatrix());
    glEnable(GL_BLEND);
    glDisable(GL_DEPTH_TEST);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    for (const auto &text : textsToRender) {
        renderText(*text);
    }
    glEnable(GL_DEPTH_TEST);
    glDisable(GL_BLEND);
    shader.stop();
}

void TextRenderer::renderText(const UiText &textToRender)  {
    const Dimensions& d = textToRender.uiPositioner.screenSpace;

    const Font& font = textToRender.getFont();
    const std::string& text = textToRender.getText();

    float screenX = d.x * Application::getInstance().getWindow().GetWidth();
    float screenY = (1.f - d.y) * Application::getInstance().getWindow().GetHeight();

    float x = screenX;
    float y = screenY - font.getLineHeight();

    float scale = 1.0f;
    shader.loadTextColor(textToRender.getColor());
    for (char c : text) {
        const Font::Character& ch = font.getCharacter(c);

        float xpos = x + static_cast<float>(ch.bearing.x) * scale;
        float ypos = y - static_cast<float>(ch.size.y - ch.bearing.y) * scale;

        float w = static_cast<float>(ch.size.x) * scale;
        float h = static_cast<float>(ch.size.y) * scale;

        float vertices[6][4] = {
            { xpos,     ypos + h,   0.0f, 0.0f },
            { xpos,     ypos,       0.0f, 1.0f },
            { xpos + w, ypos,       1.0f, 1.0f },

            { xpos,     ypos + h,   0.0f, 0.0f },
            { xpos + w, ypos,       1.0f, 1.0f },
            { xpos + w, ypos + h,   1.0f, 0.0f }
        };

        glBindVertexArray(textModel.vaoID);
        glEnableVertexAttribArray(0);

        glBindTexture(GL_TEXTURE_2D, ch.textureID);


        glBindBuffer(GL_ARRAY_BUFFER, textModel.vboID);
        glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);

        glDrawArrays(GL_TRIANGLES, 0, 6);

        x+= static_cast<float>(ch.advance >> 6) * scale;

        glBindVertexArray(0);
        glDisableVertexAttribArray(0);
    }
}

glm::mat4 TextRenderer::calculateOrthographicProjectionMatrix() {
    const auto screenWidth = static_cast<float>(Application::getInstance().getWindow().GetWidth());
    const auto screenHeight = static_cast<float>(Application::getInstance().getWindow().GetHeight());

    const glm::mat4 projectionMat = glm::ortho(0.f, screenWidth, 0.0f, screenHeight);
    return projectionMat;
}
