#ifndef FACENET_H
#define FACENET_H
#pragma once
#include "ANSFRCommon.h"
#include "hnswlib/hnswlib.h"
#include "cnn.hpp"
#include "face_reid.hpp"
#include "openvino/openvino.hpp"
#include <faiss/IndexFlat.h>

namespace ANSCENTER {
    class ANSFaceNet :public ANSFRBase {
    public:
        virtual bool Initialize(std::string licenseKey, ModelConfig modelConfig, const std::string& modelZipFilePath, const std::string& modelZipPassword, std::string& labelMap) override;
        virtual bool LoadModel(const std::string& modelZipFilePath, const std::string& modelZipPassword)override;
        bool OptimizeModel(bool fp16, std::string& optimizedModelFolder);
        std::vector<float>   Feature(const cv::Mat& image, const ANSCENTER::Object& bBox); // Run inference and get embedding information from a cropped image
        std::vector<FaceResultObject>  Match(const cv::Mat& input, const std::vector<ANSCENTER::Object>& bBox, const std::map<std::string, std::string>& userDict); // Run inference and get embedding information from a cropped image (the first bbox)
        cv::Mat GetCropFace(const cv::Mat& input, const ANSCENTER::Object& bBox);
        void Init();
        void AddEmbedding(const std::string& className, float embedding[]);
        void AddEmbedding(const std::string& className, const std::vector<float>& embedding);
        bool    UpdateParamater(double knownPersonThreshold) {
            _modelConfig.unknownPersonThreshold = knownPersonThreshold;
            m_knownPersonThresh = _modelConfig.unknownPersonThreshold;
            return true;
        }
        ~ANSFaceNet();
        bool Destroy();
    private:
        bool LoadEngine(const std::string engineFile, bool engineOptimisation = true);
        std::vector<std::vector<float>> Forward(const cv::Mat& input, std::vector<ANSCENTER::Object> outputBbox);
        std::tuple<std::vector<std::string>, std::vector<float>>  SearchForFaces(const std::vector<std::vector<float>>& detectedEmbeddings);
		std::string GetOpenVINODevice();
    protected:
        std::vector<std::string> classNames;
        ModelConfig             _modelConfig;
        std::string             _modelFilePath;
        ov::Core core;
        float m_knownPersonThresh;
        const int FACE_WIDTH = 116;
        const int FACE_HEIGHT = 116;
        const int FACE_EMBEDDING_SIZE = 512;
        std::unique_ptr<VectorCNN>faceRecognizer = nullptr;
        std::unique_ptr<faiss::IndexFlatL2> faiss_index;  // Use shared_ptr
        std::recursive_mutex		_mutex;
    };
}
#endif