#include "api_v1_apps.hpp"
#include "dataTypeList.hpp"
#include "Disposition.hpp"
#include <future>
#include <iostream>
#include <drogon/drogon.h>
#include "httpHelper.hpp"

using namespace api::v1;

// Add definition of your processing function here

/**
 * 
 * @description: 获取app模板
 * @param {HttpRequestPtr&} req
 * @param {function<void (HttpResponsePtr &)>} &
 * @param {string} token
 * @return {*}
 */
void apps::getTemplate(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr &)> &&callback, std::string token, std::string name){
    auto clientPtr = drogon::app().getDbClient();
    auto f = clientPtr->execSqlAsyncFuture("SELECT `DATA` FROM InsServerDB.`InsDataDescription` JOIN InsServerDB.InsKsTemplate ON InsServerDB.InsKsTemplate.DESCRIPTIONID = InsServerDB.InsDataDescription.DESCRIPTIONID  \
            WHERE InsServerDB.InsDataDescription.USERID = ? AND InsServerDB.InsDataDescription.NAME = ?",ins::Disposition::getPtr()->getUserId(), name);
    try{
        auto SqlResult = f.get();
        HttpResultMsg<KubeSphereTempalte, HttpNull> msg;
        HttpResponsePtr resp;
        std::string json;
        if(SqlResult.empty()){
            msg.code = "-5";
            msg.msg = "失败, 该AI模板不存在";
            msg.ok = false;
            msg.objectToJson(json);
            resp = HttpResponse::newHttpResponse();
            resp->setBody(json);
            callback(resp);
            return;
        }
        if(SqlResult.size() > 1) WarnL << name <<  "模板不唯一" << endl;
        ins::Disposition::Ptr disposition = ins::Disposition::getPtr();
        std::string data;
        for(auto line : SqlResult) {
            data = line["DATA"].as<std::string>();
        }
        msg.code = "200";
        msg.msg = "成功";
        msg.ok = true;
        KubeSphereTempalte t;
        t.CONTENTTYPE = "application/json";
        t.DATA = data;
        msg.datas.push_back(t);
        msg.objectToJson(json);
        resp = HttpResponse::newHttpResponse();
        resp->setBody(json);
        callback(resp);
    }
    catch(const drogon::orm::DrogonDbException &e)
    {
        ErrorL << "error:" << e.base().what() << std::endl;
        auto *pluginPtr=app().getPlugin<httpHelper>();
        callback(pluginPtr->makeWrongReply(e.base().what()));
    }
}

/**
 * @description: 获取AI列表
 * @param {HttpRequestPtr&} req
 * @param {function<void (HttpResponsePtr &)>} &
 * @param {string} token
 * @return {*}
 */
void apps::getAIList(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr &)> &&callback, std::string token){
    auto clientPtr = drogon::app().getDbClient();
    auto f = clientPtr->execSqlAsyncFuture("SELECT NAME,DESCRIPTION FROM `InsDataDescription` WHERE USERID = ? AND TYPE = 1",ins::Disposition::getPtr()->getUserId());
    try
    {
        auto SqlResult = f.get(); // Block until we get the result or catch the exception;
        HttpResultMsg<InsAIList, HttpNull> request;
        for(auto line: SqlResult){
            InsAIList ai;
            ai.NAME = line["NAME"].as<std::string>();
            ai.DESCRIPTION = line["DESCRIPTION"].as<std::string>();
            request.datas.push_back(ai);
        }
        std::string json;
        request.code = "200";
        request.msg = "成功";
        request.ok = true;
        request.objectToJson(json);
        HttpResponsePtr resp;
        resp = HttpResponse::newHttpResponse();
        resp->setBody(json);
        callback(resp);
    }
    catch(const drogon::orm::DrogonDbException &e)
    {
        ErrorL << "error:" << e.base().what() << std::endl;
        auto *pluginPtr=app().getPlugin<httpHelper>();
        callback(pluginPtr->makeWrongReply(e.base().what()));
    }
}

/**
 * @description: 获取AI
 * @param {HttpRequestPtr&} req
 * @param {function<void (HttpResponsePtr &)>} &
 * @param {string} token
 * @param {string} name
 * @return {*}
 */
