// GPU 없는 SDK test 전용. Production은 SDK의 공개 Python accessor만 사용한다.
#include <gst/gst.h>
#include <gstnvdsmeta.h>
#include <nvdsmeta.h>
#include <cstdint>
#include "../native/nvinferserver_rfdetr/frame_dimensions.hpp"
#include "../native/nvinferserver_rfdetr/frame_completion.hpp"

extern "C" int attach_fixture_at(uintptr_t pointer, bool populated, bool copy_frame, unsigned seq) {
    auto* buffer = reinterpret_cast<GstBuffer*>(pointer);
    auto* batch = nvds_create_batch_meta(1);
    if (!batch) return 1;
    auto* frame = nvds_acquire_frame_meta_from_pool(batch);
    frame->frame_num = seq;
    frame->buf_pts = seq * 100000000ULL;
    frame->source_frame_width = 1280;
    frame->source_frame_height = 720;
    // 실제 Runtime처럼 SDK pipeline 크기0에서 production 전달 함수를 호출한다.
    if (!contextra::publishFrameDimensions(*frame, 640, 360)) return 3;
    frame->bInferDone = true;
    nvds_add_frame_meta_to_batch(batch, frame);
    if (populated) {
        auto* object = nvds_acquire_obj_meta_from_pool(batch);
        object->unique_component_id = 7;
        object->class_id = 0;
        object->confidence = .9f;
        object->rect_params.left = 64;
        object->rect_params.top = 36;
        object->rect_params.width = 128;
        object->rect_params.height = 72;
        nvds_add_obj_meta_to_frame(frame, object, nullptr);
    }
    if (!contextra::publishCompletion(batch, frame, 7, populated ? 1 : 0, 640, 360)) return 4;
    if (copy_frame) {
        auto* copied_batch = nvds_create_batch_meta(1);
        auto* copied_frame = nvds_acquire_frame_meta_from_pool(copied_batch);
        nvds_copy_frame_meta(frame, copied_frame);
        nvds_add_frame_meta_to_batch(copied_batch, copied_frame);
        nvds_destroy_batch_meta(batch);
        batch = copied_batch;
    }
    auto* meta = gst_buffer_add_nvds_meta(buffer, batch, nullptr,
        nvds_batch_meta_copy_func, nvds_batch_meta_release_func);
    if (!meta) { nvds_destroy_batch_meta(batch); return 2; }
    meta->meta_type = NVDS_BATCH_GST_META;
    return 0;
}

extern "C" int attach_fixture(uintptr_t pointer, bool populated, bool copy_frame) {
    return attach_fixture_at(pointer, populated, copy_frame, 0);
}

extern "C" int dimension_contract() {
    NvDsFrameMeta frame{};
    frame.source_frame_width = 1280;
    frame.source_frame_height = 720;
    if (contextra::publishFrameDimensions(frame, 0, 360)) return 1;
    if (!contextra::publishFrameDimensions(frame, 640, 360)) return 2;
    if (!contextra::publishFrameDimensions(frame, 640, 360)) return 3;
    if (contextra::publishFrameDimensions(frame, 320, 360)) return 4;
    if (frame.pipeline_width != 640 || frame.source_frame_width != 1280) return 5;
    return 0;
}

// Public SDK FrameMeta copy로 identity JSON callback의 독립 수명을 확인한다.
extern "C" int copy_fixture_frames(uintptr_t source, uintptr_t target) {
    auto* batch = gst_buffer_get_nvds_batch_meta(reinterpret_cast<GstBuffer*>(source));
    if (!batch) return 1;
    auto* copied = nvds_create_batch_meta(1);
    if (!copied) return 2;
    nvds_copy_frame_meta_list(batch->frame_meta_list, copied);
    auto* meta = gst_buffer_add_nvds_meta(reinterpret_cast<GstBuffer*>(target), copied, nullptr,
        nvds_batch_meta_copy_func, nvds_batch_meta_release_func);
    if (!meta) { nvds_destroy_batch_meta(copied); return 3; }
    meta->meta_type = NVDS_BATCH_GST_META;
    return 0;
}

extern "C" int set_fixture_class(uintptr_t pointer, int class_id) {
    auto* batch = gst_buffer_get_nvds_batch_meta(reinterpret_cast<GstBuffer*>(pointer));
    if (!batch || !batch->frame_meta_list) return 1;
    auto* frame = static_cast<NvDsFrameMeta*>(batch->frame_meta_list->data);
    for (auto* item = frame->obj_meta_list; item; item = item->next)
        static_cast<NvDsObjectMeta*>(item->data)->class_id = class_id;
    return 0;
}
