#include "FaceDatabase.h"
namespace ANSCENTER {

    FaceDatabase::FaceDatabase() {
        m_db = nullptr;
        m_embedding_dim = 0;
    }
    bool FaceDatabase::Initialize(std::string path, int embedding_dim, std::string dataFolder) {
        std::lock_guard<std::mutex> lock(_mutex);
        try {
            sqlite3_stmt* stmt;
            _dataFolder = dataFolder;
            m_embedding_dim = embedding_dim;
            std::string sql;
            int rc;
            int isNotEmpty = 0;
            //this->_logger.LogDebug("FaceDatabase::Initialize. Database path: ", path, __FILE__, __LINE__);
            std::string faceDatabaseFolder = GetParentFolder(path);
            if (!FolderExist(faceDatabaseFolder)) fs::create_directory(faceDatabaseFolder);
            std::string imageDataFolder = CreateFilePath(faceDatabaseFolder, "data");
            if (!FolderExist(imageDataFolder)) fs::create_directory(imageDataFolder);

            rc = sqlite3_open(path.c_str(), &m_db);
            if (rc) {
                _logger.LogError("FaceDatabase::Initialize", std::string("Can't open database: ") + sqlite3_errmsg(m_db), __FILE__, __LINE__);
            }
            else {
                _logger.LogDebug("FaceDatabase::Initialize", "Opened database successfully", __FILE__, __LINE__);
            }

            // Fix #2: Enable WAL mode for concurrent read/write from separate processes
            sqlite3_exec(m_db, "PRAGMA journal_mode=WAL;", nullptr, nullptr, nullptr);
            // Fix #2: 5-second busy timeout for multi-process contention
            sqlite3_exec(m_db, "PRAGMA busy_timeout=5000;", nullptr, nullptr, nullptr);
            // Fix #2: Enable foreign key enforcement
            sqlite3_exec(m_db, "PRAGMA foreign_keys=ON;", nullptr, nullptr, nullptr);

            // Prepare
            sql = "SELECT name FROM sqlite_master;";
            rc = sqlite3_prepare_v2(m_db, sql.c_str(), -1, &stmt, NULL);
            if (rc != SQLITE_OK) {
                //this->_logger.LogError("FaceDatabase::Initialize. SQL error:", sqlite3_errmsg(m_db), __FILE__, __LINE__);
            }

            // Step
            while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
                isNotEmpty = 1;
                break;
            }
            sqlite3_finalize(stmt);

            if (isNotEmpty) {
                //this->_logger.LogDebug("FaceDatabase::Initialize.", "Database is not empty", __FILE__, __LINE__);
            }
            else {
                //this->_logger.LogDebug("FaceDatabase::Initialize.", "Empty Database, initiating...", __FILE__, __LINE__);
                // Prepare
                sql = "CREATE TABLE IF NOT EXISTS USER ( \
                ID  INTEGER PRIMARY KEY AUTOINCREMENT, \
                CODE TEXT, \
                NAME TEXT, \
                UNIQUE(ID, CODE)\
                )";
                rc = sqlite3_prepare_v2(m_db, sql.c_str(), -1, &stmt, NULL);
                if (rc != SQLITE_OK) {
                    //this->_logger.LogError("FaceDatabase::Initialize. SQL step error:", sqlite3_errmsg(m_db), __FILE__, __LINE__);
                }

                // Step
                rc = sqlite3_step(stmt);
                if (rc != SQLITE_ROW && rc != SQLITE_DONE) {
                    // this->_logger.LogError("FaceDatabase::Initialize. SQL step error:", sqlite3_errmsg(m_db), __FILE__, __LINE__);
                }
                else {
                    // this->_logger.LogDebug("FaceDatabase::Initialize.", "Table `USER` created successfully", __FILE__, __LINE__);
                }
                sqlite3_finalize(stmt);

                // Prepare
                sql = "CREATE TABLE IF NOT EXISTS FACE ( \
                ID    INTEGER PRIMARY KEY AUTOINCREMENT, \
                USER  INTEGER, \
                IMG_PATH  TEXT, \
                EMBEDDING BLOB, \
                UNIQUE(ID, USER), \
                FOREIGN KEY(USER) REFERENCES USER(ID) \
                )";

                rc = sqlite3_prepare_v2(m_db, sql.c_str(), -1, &stmt, NULL);
                if (rc != SQLITE_OK) {
                    //this->_logger.LogError("FaceDatabase::Initialize. SQL error:", sqlite3_errmsg(m_db), __FILE__, __LINE__);
                }

                // Step
                rc = sqlite3_step(stmt);
                if (rc != SQLITE_ROW && rc != SQLITE_DONE) {
                    // this->_logger.LogError("FaceDatabase::Initialize. SQL step error:", sqlite3_errmsg(m_db), __FILE__, __LINE__);
                }
                else {
                    // this->_logger.LogDebug("FaceDatabase::Initialize", "Table `FACE` created successfully.", __FILE__, __LINE__);
                }
                sqlite3_finalize(stmt);
            }
            return true;
        }
        catch (std::exception& e) {
            //this->_logger.LogFatal("FaceDatabase::Initialize", e.what(), __FILE__, __LINE__);
            //sqlite3_finalize(stmt);
            return false;
        }
    }
    int FaceDatabase::InsertUser(std::string userId, std::string userName) {
        std::lock_guard<std::mutex> lock(_mutex);
        std::string sql;
        sqlite3_stmt* stmt;
        int rc;
        int resultCode = 0;
        // Prepare
        sql = "INSERT INTO USER (CODE, NAME) VALUES (?, ?);";
        rc = sqlite3_prepare_v2(m_db, sql.c_str(), -1, &stmt, NULL);
        try {

            if (rc != SQLITE_OK) {
                //this->_logger.LogError("FaceDatabase::InsertUser. SQL error:", sqlite3_errmsg(m_db), __FILE__, __LINE__);
                return -2;
            }
            // Binding
            rc = sqlite3_bind_text(stmt, 1, userId.c_str(), int(userId.length()), SQLITE_STATIC);
            if (rc != SQLITE_OK) {
                //this->_logger.LogError("FaceDatabase::InsertUser. SQL bind error:", sqlite3_errmsg(m_db), __FILE__, __LINE__);
                resultCode = -3;
            }
            rc = sqlite3_bind_text(stmt, 2, userName.c_str(), int(userName.length()), SQLITE_STATIC);
            if (rc != SQLITE_OK) {
                //this->_logger.LogError("FaceDatabase::InsertUser. SQL bind error:", sqlite3_errmsg(m_db), __FILE__, __LINE__);
                resultCode = -3;
            }

            // Step
            rc = sqlite3_step(stmt);
            if (rc != SQLITE_ROW && rc != SQLITE_DONE) {
                //this->_logger.LogError("FaceDatabase::InsertUser. SQL step error:", sqlite3_errmsg(m_db), __FILE__, __LINE__);
                resultCode = -4;
            }
            if (rc == SQLITE_DONE) {
                // this->_logger.LogDebug("FaceDatabase::InsertUser:", "Record successfully created", __FILE__, __LINE__);
            }
            sqlite3_finalize(stmt);
            int id = (int)sqlite3_last_insert_rowid(m_db);
            resultCode = id;
            return resultCode;
        }
        catch (std::exception& e) {
            //this->_logger.LogFatal("FaceDatabase::InsertUser", e.what(), __FILE__, __LINE__);
            sqlite3_finalize(stmt);
            return -1;
        }
    }
    int FaceDatabase::UpdateUser(int userId, std::string newUserCode, std::string newUserName) {
        std::lock_guard<std::mutex> lock(_mutex);
        std::string sql;
        sqlite3_stmt* stmt;
        int resultCode = 0;
        int rc;
        // Prepare
        // UPDATE USER SET CODE ="0003", NAME= "Biden"  WHERE ID =1
        sql = "UPDATE USER SET CODE=?, NAME=? WHERE ID=?;";
        rc = sqlite3_prepare_v2(m_db, sql.c_str(), -1, &stmt, NULL);
        try {

            if (rc != SQLITE_OK) {
                //this->_logger.LogError("FaceDatabase::InsertUser. SQL error:", sqlite3_errmsg(m_db), __FILE__, __LINE__);
                return -1;
            }

            // Binding
            rc = sqlite3_bind_text(stmt, 1, newUserCode.c_str(), int(newUserCode.length()), SQLITE_STATIC);
            if (rc != SQLITE_OK) {
                //this->_logger.LogError("FaceDatabase::InsertUser. SQL bind error:", sqlite3_errmsg(m_db), __FILE__, __LINE__);
                resultCode = -2;
            }

            rc = sqlite3_bind_text(stmt, 2, newUserName.c_str(), int(newUserName.length()), SQLITE_STATIC);
            if (rc != SQLITE_OK) {
                //this->_logger.LogError("FaceDatabase::InsertUser. SQL bind error:", sqlite3_errmsg(m_db), __FILE__, __LINE__);
                resultCode = -2;
            }
            rc = sqlite3_bind_int(stmt, 3, userId);
            if (rc != SQLITE_OK) {
                //this->_logger.LogError("FaceDatabase::InsertUser. SQL bind error:", sqlite3_errmsg(m_db), __FILE__, __LINE__);
                resultCode = -2;
            }

            // Step
            rc = sqlite3_step(stmt);
            if (rc != SQLITE_ROW && rc != SQLITE_DONE) {
                //this->_logger.LogError("FaceDatabase::InsertUser. SQL step error:", sqlite3_errmsg(m_db), __FILE__, __LINE__);
                resultCode = -3;
            }
            if (rc == SQLITE_DONE) {
                // this->_logger.LogDebug("FaceDatabase::InsertUser:", "Record successfully created", __FILE__, __LINE__);
            }
            sqlite3_finalize(stmt);
            resultCode = 1;
            return resultCode;
        }
        catch (std::exception& e) {
            //this->_logger.LogFatal("FaceDatabase::InsertUser", e.what(), __FILE__, __LINE__);
            sqlite3_finalize(stmt);
            return 0;
        }
    }
    int FaceDatabase::InsertFace(int userId, std::string imgPath, float embedding[]) {
        std::lock_guard<std::mutex> lock(_mutex);
        if (!FileExist(imgPath)) return 0;
        std::string sql;
        sqlite3_stmt* stmt;
        int rc;
        int resultCode = 0;
        // Prepare
        sql = "INSERT INTO FACE (USER, IMG_PATH, EMBEDDING) VALUES (?, ?, ?);";
        rc = sqlite3_prepare_v2(m_db, sql.c_str(), -1, &stmt, NULL);
        try {

            if (rc != SQLITE_OK) {
                //std::cout << "SQL error: " << sqlite3_errmsg(m_db);
                return -2;
            }
            // Binding
            rc = sqlite3_bind_int(stmt, 1, userId);
            if (rc != SQLITE_OK) {
                //this->_logger.LogError("FaceDatabase::InsertFace. SQL bind error:", sqlite3_errmsg(m_db), __FILE__, __LINE__);
                resultCode = -3;
            }
            rc = sqlite3_bind_text(stmt, 2, imgPath.c_str(), int(imgPath.length()), SQLITE_STATIC);
            if (rc != SQLITE_OK) {
                //this->_logger.LogError("FaceDatabase::InsertFace. SQL bind error:", sqlite3_errmsg(m_db), __FILE__, __LINE__);
                resultCode = -3;
            }
            rc = sqlite3_bind_blob(stmt, 3, embedding, sizeof(float) * m_embedding_dim, SQLITE_STATIC);
            if (rc != SQLITE_OK) {
                //::cout << "SQL bind error: " << sqlite3_errmsg(m_db);
                resultCode = -3;
            }

            // Step
            rc = sqlite3_step(stmt);
            if (rc != SQLITE_ROW && rc != SQLITE_DONE) {
                //this->_logger.LogError("FaceDatabase::InsertFace. SQL step error:", sqlite3_errmsg(m_db), __FILE__, __LINE__);
                resultCode = -4;
            }
            if (rc == SQLITE_DONE) {
                //this->_logger.LogDebug("FaceDatabase::InsertFace.", "Embedding for user created successfully", __FILE__, __LINE__);
            }
            sqlite3_finalize(stmt);
            int id = (int)sqlite3_last_insert_rowid(m_db);
            resultCode = id;
            return resultCode;

        }
        catch (std::exception& e) {
            //this->_logger.LogFatal("FaceDatabase::InsertFace", e.what(), __FILE__, __LINE__);
            sqlite3_finalize(stmt);
            return -1;
        }

    }
    int FaceDatabase::DeleteFace(int id) {
        try {
            // Fix #4: Single lock scope — GetFaceById + DELETE in one atomic section
            std::lock_guard<std::mutex> lock(_mutex);
            std::string sql;
            sqlite3_stmt* stmt;
            int rc;
            int userId;
            int resultCode = 0;
            std::string faceImagePath;

            // Look up face image path (now inside lock — no TOCTOU race)
            {
                sqlite3_stmt* lookupStmt;
                rc = sqlite3_prepare_v2(m_db, "SELECT USER, IMG_PATH FROM FACE WHERE ID=?;", -1, &lookupStmt, NULL);
                if (rc == SQLITE_OK) {
                    sqlite3_bind_int(lookupStmt, 1, id);
                    if (sqlite3_step(lookupStmt) == SQLITE_ROW) {
                        userId = sqlite3_column_int(lookupStmt, 0);
                        const char* pathText = reinterpret_cast<const char*>(sqlite3_column_text(lookupStmt, 1));
                        faceImagePath = pathText ? std::string(pathText) : "";
                    }
                }
                sqlite3_finalize(lookupStmt);
            }

            // Delete image file
            if (!faceImagePath.empty() && FileExist(faceImagePath)) {
                if (!fs::remove(faceImagePath)) {
                    _logger.LogError("FaceDatabase::DeleteFace", "Failed to delete face image: " + faceImagePath, __FILE__, __LINE__);
                }
            }
            //_mutex.lock();
            // Prepare
            sql = "DELETE FROM FACE WHERE ID=?;";
            rc = sqlite3_prepare_v2(m_db, sql.c_str(), -1, &stmt, NULL);

            if (rc != SQLITE_OK) {
                //this->_logger.LogError("FaceDatabase::DeleteFace. SQL error:", sqlite3_errmsg(m_db), __FILE__, __LINE__);
                resultCode = -1;
            }

            // Binding
            rc = sqlite3_bind_int(stmt, 1, id);
            if (rc != SQLITE_OK) {
                //this->_logger.LogError("FaceDatabase::DeleteFace. SQL bind error:", sqlite3_errmsg(m_db), __FILE__, __LINE__);
                resultCode = -2;
            }
            // Step
            rc = sqlite3_step(stmt);
            if (rc != SQLITE_ROW && rc != SQLITE_DONE) {
                //this->_logger.LogError("FaceDatabase::DeleteFace. SQL step error:", sqlite3_errmsg(m_db), __FILE__, __LINE__);
                resultCode = -3;
            }
            if (rc == SQLITE_DONE) {
                // this->_logger.LogDebug("FaceDatabase::DeleteFace.", "Embedding for user deleted successfully", __FILE__, __LINE__);
            }
            sqlite3_finalize(stmt);
            resultCode = 1;
            //_mutex.unlock();
            return resultCode;
        }
        catch (std::exception& e) {
            //this->_logger.LogFatal("FaceDatabase::DeleteFace", e.what(), __FILE__, __LINE__);
            //_mutex.unlock();
            return 0;
        }
    }
    int FaceDatabase::DeleteUser(int userId) {
        try {
            std::string sql;
            sqlite3_stmt* stmt;
            int resultCode = 0;
            int rc;

            std::vector<int> faceIds;
            faceIds.clear();
            GetFaceIdsByUser(userId, faceIds);
            int numOfFaces = (int)faceIds.size();
            //this->_logger.LogDebug("FaceDatabase::DeleteUser. Number of Face for this user", std::to_string(numOfFaces), __FILE__, __LINE__);
            if (numOfFaces > 0) {
                for (int i = 0; i < numOfFaces; i++) {
                    if (!DeleteFace(faceIds[i])) {
                        //this->_logger.LogError("FaceDatabase::DeleteUser. Failed to delete face id", std::to_string(numOfFaces), __FILE__, __LINE__);
                    }
                }
            }
            std::string userImageFolderName = "User" + std::to_string(userId);
            std::string userImageFolder = CreateFilePath(_dataFolder, userImageFolderName);
            if (FolderExist(userImageFolder)) {
                if (!DeleteFolder(userImageFolder)) {
                    //this->_logger.LogError("FaceDatabase::DeleteUser. Failed to delete user data folder", userImageFolder, __FILE__, __LINE__);
                }
            }

            // Delete person 
            std::lock_guard<std::mutex> lock(_mutex);
            //_mutex.lock();
           // Prepare
            sql = "DELETE FROM USER WHERE ID=?;";
            rc = sqlite3_prepare_v2(m_db, sql.c_str(), -1, &stmt, NULL);
            if (rc != SQLITE_OK) {
                //this->_logger.LogError("FaceDatabase::DeleteUser. SQL error:", sqlite3_errmsg(m_db), __FILE__, __LINE__);
                resultCode = -1;
            }
            // Binding
            rc = sqlite3_bind_int(stmt, 1, userId);
            if (rc != SQLITE_OK) {
                //this->_logger.LogError("FaceDatabase::DeleteUser. SQL bind error:", sqlite3_errmsg(m_db), __FILE__, __LINE__);
                resultCode = -2;
            }

            // Step
            rc = sqlite3_step(stmt);
            if (rc != SQLITE_ROW && rc != SQLITE_DONE) {
                //this->_logger.LogError("FaceDatabase::DeleteUser. SQL step error:", sqlite3_errmsg(m_db), __FILE__, __LINE__);
                resultCode = -3;
            }
            if (rc == SQLITE_DONE) {
                //this->_logger.LogDebug("FaceDatabase::DeleteUser.", "Deleted person successfully", __FILE__, __LINE__);
            }
            sqlite3_finalize(stmt);
            resultCode = 1;
            //_mutex.unlock();
            return resultCode;
        }
        catch (std::exception& e) {
            //this->_logger.LogFatal("FaceDatabase::DeleteUser", e.what(), __FILE__, __LINE__);
            return 0;
        }
    }
    int FaceDatabase::GetUserId(std::string code) {
        std::lock_guard<std::mutex> lock(_mutex);
        std::string sql;
        sqlite3_stmt* stmt;
        int rc;
        // Prepare
        sql = "SELECT ID FROM USER WHERE CODE =?;";
        rc = sqlite3_prepare_v2(m_db, sql.c_str(), -1, &stmt, NULL);
        try {

            int resultCode = 0;
            int userId = -1;

            if (rc != SQLITE_OK) {
                //this->_logger.LogError("FaceDatabase::GetUser. SQL error:", sqlite3_errmsg(m_db), __FILE__, __LINE__);
                resultCode = -1;
            }

            // Binding
            rc = sqlite3_bind_text(stmt, 1, code.c_str(), int(code.length()), SQLITE_STATIC);
            if (rc != SQLITE_OK) {
                //this->_logger.LogError("FaceDatabase::GetUser. SQL bind error:", sqlite3_errmsg(m_db), __FILE__, __LINE__);
                resultCode = -2;
            }

            // Step
            rc = sqlite3_step(stmt);
            if (rc != SQLITE_ROW && rc != SQLITE_DONE) {
                //this->_logger.LogError("FaceDatabase::GetUser. SQL step error:", sqlite3_errmsg(m_db), __FILE__, __LINE__);
                resultCode = -3;
            }
            if (rc == SQLITE_ROW) {
                //this->_logger.LogDebug("FaceDatabase::GetUser.", "Get User information successfully", __FILE__, __LINE__);
                userId = sqlite3_column_int(stmt, 0);
            }
            sqlite3_finalize(stmt);
            resultCode = userId;
            return resultCode;
        }
        catch (std::exception& e) {
            //this->_logger.LogFatal("FaceDatabase::GetUserId", e.what(), __FILE__, __LINE__);
            sqlite3_finalize(stmt);
            return -1;
        }
    }
    int FaceDatabase::GetUser(int userId, std::string& code, std::string& userName) {
        std::lock_guard<std::mutex> lock(_mutex);
        std::string sql;
        sqlite3_stmt* stmt;
        int resultCode = 0;
        userName = "";
        code = "";
        int rc;
        // Prepare
        sql = "SELECT * FROM USER WHERE ID =?;";
        rc = sqlite3_prepare_v2(m_db, sql.c_str(), -1, &stmt, NULL);
        try {
            if (rc != SQLITE_OK) {
                //this->_logger.LogError("FaceDatabase::GetUser. SQL error:", sqlite3_errmsg(m_db), __FILE__, __LINE__);
                resultCode = -1;
            }

            // Binding
            rc = sqlite3_bind_int(stmt, 1, userId);
            if (rc != SQLITE_OK) {
                //this->_logger.LogError("FaceDatabase::GetUser. SQL bind error:", sqlite3_errmsg(m_db), __FILE__, __LINE__);
                resultCode = -2;
            }

            // Step
            rc = sqlite3_step(stmt);
            if (rc != SQLITE_ROW && rc != SQLITE_DONE) {
                //this->_logger.LogError("FaceDatabase::GetUser. SQL step error:", sqlite3_errmsg(m_db), __FILE__, __LINE__);
                resultCode = -3;
            }
            if (rc == SQLITE_ROW) {
                //this->_logger.LogDebug("FaceDatabase::GetUser.", "Get User information successfully", __FILE__, __LINE__);
                const char* codeText = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 1));
                const char* nameText = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 2));
                code = codeText ? std::string(codeText) : "";
                userName = nameText ? std::string(nameText) : "";
            }
            sqlite3_finalize(stmt);
            resultCode = 1;
            return resultCode;
        }
        catch (std::exception& e) {
            //this->_logger.LogFatal("FaceDatabase::GetUserId", e.what(), __FILE__, __LINE__);
            sqlite3_finalize(stmt);
            return -1;
        }
    }

    int FaceDatabase::GetFaceIdsByUser(int userId, std::vector<int>& faceIds)
    {
        std::lock_guard<std::mutex> lock(_mutex);
        faceIds.clear();
        std::string sql;
        sqlite3_stmt* stmt;
        int rc;
        sql = "SELECT ID FROM FACE WHERE USER=?;";
        rc = sqlite3_prepare_v2(m_db, sql.c_str(), -1, &stmt, NULL);
        try {
            int resultCode = 0;
            int faceId;
            if (rc != SQLITE_OK) {
                _logger.LogError("FaceDatabase::GetFaceIdsByUser", std::string("SQL error: ") + sqlite3_errmsg(m_db), __FILE__, __LINE__);
                resultCode = -1;
            }

            // Binding
            rc = sqlite3_bind_int(stmt, 1, userId);
            if (rc != SQLITE_OK) {
                _logger.LogError("FaceDatabase::GetFaceIdsByUser", std::string("SQL bind error: ") + sqlite3_errmsg(m_db), __FILE__, __LINE__);
                resultCode = -2;
            }
            while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
                faceId = sqlite3_column_int(stmt, 0);
                faceIds.push_back(faceId);
            }
            if (rc != SQLITE_DONE) {
                _logger.LogError("FaceDatabase::GetFaceIdsByUser", std::string("SQL step error: ") + sqlite3_errmsg(m_db), __FILE__, __LINE__);
            }
            sqlite3_finalize(stmt);
            resultCode = 1;
            return resultCode;
        }
        catch (std::exception& e) {
            //this->_logger.LogFatal("FaceDatabase::GetFaceIdsByUser", e.what(), __FILE__, __LINE__);
            sqlite3_finalize(stmt);
            return 0;
        }
    }
    int FaceDatabase::GetUsers(std::vector<int>& ids, std::vector<std::string>& codes, std::vector<std::string>& userNames) {
        std::lock_guard<std::mutex> lock(_mutex);
        std::string sql;
        sqlite3_stmt* stmt;
        int rc;
        int userId;
        std::string userCode;
        std::string userName;
        int resutCode = 0;
        ids.clear();
        codes.clear();
        userNames.clear();
        sql = "SELECT * FROM USER;";
        rc = sqlite3_prepare_v2(m_db, sql.c_str(), -1, &stmt, NULL);
        try {
            if (rc != SQLITE_OK) {
                //this->_logger.LogError("FaceDatabase::GetUsers. SQL error:", sqlite3_errmsg(m_db), __FILE__, __LINE__);
                resutCode = -1;
            }
            while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
                userId = sqlite3_column_int(stmt, 0);
                const char* codeText = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 1));
                const char* nameText = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 2));
                userCode = codeText ? std::string(codeText) : "";
                userName = nameText ? std::string(nameText) : "";
                ids.push_back(userId);
                codes.push_back(userCode);
                userNames.push_back(userName);
            }
            if (rc != SQLITE_DONE) {
                //this->_logger.LogError("FaceDatabase::GetUsers. SQL error:", sqlite3_errmsg(m_db), __FILE__, __LINE__);
            }
            sqlite3_finalize(stmt);
            resutCode = 1;
            return resutCode;
        }
        catch (std::exception& e) {
            //this->_logger.LogFatal("FaceDatabase::GetUsers", e.what(), __FILE__, __LINE__);
            sqlite3_finalize(stmt);
            return 0;
        }
    }
    int FaceDatabase::GetFaceById(int faceId, int& userId, std::string& imagePath) {
        std::lock_guard<std::mutex> lock(_mutex);
        std::string sql;
        sqlite3_stmt* stmt;
        int rc;
        int resultCode = 0;
        userId = -1;
        imagePath = "";
        // SELECT *FROM FACE WHERE ID =1
        sql = "SELECT * FROM FACE WHERE ID =?;";
        rc = sqlite3_prepare_v2(m_db, sql.c_str(), -1, &stmt, NULL);
        try {
            if (rc != SQLITE_OK) {
                _logger.LogError("FaceDatabase::GetFaceById", std::string("SQL error: ") + sqlite3_errmsg(m_db), __FILE__, __LINE__);
                resultCode = -1;
            }
            // Binding
            rc = sqlite3_bind_int(stmt, 1, faceId);
            if (rc != SQLITE_OK) {
                _logger.LogError("FaceDatabase::GetFaceById", std::string("SQL bind error: ") + sqlite3_errmsg(m_db), __FILE__, __LINE__);
                resultCode = -2;
            }
            while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
                userId = sqlite3_column_int(stmt, 1);
                const char* pathText = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 2));
                imagePath = pathText ? std::string(pathText) : "";
            }
            if (rc != SQLITE_DONE) {
                //this->_logger.LogError("FaceDatabase::GetFaceIds. SQL error:", sqlite3_errmsg(m_db), __FILE__, __LINE__);
            }
            sqlite3_finalize(stmt);
            resultCode = 1;
            return resultCode;
        }
        catch (std::exception& e) {
            //this->_logger.LogFatal("FaceDatabase::GetFaceIds", e.what(), __FILE__, __LINE__);
            sqlite3_finalize(stmt);
            return 0;
        }
    }
    std::map<std::string, std::string> FaceDatabase::GetUserDict() {
        std::lock_guard<std::mutex> lock(_mutex);
        std::map<std::string, std::string> userDict;
        userDict.clear();
        std::string sql;
        sqlite3_stmt* stmt;
        int rc;
		std::string userId;
        std::string userCode;
        std::string userName;
        // get user id and name
        sql = "SELECT * FROM USER;";
        rc = sqlite3_prepare_v2(m_db, sql.c_str(), -1, &stmt, NULL);
        try {
            if (rc != SQLITE_OK) {
                //this->_logger.LogError("FaceDatabase::GetUserDict. SQL error:", sqlite3_errmsg(m_db), __FILE__, __LINE__);
            }
            while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
                const char* idText = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0));
                const char* codeText = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 1));
                const char* nameText = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 2));
                userId = idText ? std::string(idText) : "";
                userCode = codeText ? std::string(codeText) : "";
                userName = nameText ? std::string(nameText) : "";
                if (!userCode.empty()) {
                    userDict[userId] = userName+"(" + userCode + ")";
                }
                else {
                    userDict[userId] = userName;
                }
            }
            if (rc != SQLITE_DONE) {
                //this->_logger.LogError("FaceDatabase::GetUserDict. SQL error:", sqlite3_errmsg(m_db), __FILE__, __LINE__);
            }
            sqlite3_finalize(stmt);
            return userDict;
        }
        catch (std::exception& e) {
            //this->_logger.LogFatal("FaceDatabase::GetUserDict", e.what(), __FILE__, __LINE__);
            sqlite3_finalize(stmt);
            return userDict;
        }
    }
    int FaceDatabase::GetNumEmbeddings() {
        std::lock_guard<std::mutex> lock(_mutex);
        try {
            int numEmbeds = 0;
            std::string sql;
            sqlite3_stmt* stmt;
            int rc;
            int resultCode = 0;
            // Prepare
            sql = "SELECT COUNT(*) FROM FACE;";
            rc = sqlite3_prepare_v2(m_db, sql.c_str(), -1, &stmt, NULL);
            if (rc != SQLITE_OK) {
                //this->_logger.LogError("FaceDatabase::GetNumEmbeddings. SQL error:", sqlite3_errmsg(m_db), __FILE__, __LINE__);
                resultCode = -1;
            }
            // Step
            rc = sqlite3_step(stmt);
            if (rc != SQLITE_ROW && rc != SQLITE_DONE) {
                //this->_logger.LogError("FaceDatabase::GetNumEmbeddings. SQL step error:", sqlite3_errmsg(m_db), __FILE__, __LINE__);
                resultCode = -2;
            }
            numEmbeds = sqlite3_column_int(stmt, 0);
            sqlite3_finalize(stmt);
            resultCode = numEmbeds;
            return resultCode;
        }
        catch (std::exception& e) {
            //this->_logger.LogFatal("FaceDatabase::GetNumEmbeddings", e.what(), __FILE__, __LINE__);
            return 0;
        }
    }

    int FaceDatabase::GetEmbeddings(std::unique_ptr<ANSFRBase>& recognizer) {
        try {
            std::string sql;
            sqlite3_stmt* stmt;
            int rc;
            int resultCode = 0;
            std::string userId;
            int numEmbeds = GetNumEmbeddings();
            _logger.LogDebug("FaceDatabase::GetEmbeddings", "There are " + std::to_string(numEmbeds) + " embeddings in database", __FILE__, __LINE__);
            // get embedding
            //_mutex.lock();
            std::lock_guard<std::mutex> lock(_mutex);
            sql = "SELECT * FROM FACE;";
            rc = sqlite3_prepare_v2(m_db, sql.c_str(), -1, &stmt, NULL);
            if (rc != SQLITE_OK) {
                //this->_logger.LogError("FaceDatabase::GetEmbeddings. SQL step error:", sqlite3_errmsg(m_db), __FILE__, __LINE__);
                resultCode = -1;
            }
            while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
                const char* userIdText = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 1));
                if (!userIdText) continue;
                userId = std::string(userIdText);
                float* embedding = (float*)sqlite3_column_blob(stmt, 3);
                if (!embedding) continue;
                recognizer->AddEmbedding(userId, embedding);
            }
            if (rc != SQLITE_DONE) {
                //this->_logger.LogError("FaceDatabase::GetEmbeddings. SQL error:", sqlite3_errmsg(m_db), __FILE__, __LINE__);
            }
            sqlite3_finalize(stmt);
            resultCode = 0;
            //_mutex.unlock();
            return resultCode;

        }
        catch (std::exception& e) {
            //this->_logger.LogFatal("FaceDatabase::GetEmbeddings", e.what(), __FILE__, __LINE__);
            //_mutex.unlock();
            return 0;
        }
    }
    int FaceDatabase::GetEmbeddings(ANSFRBase& recognizer) {
        try {
            std::string sql;
            sqlite3_stmt* stmt;
            int rc;
            int resultCode = 0;
            std::string userId;
            int numEmbeds = GetNumEmbeddings();
            _logger.LogDebug("FaceDatabase::GetEmbeddings", "There are " + std::to_string(numEmbeds) + " embeddings in database", __FILE__, __LINE__);
            // get embedding
            //_mutex.lock();
            std::lock_guard<std::mutex> lock(_mutex);
            sql = "SELECT * FROM FACE;";
            rc = sqlite3_prepare_v2(m_db, sql.c_str(), -1, &stmt, NULL);
            if (rc != SQLITE_OK) {
                //this->_logger.LogError("FaceDatabase::GetEmbeddings. SQL step error:", sqlite3_errmsg(m_db), __FILE__, __LINE__);
                resultCode = -1;
            }
            while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
                const char* userIdText = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 1));
                if (!userIdText) continue;
                userId = std::string(userIdText);
                float* embedding = (float*)sqlite3_column_blob(stmt, 3);
                if (!embedding) continue;
                recognizer.AddEmbedding(userId, embedding);
            }
            if (rc != SQLITE_DONE) {
                //this->_logger.LogError("FaceDatabase::GetEmbeddings. SQL error:", sqlite3_errmsg(m_db), __FILE__, __LINE__);
            }
            sqlite3_finalize(stmt);
            resultCode = 0;
            //_mutex.unlock();
            return resultCode;

        }
        catch (std::exception& e) {
            //this->_logger.LogFatal("FaceDatabase::GetEmbeddings", e.what(), __FILE__, __LINE__);
            //_mutex.unlock();
            return 0;
        }
    }

    int FaceDatabase::GetAllEmbeddingRecords(std::vector<FaceEmbeddingRecord>& records) {
        try {
            std::lock_guard<std::mutex> lock(_mutex);
            records.clear();

            int numEmbeds = 0;
            {
                // Count for pre-allocation (inline, mutex already held)
                sqlite3_stmt* countStmt;
                int rc = sqlite3_prepare_v2(m_db, "SELECT COUNT(*) FROM FACE;", -1, &countStmt, NULL);
                if (rc == SQLITE_OK && sqlite3_step(countStmt) == SQLITE_ROW) {
                    numEmbeds = sqlite3_column_int(countStmt, 0);
                }
                sqlite3_finalize(countStmt);
            }

            records.reserve(numEmbeds);

            sqlite3_stmt* stmt;
            int rc = sqlite3_prepare_v2(m_db,
                "SELECT ID, USER, EMBEDDING FROM FACE;", -1, &stmt, NULL);
            if (rc != SQLITE_OK) {
                return -1;
            }

            while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
                int faceId = sqlite3_column_int(stmt, 0);

                const char* userIdText = reinterpret_cast<const char*>(
                    sqlite3_column_text(stmt, 1));
                if (!userIdText) continue;

                const float* embData = reinterpret_cast<const float*>(
                    sqlite3_column_blob(stmt, 2));
                int embBytes = sqlite3_column_bytes(stmt, 2);
                int embSize = embBytes / static_cast<int>(sizeof(float));
                if (!embData || embSize <= 0) continue;

                FaceEmbeddingRecord record;
                record.faceId = faceId;
                record.userId = std::string(userIdText);
                record.embedding.assign(embData, embData + embSize);
                records.push_back(std::move(record));
            }

            sqlite3_finalize(stmt);
            return 0;
        }
        catch (const std::exception& e) {
            return -1;
        }
    }

    int FaceDatabase::GetUsersWithFaceIds(std::vector<int>& ids, std::vector<std::string>& codes,
        std::vector<std::string>& userNames, std::vector<std::vector<int>>& faceIdsByUser) {
        // Fix #12: Single JOIN query replaces N+1 GetUser + GetFaceIdsByUser calls
        std::lock_guard<std::mutex> lock(_mutex);
        ids.clear();
        codes.clear();
        userNames.clear();
        faceIdsByUser.clear();

        try {
            sqlite3_stmt* stmt;
            int rc = sqlite3_prepare_v2(m_db,
                "SELECT U.ID, U.CODE, U.NAME, F.ID AS FACE_ID "
                "FROM USER U LEFT JOIN FACE F ON U.ID = F.USER "
                "ORDER BY U.ID;",
                -1, &stmt, NULL);
            if (rc != SQLITE_OK) {
                _logger.LogError("FaceDatabase::GetUsersWithFaceIds",
                    std::string("SQL error: ") + sqlite3_errmsg(m_db), __FILE__, __LINE__);
                return -1;
            }

            int lastUserId = -1;
            while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
                int userId = sqlite3_column_int(stmt, 0);
                if (userId != lastUserId) {
                    // New user row
                    const char* codeText = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 1));
                    const char* nameText = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 2));
                    ids.push_back(userId);
                    codes.push_back(codeText ? std::string(codeText) : "");
                    userNames.push_back(nameText ? std::string(nameText) : "");
                    faceIdsByUser.emplace_back();
                    lastUserId = userId;
                }
                // Append face ID (may be NULL if user has no faces — LEFT JOIN)
                if (sqlite3_column_type(stmt, 3) != SQLITE_NULL) {
                    faceIdsByUser.back().push_back(sqlite3_column_int(stmt, 3));
                }
            }
            if (rc != SQLITE_DONE) {
                _logger.LogError("FaceDatabase::GetUsersWithFaceIds",
                    std::string("SQL step error: ") + sqlite3_errmsg(m_db), __FILE__, __LINE__);
            }
            sqlite3_finalize(stmt);
            return 1;
        }
        catch (const std::exception& e) {
            _logger.LogError("FaceDatabase::GetUsersWithFaceIds", e.what(), __FILE__, __LINE__);
            return 0;
        }
    }

    FaceDatabase::~FaceDatabase() {
        try {
            Destroy();
        }
        catch (std::exception& e) {
            _logger.LogError("FaceDatabase::~FaceDatabase", e.what(), __FILE__, __LINE__);
        }

    }

    bool FaceDatabase::Destroy() {
        std::lock_guard<std::mutex> lock(_mutex);
        try {
            if (!m_db) return true;
            int rc = sqlite3_close(m_db);
            if (rc == SQLITE_OK) {
                //this->_logger.LogDebug("Database::Destroy", "Success!", __FILE__, __LINE__);
                m_db = nullptr;
                return true;
            }
            else {
                std::string errorCode = "Cannot close database connection.Error code:" + std::to_string(rc);
                //this->_logger.LogError("Database::Destroy", errorCode, __FILE__, __LINE__);
                return false;
            }
        }
        catch (std::exception& e) {
            //this->_logger.LogFatal("FaceDatabase::Destroy", e.what(), __FILE__, __LINE__);
            return false;
        }
    }
}