/*
 * svg_doc.cpp
 * SvgDoc: source-backed rasterizable SVG document.
 * Copyright (c) 2026 Daniel Hammer
 */

#include "svg_doc.hpp"

#include <montauk/syscall.h>
#include <montauk/heap.h>
#include <gui/gui.hpp>
#include <gui/svg.hpp>

namespace imageviewer {

bool svgdoc_init(SvgDoc* doc, uint8_t* source, int source_len) {
    if (!doc) return false;
    *doc = {};
    if (!source || source_len <= 0) return false;

    doc->source = source;
    doc->source_len = source_len;
    gui::svg_get_natural_size((const char*)source, source_len,
                              &doc->natural_w, &doc->natural_h);
    if (doc->natural_w < 1) doc->natural_w = 1;
    if (doc->natural_h < 1) doc->natural_h = 1;
    return true;
}

bool svgdoc_render(SvgDoc* doc, float target_scale, int max_edge) {
    if (!doc || !doc->source) return false;
    if (target_scale <= 0.0f) target_scale = 1.0f;
    if (max_edge < 1) max_edge = 1;

    // Clamp so the longest edge of the rasterized output stays within max_edge.
    int natural_long = doc->natural_w > doc->natural_h ? doc->natural_w : doc->natural_h;
    float max_scale = (float)max_edge / (float)natural_long;
    if (target_scale > max_scale) target_scale = max_scale;
    if (target_scale < 0.01f) target_scale = 0.01f;

    // Skip if cache is already close enough (avoids re-render on float jitter).
    if (doc->pixels && doc->render_scale > 0.0f) {
        float ratio = target_scale / doc->render_scale;
        if (ratio > 0.995f && ratio < 1.005f) return true;
    }

    int new_w = (int)((float)doc->natural_w * target_scale);
    int new_h = (int)((float)doc->natural_h * target_scale);
    if (new_w < 1) new_w = 1;
    if (new_h < 1) new_h = 1;

    gui::SvgIcon icon = gui::svg_render(
        (const char*)doc->source, doc->source_len,
        new_w, new_h, gui::Color::from_rgb(0, 0, 0));
    if (!icon.pixels) return false;

    if (doc->pixels) montauk::mfree(doc->pixels);
    doc->pixels = icon.pixels;
    doc->render_w = icon.width;
    doc->render_h = icon.height;
    doc->render_scale = target_scale;
    return true;
}

void svgdoc_free(SvgDoc* doc) {
    if (!doc) return;
    if (doc->pixels) montauk::mfree(doc->pixels);
    if (doc->source) montauk::mfree(doc->source);
    *doc = {};
}

} // namespace imageviewer
