#include <gst/gst.h>

#include <cmath>
#include <fstream>
#include <iostream>
#include <iterator>
#include <optional>
#include <tuple>  // for std::tuple
#include <vector>

#include "config_manager.hpp"
#include "face_candid_trace.hpp"
#include "gstnvdsmeta.h"
#include "nvdsmeta.h"
#include "nvdsmeta_schema.h"

class NvTrackerManager {
   private:
    struct FaceBody {
        int object_id = 0;
        int source_id = 0;
        int num_frames = 0;
        float largest_area = -1;
    };
    struct FaceCandidate {
        float w = 0;
        float h = 0;
        float face_score;
        gint frame_number;
        int object_id;
        int source_id;
    };

    static std::vector<FaceBody> body_face_list;
    static FaceCandidTrace *face_candidate_trace;
    float face_score;

   public:
    static unsigned int PGIE_NET_WIDTH;
    static unsigned int PGIE_NET_HEIGHT;
    static unsigned int MUXER_OUTPUT_WIDTH;
    static unsigned int MUXER_OUTPUT_HEIGHT;

    GstElement *tracker = NULL;
    static gint frame_number;
    std::string ll_config_file;
    std::string ll_lib_file;
    NvTrackerManager();
    ~NvTrackerManager();
    bool create_nv_tracker();
    void attach_probe_to_element();
    static GstPadProbeReturn tracker_src_pad_buffer_probe(GstPad *,
                                                          GstPadProbeInfo *,
                                                          gpointer);
    static bool check_existence(int, int, float, bool *);
    float get_face_score(float *);
    static std::optional<
        std::tuple<std::tuple<float, float, float, float>, float>>
    face_box_extract(float *);
};