#include <gst/gst.h>

#include <fstream>
#include <iostream>

// #include "gstnvdsinfer.h"
#include "gstnvdsmeta.h"
#include "nvds_version.h"
// #include "nvdsinfer_custom_impl.h"
#include <immintrin.h>  // for AVX intrinsics

#include "config_manager.hpp"
#include "custom_gstnvdsinfer.hpp"
#include "nvdsmeta.h"
#include "nvdsmeta_schema.h"

class FaceNvInferServerManager {
   private:
   public:
    struct FACE_BODY {
        int object_id = 0;
        float face_score = 0;
    };
    static std::vector<FACE_BODY> face_body_list;
    GstElement *face_detector = NULL;
    int face_batch_size;
    inline static constexpr bool save_img = TRUE;
    inline static constexpr bool attach_user_meta = TRUE;
    inline static float compression_coefficient;

    static unsigned int FACE_NET_WIDTH;
    static unsigned int FACE_NET_HEIGHT;
    static unsigned int MUXER_OUTPUT_WIDTH;
    static unsigned int MUXER_OUTPUT_HEIGHT;
    static unsigned int nvds_lib_major_version;
    static unsigned int nvds_lib_minor_version;
    static gint frame_number;
    static guint use_device_mem;
    std::string inferserver_face_config_file;
    static float threshold_face_detection;
    FaceNvInferServerManager();
    bool create_face_nv_infer_server(int);
    ~FaceNvInferServerManager();
    // static GstPadProbeReturn osd_sink_pad_buffer_probe(GstPad *,
    //                                                    GstPadProbeInfo *,
    //                                                    gpointer);
    //  void attach_probe_to_element(GstElement *);
    // static GstPadProbeReturn pgie_pad_buffer_probe(GstPad *, GstPadProbeInfo
    // *,
    //                                                gpointer);
    //  static GstPadProbeReturn osd_sink_pad_buffer_probe_new(GstPad *,
    //                                                         GstPadProbeInfo
    //                                                         *, gpointer);
    // static void *set_metadata_ptr(float *);
    // static gpointer copy_user_meta(gpointer, gpointer);
    // static void release_user_meta(gpointer, gpointer);

    static GstPadProbeReturn sgie_pad_buffer_probe(GstPad *, GstPadProbeInfo *,
                                                   gpointer);
    //  static GstPadProbeReturn osd_sink_pad_buffer_probe_new(GstPad *,
    //                                                         GstPadProbeInfo
    //                                                         *, gpointer);
    static void *set_metadata_ptr(float *);
    static gpointer copy_user_meta(gpointer, gpointer);
    static void release_user_meta(gpointer, gpointer);
    static NvOSD_RectParams *allign_postprocess(NvOSD_RectParams &, float *);
    static float numpy_clip(float, float, float);
    static void add_face_body(int, float);
    static bool all_zero_avx(const float *, size_t);
    static bool all_zero(const float *, size_t);
    static void encode_full_frame_attach_meta(gpointer, NvBufSurface *,
                                              NvDsFrameMeta *);
    static void encode_objects_attach_meta(gpointer, NvBufSurface *,
                                           NvDsFrameMeta *, NvDsObjectMeta *);
};