/*
 * Copyright 2024 KylinSoft Co., Ltd.
 *
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program. If not, see <https://www.gnu.org/licenses/>.
 */

#include "embedding.h"

#include <cstring>

#include "embeddingcommon.h"
#include "error.h"
#include "imageembeddingsession.h"
#include "textembeddingsession.h"
float *embedding_result_get_vector_data(EmbeddingResult *result) {
    if (!result) return nullptr;
    return result->vector_result.data();
}

int embedding_result_get_vector_length(EmbeddingResult *result) {
    if (!result) return 0;
    return result->vector_result.size();
}

int embedding_result_get_error_code(EmbeddingResult *result) {
    if (!result) return COREAI_EMBEDDING_INPUT_ERROR;
    return result->error_code;
}
const char *embedding_result_get_error_message(EmbeddingResult *result) {
    if (!result) return nullptr;
    return result->error_message.c_str();
}

void embedding_result_destroy(EmbeddingResult **result) {
    // 双重检查
    if (!result) return;
    if (*result != nullptr) {
        delete *result;
        *result = nullptr;
    }
}
void embedding_model_info_destroy(char *result) { delete[] result; }

_TextEmbeddingSession *text_embedding_create_session() {
    _TextEmbeddingSession *textEmbeddingSession = new _TextEmbeddingSession();
    return textEmbeddingSession;
}
void text_embedding_destroy_session(_TextEmbeddingSession **session) {
    // 双重检查
    if (!session) return;
    if (*session != nullptr) {
        delete *session;
        *session = nullptr;
    }
}
int text_embedding_init_session(_TextEmbeddingSession *session) {
    if (!session) return COREAI_EMBEDDING_INPUT_ERROR;

    // 先init 与runtime的连接
    if (session->connect() != 0) return COREAI_EMBEDDING_CONNECTION_ERROR;
    // 模型加载
    return session->init();
}
bool text_embedding_get_model_info(_TextEmbeddingSession *session,
                                   char **model_info) {
    if (!session) return false;
    std::string res;
    res = session->getModelInfo();
    if (!res.empty()) {
        size_t length = res.size() + 1;
        *model_info = new char[length];
        std::strcpy(*model_info, res.c_str());
        return true;
    }
    return false;
}

bool text_embedding(TextEmbeddingSession *session, const char *text,
                    EmbeddingResult **result) {
    if (!session || !text) {
        *result = new EmbeddingResult(COREAI_EMBEDDING_INPUT_ERROR,
                                      "Incorrect input parameter");
        return false;
    }
    // 这里面会开辟内存 所以需要用户调用destory接口
    *result = session->embeddingText(text);
    if (!result || !(*result)) return false;
    return true;
}

void text_embedding_async(_TextEmbeddingSession *session, const char *text,
                          TextEmbeddingResultCallback callback,
                          void *callback_user_data) {
    if (!session || !text) {
        EmbeddingResult result(COREAI_EMBEDDING_INPUT_ERROR,
                               "Incorrect input parameter");
        callback(&result, callback_user_data);
        return;
    }
    session->embeddingTextAsync(text, callback, callback_user_data);
}

_ImageEmbeddingSession *image_embedding_create_session() {
    _ImageEmbeddingSession *imageEmbeddingSession =
        new _ImageEmbeddingSession();
    return imageEmbeddingSession;
}
void image_embedding_destroy_session(_ImageEmbeddingSession **session) {
    if (!session) return;
    if (*session != nullptr) {
        delete *session;
        *session = nullptr;
    }
}
int image_embedding_init_session(_ImageEmbeddingSession *session) {
    if (!session) return COREAI_EMBEDDING_INPUT_ERROR;

    // 先init 与runtime的连接
    if (session->connect() != 0) return COREAI_EMBEDDING_CONNECTION_ERROR;
    // 模型加载
    return session->init();
}

bool image_embedding_get_model_info(_ImageEmbeddingSession *session,
                                    char **model_info) {
    if (!session) return false;
    std::string res;
    res = session->getModelInfo();
    if (!res.empty()) {
        size_t length = res.size() + 1;
        *model_info = new char[length];
        std::strcpy(*model_info, res.c_str());
        return true;
    }
    return false;
}

bool text_embedding_by_image_model(_ImageEmbeddingSession *session,
                                   const char *text, EmbeddingResult **result) {
    if (!session || !text) {
        *result = new EmbeddingResult(COREAI_EMBEDDING_INPUT_ERROR,
                                      "Incorrect input parameter");
        return false;
    }

    *result = session->embeddingText(
        text);  // 这里面会开辟内存 所以需要用户调用destory接口
    if (!result || !(*result)) return false;
    return true;
}

bool image_embedding_by_image_file(_ImageEmbeddingSession *session,
                                   const char *image_file,
                                   EmbeddingResult **result) {
    if (!session || !image_file) {
        *result = new EmbeddingResult(COREAI_EMBEDDING_INPUT_ERROR,
                                      "Incorrect input parameter");
        return false;
    }

    *result = session->embeddingImage(
        image_file);  // 这里面会开辟内存 所以需要用户调用destory接口
    if (!result || !(*result)) return false;
    return true;
}

bool image_embedding_by_base64_image_data(_ImageEmbeddingSession *session,
                                          const unsigned char *image_data,
                                          unsigned int image_data_length,
                                          EmbeddingResult **result) {
    if (!session || !image_data) {
        *result = new EmbeddingResult(COREAI_EMBEDDING_INPUT_ERROR,
                                      "Incorrect input parameter");
        return false;
    }
    std::string base64_str(reinterpret_cast<const char *>(image_data),
                           image_data_length);
    *result = session->embeddingBase64Image(
        base64_str);  // 这里面会开辟内存 所以需要用户调用destory接口
    if (!result || !(*result)) return false;
    return true;
}

void text_embedding_by_image_model_async(_ImageEmbeddingSession *session,
                                         const char *text,
                                         ImageEmbeddingResultCallback callback,
                                         void *callback_user_data) {
    if (!session || !text) {
        EmbeddingResult result(COREAI_EMBEDDING_INPUT_ERROR,
                               "Incorrect input parameter");
        callback(&result, callback_user_data);
        return;
    }
    session->embeddingTextAsync(text, callback, callback_user_data);
}
void image_embedding_from_by_file_async(_ImageEmbeddingSession *session,
                                        const char *file_path,
                                        ImageEmbeddingResultCallback callback,
                                        void *callback_user_data) {
    if (!session || !file_path) {
        EmbeddingResult result(COREAI_EMBEDDING_INPUT_ERROR,
                               "Incorrect input parameter");
        callback(&result, callback_user_data);
        return;
    }
    session->embeddingImageAsync(file_path, callback, callback_user_data);
}

void image_embedding_by_base64_image_data_async(
    _ImageEmbeddingSession *session, const unsigned char *image_data,
    unsigned int image_data_length, ImageEmbeddingResultCallback callback,
    void *callback_user_data) {
    if (!session || !image_data) {
        EmbeddingResult result(COREAI_EMBEDDING_INPUT_ERROR,
                               "Incorrect input parameter");
        callback(&result, callback_user_data);
        return;
    }
    std::string base64_image_str(reinterpret_cast<const char *>(image_data),
                                 image_data_length);
    session->embeddingBase64ImageAsync(base64_image_str, callback,
                                       callback_user_data);
}