//
// Created by sasha on 27.11.2025.
//

#include "text.h"

#include <sys/stat.h>
#include <unistd.h>
#include <format>
#include <functional>
#include <filesystem>

#include "engine/engine.h"

Text::Text(IWidget *parent, float x, float y, const std::string &fontName, float ptsize,
           SDL_Color color, SDL_Color bgColor, TextRenderMode renderMode, bool cached) : IWidget(parent, x, y,0,0){

    this->fontName = fontName;
    this->ptsize = ptsize;
    this->color = color;
    this->renderMode = renderMode;
    this->cached = cached;
    this->texture = nullptr;
}


Text::~Text() {
    if (texture) SDL_DestroyTexture(texture);
}

void Text::setText(const std::string &text,
                   const std::string &fontName,
                   float ptsize,
                   SDL_Color color,
                   SDL_Color bgColor,
                   TextRenderMode renderMode
) {
    this->fontName = fontName;
    this->ptsize = ptsize;
    this->color = color;
    this->renderMode = renderMode;

    setText(text);
}

void Text::setText(const std::string &text) {
    if (fontName.empty()) return;

    SDL_Surface *surface;

#if defined(__ANDROID__)
    std::filesystem::create_directory(std::format("{}/surface_text/",SDL_GetAndroidCachePath()));
#else
#endif

    std::hash<std::string> hasher;
    std::string color_str = std::format("{:02}{:02}{:02}",color.r,color.g,color.b);
    std::string bg_color_str = std::format("{:02}{:02}{:02}",bgColor.r,bgColor.g,bgColor.b);
    std::string key = std::format("{}_{}_{}_{}_{}_{}",text,fontName,ptsize,color_str,bg_color_str,(int)renderMode);
#if defined(__ANDROID__)
    std::string cache_filename =std::format("{}/surface_text/{}.png",SDL_GetAndroidCachePath(),hasher(key));
#else
    std::string cache_filename =std::format("surface_text/{}.png",hasher(key));
#endif

    if (!cached or !std::filesystem::exists(cache_filename)) {

        // умножаем на scale чтобы исключить размытие
        TTF_Font *font = FontCache::getFont(fontName, ptsize * Engine::scale());
        if (!font) {
            SDL_LogError(SDL_LOG_CATEGORY_CUSTOM, "[Text::setText] Failed to load font %s: %s",
                         fontName.c_str(), SDL_GetError());
            return;
        }

        switch (renderMode) {
            case TextRenderMode::Solid:
                surface = TTF_RenderText_Solid(font, text.c_str(), text.size(), color);
                break;
            case TextRenderMode::Shaded:
                surface = TTF_RenderText_Shaded(font, text.c_str(), text.size(), color, bgColor);
                break;
            case TextRenderMode::Blended:
                surface = TTF_RenderText_Blended(font, text.c_str(), text.size(), color);
                break;
            case TextRenderMode::LCD:
                surface = TTF_RenderText_LCD(font, text.c_str(), text.size(), color, bgColor);
                break;
            default:
                break;
        }

        if (cached) {
            IMG_SavePNG(surface, cache_filename.c_str());
        }
    }else {
        surface = IMG_Load(cache_filename.c_str());
    }

    if (!surface) {
        SDL_LogError(SDL_LOG_CATEGORY_CUSTOM, "[Text::setText] Text rendering failed: %s", SDL_GetError());
        return;
    }

    setSize(surface->w/Engine::scale(), surface->h/Engine::scale());

    if (texture) {
        SDL_DestroyTexture(texture);
        texture=nullptr;
    }

    texture = SDL_CreateTextureFromSurface(Engine::getRenderer(), surface);
    SDL_DestroySurface(surface);
}

void Text::draw() {
    if (texture) {
        SDL_FRect dest = getScaleFRect();
        SDL_RenderTexture(Engine::getRenderer(), texture, NULL, &dest);
    }
}

void Text::setCached(bool value) {
    this->cached = value;
}


