// DragonX Wallet - ImGui Edition
// Copyright 2024-2026 The Hush Developers
// Released under the GPLv3

#include "svg_texture.h"
#include "texture_loader.h"   // CreateRawTexture
#include "logger.h"

// nanosvg (memononen, zlib/public-domain, vendored in libs/nanosvg). Implementations compiled ONLY here.
#define NANOSVG_IMPLEMENTATION
#include "nanosvg/nanosvg.h"
#define NANOSVGRAST_IMPLEMENTATION
#include "nanosvg/nanosvgrast.h"

#include <algorithm>
#include <string>
#include <vector>

namespace dragonx {
namespace util {

// Perceptual brightness of a nanosvg color (byte order R,G,B,A — matches ImU32/IM_COL32).
static inline float svgLuma(unsigned int c) {
    const float r = (c & 0xFFu) / 255.0f;
    const float g = ((c >> 8) & 0xFFu) / 255.0f;
    const float b = ((c >> 16) & 0xFFu) / 255.0f;
    return 0.299f * r + 0.587f * g + 0.114f * b;
}

bool LoadTextureFromSvg(const char* svgText, int pxSize, ImU32 bodyColor, ImU32 detailColor,
                        ImTextureID* outTex, int* outW, int* outH) {
    if (!svgText || pxSize <= 0 || !outTex) return false;

    // nsvgParse mutates its input buffer — parse a copy.
    std::string buf(svgText);
    NSVGimage* img = nsvgParse(&buf[0], "px", 96.0f);
    if (!img || img->width <= 0.0f || img->height <= 0.0f) {
        if (img) nsvgDelete(img);
        DEBUG_LOGF("LoadTextureFromSvg: parse failed / empty image\n");
        return false;
    }

    // Recolor by brightness: light fills -> detail, darker fills -> body. Force opaque so a theme color
    // with partial alpha can't make the mark translucent. ImU32 and nanosvg color share byte order.
    const unsigned int body   = (static_cast<unsigned int>(bodyColor)   & 0x00FFFFFFu) | 0xFF000000u;
    const unsigned int detail = (static_cast<unsigned int>(detailColor) & 0x00FFFFFFu) | 0xFF000000u;
    for (NSVGshape* s = img->shapes; s; s = s->next) {
        if (s->fill.type == NSVG_PAINT_COLOR)
            s->fill.color = (svgLuma(s->fill.color) > 0.6f) ? detail : body;
        if (s->stroke.type == NSVG_PAINT_COLOR)
            s->stroke.color = (svgLuma(s->stroke.color) > 0.6f) ? detail : body;
    }

    const float scale = static_cast<float>(pxSize) / img->width;
    const int w = pxSize;
    const int h = std::max(1, static_cast<int>(img->height * scale + 0.5f));

    std::vector<unsigned char> rgba(static_cast<size_t>(w) * h * 4, 0);
    NSVGrasterizer* rast = nsvgCreateRasterizer();
    if (!rast) { nsvgDelete(img); return false; }
    nsvgRasterize(rast, img, 0.0f, 0.0f, scale, rgba.data(), w, h, w * 4);
    nsvgDeleteRasterizer(rast);
    nsvgDelete(img);

    if (!CreateRawTexture(rgba.data(), w, h, /*repeat=*/false, outTex)) {
        DEBUG_LOGF("LoadTextureFromSvg: CreateRawTexture failed (%dx%d)\n", w, h);
        return false;
    }
    if (outW) *outW = w;
    if (outH) *outH = h;
    return true;
}

} // namespace util
} // namespace dragonx
