#include "Database.h"
#include "BoostLog.h"
#include "sqlite3.h"

bool Database::addPalmFeature(const PalmFeature &palm) {
    sqlite3_stmt *statement = nullptr;
    constexpr const char *sql = "INSERT INTO palm_feature (username,feature) VALUES (?,?);";
    int status = sqlite3_prepare_v2(m_sqlite, sql, -1, &statement, 0);
    if (status != SQLITE_OK) {
        LOG(error) << "Failed to prepare statement: " << sqlite3_errmsg(m_sqlite);
        return false;
    }
    sqlite3_bind_text(statement, 1, palm.username.c_str(), -1, SQLITE_TRANSIENT);
    sqlite3_bind_blob(statement, 2, palm.feature.data(), palm.feature.size(), SQLITE_TRANSIENT);

    status = sqlite3_step(statement);
    if (status != SQLITE_DONE) {
        LOG(error) << "Failed to execute statement: " << sqlite3_errmsg(m_sqlite);
        return false;
    }

    sqlite3_finalize(statement);
    return true;
}

PalmFeatures Database::palmFeatures() const {
    PalmFeatures ret;
    sqlite3_stmt *statement = nullptr;
    constexpr const char *sql = "SELECT * FROM palm_feature";
    if (sqlite3_prepare_v2(m_sqlite, sql, -1, &statement, NULL) != SQLITE_OK) {
        LOG(error) << "Can't prepare statement: " << sqlite3_errmsg(m_sqlite);
        return ret;
    }
    while (sqlite3_step(statement) == SQLITE_ROW) {
        PalmFeature feature;
        feature.id = sqlite3_column_int64(statement, 0);
        feature.username = reinterpret_cast<const char *>(sqlite3_column_text(statement, 1));

        auto data = reinterpret_cast<const uint8_t *>(sqlite3_column_blob(statement, 2));
        int size = sqlite3_column_bytes(statement, 2);
        feature.feature = std::vector<uint8_t>(data, data + size);
        ret.push_back(feature);
    }

    return ret;
}

bool Database::open(const std::string &path) {
    if (sqlite3_open(path.c_str(), &m_sqlite) != SQLITE_OK) {
        LOG(error) << "sqlite3_open() failed: " << sqlite3_errmsg(m_sqlite);
        return false;
    }
    initializeTables();
    return true;
}

void Database::initializeTables() {
    constexpr const char *sql = R"(
        CREATE TABLE IF NOT EXISTS palm_feature(
            id          INTEGER PRIMARY KEY,
            username    TEXT    NOT NULL,
            feature     BLOB
        );
    )";
    char *errorMessage = nullptr;
    int status = sqlite3_exec(m_sqlite, sql, 0, 0, &errorMessage);
    if (status != SQLITE_OK) {
        LOG(error) << "SQL error: " << errorMessage;
        sqlite3_free(errorMessage);
    }
}
