#include "nv_message_broker.hpp"

NvMessageBroker::NvMessageBroker() {
    const auto &config = ConfigManager::get_instance().get_config();

    msgbroker_config_file = config["msgbroker"]["msgbroker_config_file"];
    protocol_adaptor_library = config["msgbroker"]["protocol_adaptor_library"];
    topic_redis = config["msgbroker"]["topic_redis"];
    redis_host = config["msgbroker"]["redis_broker_host"];
    redis_port = config["msgbroker"]["redis_broker_port"];
    conn_str = redis_host + ";" + std::to_string(redis_port);
}

bool NvMessageBroker::create_message_broker() {
    msgbroker = gst_element_factory_make("nvmsgbroker", "nvmsg-broker");

    g_object_set(G_OBJECT(msgbroker), "proto-lib",
                 protocol_adaptor_library.c_str(),
                 //  "conn-str", conn_str.c_str(),
                 "sync", FALSE, NULL);
    g_object_set(G_OBJECT(msgbroker), "config", msgbroker_config_file.c_str(),
                 NULL);

    // nvmsgbroker looks first at the --conn-str (or conn-str property).
    // If it’s not provided, and you gave a --cfg-file (or config property), it
    // will read hostname and port from the config file. If you set both, the
    // conn-str overrides the file values. g_object_set (G_OBJECT (msgbroker),
    // "conn-str", conn_str, NULL);
    g_object_set(G_OBJECT(msgbroker), "topic", topic_redis.c_str(), NULL);

    if (!msgbroker) {
        g_printerr("Unable to create msgbroker.Exiting.");
        return false;
    }
    return true;
}

void NvMessageBroker::attach_probe_to_sink_msgbroker() {
    GstPad *sink_pad = gst_element_get_static_pad(msgbroker, "sink");
    if (!sink_pad) {
        std::cerr << "Unable to get sink_pad sink pad\n";
        return;
    }

    gst_pad_add_probe(sink_pad, GST_PAD_PROBE_TYPE_BUFFER,
                      broker_sink_pad_probe, NULL, NULL);
    gst_object_unref(sink_pad);
}

GstPadProbeReturn NvMessageBroker::broker_sink_pad_probe(GstPad *pad,
                                                         GstPadProbeInfo *info,
                                                         gpointer user_data) {
    (void)pad;
    (void)user_data;
    GstBuffer *buf = GST_PAD_PROBE_INFO_BUFFER(info);
    if (!buf) return GST_PAD_PROBE_OK;

    // Iterate metadata in the buffer
    NvDsMetaList *l_frame = NULL;
    NvDsMetaList *l_user = NULL;
    NvDsBatchMeta *batch_meta = gst_buffer_get_nvds_batch_meta(buf);
    if (!batch_meta) return GST_PAD_PROBE_OK;

    for (l_frame = batch_meta->frame_meta_list; l_frame != NULL;
         l_frame = l_frame->next) {
        NvDsFrameMeta *frame_meta = (NvDsFrameMeta *)(l_frame->data);

        for (l_user = frame_meta->frame_user_meta_list; l_user != NULL;
             l_user = l_user->next) {
            NvDsUserMeta *user_meta = (NvDsUserMeta *)(l_user->data);
            if (user_meta &&
                user_meta->base_meta.meta_type == NVDS_EVENT_MSG_META) {
                NvDsEventMsgMeta *msg_meta =
                    (NvDsEventMsgMeta *)user_meta->user_meta_data;

                if (msg_meta && msg_meta->extMsg != NULL) {
                    // You can inspect or pretty-print the JSON payload
                    g_print("Broker Probe 1: JSON payload: %s\n",
                            (char *)msg_meta->extMsg);
                }
            }
        }
    }

    // Also inspect per-frame metas (some code attaches to frame_user_meta_list)
    for (NvDsMetaList *lf = batch_meta->frame_meta_list; lf; lf = lf->next) {
        NvDsFrameMeta *fmeta = (NvDsFrameMeta *)lf->data;
        if (!fmeta) continue;

        for (NvDsMetaList *l = fmeta->frame_user_meta_list; l; l = l->next) {
            NvDsUserMeta *um = (NvDsUserMeta *)l->data;
            if (!um) continue;

            // g_print("[nvmsgconv probe] frame %d user meta type=%s ptr=%p\n",
            //         fmeta->frame_num,
            //         metaTypeToString(um->base_meta.meta_type),
            //         (void*)um->user_meta_data);

            if (um->base_meta.meta_type == NVDS_EVENT_MSG_META) {
                NvDsEventMsgMeta *m = (NvDsEventMsgMeta *)um->user_meta_data;
                if (!m) continue;
                if (m && m->extMsg != NULL) {
                    // You can inspect or pretty-print the JSON payload
                    g_print("Broker Probe 2: JSON payload: %s\n",
                            (char *)m->extMsg);
                }
                // g_print("frame-level event msg objClassId=%d objectId=%s
                // componentId=%d trackingId=%ld confidence=%f ptr=%p frameId=%"
                // G_GINT64_FORMAT
                //         "\n",
                //         m->objClassId, m->objectId, m->componentId,
                //         m->trackingId, m->confidence, (void *)m,
                //         (gint64)m->frameId);

                // g_print("ts_ptr=%p\n", (void *)m->ts);
                // g_print("ts_ptr=%p\n", (void *)m->ts);
                // if (m->ts && safe_string_print(m->ts, 256)) {
                //     g_print("ts: %s\n", m->ts);
                // } else if (m->ts) {
                //     g_print("ts suspicious - not printing\n");
                // } else {
                //     g_print("ts=NULL\n");
                // }
            }
        }
    }

    return GST_PAD_PROBE_OK;
}