/**
 * @file font_manager.c
 * @author Piotr Krygier (piotrkrygier@everyonencancode.xyz)
 * @brief Font manager. Load fonts from file and render it on the scene
 * @version 0.1
 * @date 2025-10-08
 *
 * @copyright Copyright (c) 2025
 *
 */

#include "font_manager.h"

#include <SDL3/SDL_log.h>
#include <assert.h>
#include <cglm/types.h>
#include <ft2build.h>
#include <freetype/freetype.h>
#include <freetype/fttypes.h>
#include <stdint.h>
#include <string.h>
#include <vulkan/vulkan_core.h>

#include "freetype/freetype.h"
#include "graphics_context.h"
#include "mesh_controller.h"
#include "src/vulkan_commons.h"
#include "utilities/commons.h"
#include "utilities/errors_common.h"
#include "utilities/file_utils.h"
#include "vulkan_image.h"

#define FONTS_START_CHARACTER_CODE (33U)

FT_Library g_font_library = NULL;
FT_Face g_font_faces[FONTS_MAX_COUNT] = {NULL};
size_t g_font_free_index = 0U;

rse_err_t fonts_init(void)
{
    FT_Error error = FT_Err_Ok;

    error = FT_Init_FreeType(&g_font_library);

    if (error != FT_Err_Ok) {
        SDL_LogCritical(SDL_LOG_CATEGORY_APPLICATION, "Failed to initialize FreeType2. Error code: %d", error);
        return RSE_ERROR_INTERNAL_ERROR;
    }

    return RSE_ERROR_NO_ERROR;
}

rse_err_t fonts_load_from_file(struct graphics_context_t* context, const char* file_path, rse_id_t* font_id)
{
    FT_Error error = FT_Err_Ok;
    rse_err_t ret = RSE_ERROR_NO_ERROR;
    char real_path[MAX_PATH_LENGTH] = {0};

    assert(context != NULL);
    assert(file_path != NULL);
    assert(font_id != NULL);
    assert(g_font_library != NULL);
    assert(g_font_free_index < FONTS_MAX_COUNT);

    strncpy(real_path, file_path, MAX_PATH_LENGTH);

    if ((ret = file_append_full_path(real_path, MAX_PATH_LENGTH)) != RSE_ERROR_NO_ERROR) {
        return ret;
    }

    error = FT_New_Face(g_font_library, real_path, 0, &g_font_faces[g_font_free_index]);
    if (error != FT_Err_Ok) {
        SDL_LogCritical(SDL_LOG_CATEGORY_APPLICATION, "Failed to load new font face. Error code: %d", error);
        return RSE_ERROR_INTERNAL_ERROR;
    }

    *font_id = g_font_free_index++;

    return RSE_ERROR_NO_ERROR;
}

