#include "fpng.h"
#include "lodepng.h"
#include <stdlib.h>
#include <string.h>
#include <vector>

extern "C" {

void fpng_init_wasm() {
    fpng::fpng_init();
}

/**
 * Encode RGBA data into PNG using fpng (ultra-fast, raw RGBA lossless passthrough)
 * @param pImage Pointer to RGBA buffer
 * @param w Width
 * @param h Height
 * @param out_buf Pointer to void* (will store output pointer)
 * @param out_size Pointer to uint32_t (will store output byte length)
 * @return 0 on success, 1 on failure
 */
int fpng_encode_rgba_wasm(const void* pImage, uint32_t w, uint32_t h, void** out_buf, uint32_t* out_size) {
    if (!pImage || !w || !h || !out_buf || !out_size) return 1;

    std::vector<uint8_t> out_vector;
    bool success = fpng::fpng_encode_image_to_memory(pImage, w, h, 4, out_vector, 0);
    if (!success || out_vector.empty()) {
        return 1;
    }

    uint32_t sz = static_cast<uint32_t>(out_vector.size());
    void* ptr = malloc(sz);
    if (!ptr) return 1;

    memcpy(ptr, out_vector.data(), sz);
    *out_buf = ptr;
    *out_size = sz;
    return 0;
}

/**
 * Decode PNG data into 32-bit RGBA buffer
 * @param pImage Pointer to PNG buffer
 * @param image_size PNG byte length
 * @param out_buf Pointer to void* (will store output RGBA pointer)
 * @param out_w Pointer to uint32_t (will store width)
 * @param out_h Pointer to uint32_t (will store height)
 * @return 0 on success, 1 on failure
 */
int fpng_decode_rgba_wasm(const void* pImage, uint32_t image_size, void** out_buf, uint32_t* out_w, uint32_t* out_h) {
    if (!pImage || !image_size || !out_buf || !out_w || !out_h) return 1;

    std::vector<uint8_t> out_vector;
    uint32_t width = 0, height = 0, channels_in_file = 0;
    
    int status = fpng::fpng_decode_memory(pImage, image_size, out_vector, width, height, channels_in_file, 4);
    if (status == fpng::FPNG_DECODE_SUCCESS && !out_vector.empty()) {
        uint32_t sz = static_cast<uint32_t>(out_vector.size());
        void* ptr = malloc(sz);
        if (!ptr) return 1;
        memcpy(ptr, out_vector.data(), sz);
        *out_buf = ptr;
        *out_w = width;
        *out_h = height;
        return 0;
    }

    // Fallback to lodepng for generic non-fpng PNGs
    unsigned char* lode_out = nullptr;
    unsigned lw = 0, lh = 0;
    unsigned err = lodepng_decode32(&lode_out, &lw, &lh, static_cast<const unsigned char*>(pImage), image_size);
    if (err == 0 && lode_out) {
        *out_buf = lode_out;
        *out_w = lw;
        *out_h = lh;
        return 0;
    }

    return 1;
}

}