void apps::getAI(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr &)> &&callback, std::string token, std::string name){
    auto clientPtr = drogon::app().getDbClient();
    auto f = clientPtr->execSqlAsyncFuture("SELECT `DATA` FROM InsServerDB.`InsDataDescription` JOIN InsServerDB.InsKsTemplate ON InsServerDB.InsKsTemplate.DESCRIPTIONID = InsServerDB.InsDataDescription.DESCRIPTIONID  \
         WHERE InsServerDB.InsDataDescription.USERID = ? AND InsServerDB.InsDataDescription.NAME = ?",ins::Disposition::getPtr()->getUserId(), name);
    try{
        auto SqlResult = f.get(); // Block until we get the result or catch the exception;
        HttpResultMsg<InsAIInfo, HttpNull> request;
        for(auto line : SqlResult) {
            InsAIInfo ai;
            ai.NAME = name;
            ai.DATA = line["DATA"].as<std::string>();
            request.datas.push_back(ai);
        }
        std::string json;
        request.code = "200";
        request.msg = "成功";
        request.ok = true;
        request.objectToJson(json);
        HttpResponsePtr resp;
        resp = HttpResponse::newHttpResponse();
        resp->setBody(json);
        callback(resp);
    }
    catch(const drogon::orm::DrogonDbException &e)
    {
        ErrorL << "error:" << e.base().what() << std::endl;
        auto *pluginPtr=app().getPlugin<httpHelper>();
        callback(pluginPtr->makeWrongReply(e.base().what()));
    }
}

/**
 * @description: postAI
 * @param {HttpRequestPtr&} req
 * @param {function<void (HttpResponsePtr &)>} &
 * @param {string} token
 * @param {string} name
 * @return {*}
 */
void apps::postAI(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr &)> &&callback, std::string token, std::string name, std::string uri){
    auto clientPtr = drogon::app().getDbClient();
    auto f = clientPtr->execSqlAsyncFuture("SELECT `DATA` FROM InsServerDB.`InsDataDescription` JOIN InsServerDB.InsKsTemplate ON InsServerDB.InsKsTemplate.DESCRIPTIONID = InsServerDB.InsDataDescription.DESCRIPTIONID  \
            WHERE InsServerDB.InsDataDescription.USERID = ? AND InsServerDB.InsDataDescription.NAME = ?",ins::Disposition::getPtr()->getUserId(), name);
    try{
        auto SqlResult = f.get();
        HttpResultMsg<HttpNull, HttpNull> msg;
        HttpResponsePtr resp;
        std::string json;
        if(SqlResult.empty() || uri == ""){
            msg.code = "-5";
            msg.msg = "失败, 该AI模板不存在或流地址为空";
            msg.ok = false;
            msg.objectToJson(json);
            resp = HttpResponse::newHttpResponse();
            resp->setBody(json);
            callback(resp);
            return;
        }
        if(SqlResult.size() > 1) WarnL << name <<  "模板不唯一" << endl;
        ins::Disposition::Ptr disposition = ins::Disposition::getPtr();
        std::string data;
        for(auto line : SqlResult) {
            data = line["DATA"].as<std::string>();
        }
        std::string src = "http://"+ disposition->k8s_IP + ":" + std::to_string(disposition->k8s_port);
        auto client = HttpClient::newHttpClient(src);
        auto send_req = HttpRequest::newHttpRequest();
        send_req->setMethod(drogon::Post);
        send_req->setPath("/apis/apps/v1/namespaces/" + disposition->getWorkspace() +  "/deployments");
        send_req->addHeader("Authorization", disposition->KsToken.token_type + " " + disposition->KsToken.access_token);
        send_req->setContentTypeCode(CT_APPLICATION_JSON);
        send_req->setBody(data);
        auto result = client->sendRequest(send_req);
        auto *pluginPtr=app().getPlugin<httpHelper>();
        auto request = pluginPtr->replyRequest(result,send_req->getMethod());
        callback(request);
    }
    catch(const drogon::orm::DrogonDbException &e)
    {
        ErrorL << "error:" << e.base().what() << std::endl;
        auto *pluginPtr=app().getPlugin<httpHelper>();
        callback(pluginPtr->makeWrongReply(e.base().what()));
    }
}

/**
 * @description: deleteAI
 * @param {HttpRequestPtr&} req
 * @param {function<void (HttpResponsePtr &)>} &
 * @param {string} token
 * @param {string} name
 * @return {*}
 */
void apps::deleteAI(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr &)> &&callback, std::string token, std::string name){
    ins::Disposition::Ptr disposition = ins::Disposition::getPtr();
    std::string uri = "http://"+ disposition->k8s_IP + ":" + std::to_string(disposition->k8s_port);
    auto client = HttpClient::newHttpClient(uri);
    auto send_req = HttpRequest::newHttpRequest();
    send_req->setMethod(drogon::Delete);
    send_req->setPath("/apis/apps/v1/namespaces/" + disposition->getWorkspace() +  "/deployments/" + name);
    send_req->addHeader("Authorization", disposition->KsToken.token_type + " " + disposition->KsToken.access_token);
    auto result = client->sendRequest(send_req);
    auto *pluginPtr=app().getPlugin<httpHelper>();
    auto request = pluginPtr->replyRequest(result,send_req->getMethod());
    callback(request);
}