rse_err_t fonts_set_font_size(struct graphics_context_t* context, const rse_id_t font_id, const uint32_t font_size)
{
    rse_err_t status = RSE_ERROR_NO_ERROR;
    // size_t iter = 0U;
    FT_UInt glyph_index = 0U;
    FT_Error error = FT_Err_Ok;
    FT_GlyphSlot glyph = NULL;
    struct vertex_t vertices[4] = {0};
    uint16_t indices[] = {0, 1, 2, 2, 3, 0};
    struct sized_font_data_t* font = NULL;

    assert(context != NULL);
    assert(font_id < FONTS_MAX_COUNT);
    assert(g_font_faces[font_id] != NULL);

    error = FT_Set_Pixel_Sizes(g_font_faces[font_id], 0, font_size);

    if (error != FT_Err_Ok) {
        SDL_LogCritical(SDL_LOG_CATEGORY_APPLICATION, "Failed to set font size. Error code: %d", error);
        return RSE_ERROR_INTERNAL_ERROR;
    }

    font = &context->fonts_data.fonts[font_id];
    font->font_size = font_size;

    // for (iter = 0U; iter < FONT_CHARACTERS_COUNT; ++iter) {
    // glyph_index = iter + FONTS_START_CHARACTER_CODE;
    glyph_index = 33 + FONTS_START_CHARACTER_CODE;

    error = FT_Load_Char(g_font_faces[font_id], glyph_index, FT_LOAD_RENDER);
    if (error != FT_Err_Ok) {
        SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
                    "Failed to load glyph with id %d. Error code: %d",
                    glyph_index,
                    error);
        // continue;
        return RSE_ERROR_INTERNAL_ERROR;
    }

    glyph = g_font_faces[font_id]->glyph;
    STATUS_CHECK(load_texture_from_bitmat(context,
                                          glyph->bitmap.buffer,
                                          glyph->bitmap.width,
                                          glyph->bitmap.rows,
                                          &font->font_characters[33].texture_id,
                                          VK_FORMAT_R8_UNORM));

    vertices[0].pos[0] = 0.0 - glyph->bitmap.width;
    vertices[0].pos[1] = glyph->bitmap.rows;
    vertices[0].pos[2] = 0.0;
    vertices[0].color[0] = 1.0;
    vertices[0].color[1] = 1.0;
    vertices[0].color[2] = 1.0;
    vertices[0].tex_coords[0] = 0.0;
    vertices[0].tex_coords[1] = 1.0;

    vertices[1].pos[0] = glyph->bitmap.width;
    vertices[1].pos[1] = glyph->bitmap.rows;
    vertices[1].pos[2] = 0.0;
    vertices[1].color[0] = 1.0;
    vertices[1].color[1] = 1.0;
    vertices[1].color[2] = 1.0;
    vertices[1].tex_coords[0] = 1.0;
    vertices[1].tex_coords[1] = 1.0;

    vertices[2].pos[0] = glyph->bitmap.width;
    vertices[2].pos[1] = 0.0 - glyph->bitmap.rows;
    vertices[2].pos[2] = 0.0;
    vertices[2].color[0] = 1.0;
    vertices[2].color[1] = 1.0;
    vertices[2].color[2] = 1.0;
    vertices[2].tex_coords[0] = 1.0;
    vertices[2].tex_coords[1] = 0.0;

    vertices[3].pos[0] = 0.0 - glyph->bitmap.width;
    vertices[3].pos[1] = 0.0 - glyph->bitmap.rows;
    vertices[3].pos[2] = 0.0;
    vertices[3].color[0] = 1.0;
    vertices[3].color[1] = 1.0;
    vertices[3].color[2] = 1.0;
    vertices[3].tex_coords[0] = 0.0;
    vertices[3].tex_coords[1] = 0.0;

    STATUS_CHECK(mesh_create(context, vertices, indices, 4, 6, &font->font_characters[33].mesh_id));
    // }

    return RSE_ERROR_NO_ERROR;
}

rse_err_t print_debug_text(struct graphics_context_t* context, rse_id_t font_id, char* text)
{
    rse_err_t status = RSE_ERROR_NO_ERROR;
    (void)text;

    STATUS_CHECK(mesh_create_instance(
        context,
        context->fonts_data.fonts[font_id].font_characters[33].mesh_id,
        (struct instance_data_t){{0.0f, 0.0f, 2.4f},
                                 {0.0f, 0.0f, 0.0},
                                 1.0f,
                                 context->fonts_data.fonts[font_id].font_characters[33].texture_id}));

    return status;
}
// rse_err_t print_debug_text(struct graphics_context_t* context, char* text)
// {
//     rse_err_t status = RSE_ERROR_NO_ERROR;
//     size_t width, height;
//     size_t iter = 0U;
//     int number_of_quads = 0;
//     char buffer[99999] = {0};
//     float *v0, *v2 = NULL;
//
//     int min_x, min_y, max_x, max_y = 0;
//     int yy, xx;
//
//     width = context->swapchain_data.swapchain_extent.width;
//     height = context->swapchain_data.swapchain_extent.height;
//
//     context->debug_overlay.pixels_size = width * height * sizeof(uint32_t);
//
//     rse_memset(context->debug_overlay.pixels, 0, context->debug_overlay.pixels_size);
//
//     number_of_quads = stb_easy_font_print(10.0, 20.0, text, NULL, (void*)buffer, sizeof(buffer));
//
//     for (iter = 0U; iter < number_of_quads * 4; ++iter) {
//         v0 = (float*)&buffer[iter * 16 + 0];
//         v2 = (float*)&buffer[iter * 16 + 32];
//
//         min_x = v0[0];
//         min_y = v0[1];
//         max_x = v2[0];
//         max_y = v2[1];
//
//         for (yy = min_y; yy < max_y; ++yy) {
//             for (xx = min_x; xx < max_x; ++xx) {
//                 if (xx >= 0 && yy >= 0 && xx < (int)width && yy < (int)height) {
//                     context->debug_overlay.pixels[yy * width + xx] = 0xFFFFFFFF;  // RGBA white
//                 }
//             }
//         }
//     }
//
//     STATUS_CHECK(texture_update_image(context, (unsigned char*)context->debug_overlay.pixels, width, height,
//     context->debug_overlay.texture_id, VK_FORMAT_R8G8B8A8_UNORM));
//
//     return RSE_ERROR_NO_ERROR;
// }
