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

using namespace api::v1;

/**
 * @description: 获取Nodes
 * @param {HttpRequestPtr&} req
 * @param {HttpResponsePtr} &
 * @return {*}
 */
void K8s::getNodes(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr &)> &&callback, 
    std::string token){
    auto clientPtr = drogon::app().getDbClient();
    auto f = clientPtr->execSqlAsyncFuture("SELECT UID,NAME,CREATIONTIMESTAMP,LABELS,CAPACITY,ALLOCATABLE,CONDITIONS,ADDRESSES \
         FROM InsServerDB.`InsKsNodes` WHERE USERID = ? and ISDELETE = 0",ins::Disposition::getPtr()->getUserId());
    try
    {
        auto SqlResult = f.get(); // Block until we get the result or catch the exception;
        HttpResultMsg<KubeSphereNodes, HttpNull> request;
        for(auto line: SqlResult){
            KubeSphereNodes data;
            data.UID = line["UID"].as<std::string>();
            data.NAME = line["NAME"].as<std::string>();
            data.CREATIONTIMESTAMP = line["CREATIONTIMESTAMP"].as<std::string>();
            data.LABELS = line["LABELS"].as<std::string>();
            data.CAPACITY = line["CAPACITY"].as<std::string>();
            data.ALLOCATABLE = line["ALLOCATABLE"].as<std::string>();
            data.CONDITIONS = line["CONDITIONS"].as<std::string>();
            data.ADDRESSES = line["ADDRESSES"].as<std::string>();
            request.datas.push_back(data);
        }
        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: 获取Serviers
 * @param {HttpRequestPtr&} req
 * @param {HttpResponsePtr} &
 * @return {*}
 */
void K8s::getServers(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr &)> &&callback, 
     std::string token) {
    auto clientPtr = drogon::app().getDbClient();
    auto f = clientPtr->execSqlAsyncFuture("SELECT UID,NAME,NAMESPACE,LABELS,PORTS,CLUSTERIP,TYPE \
         FROM InsServerDB.`InsKsServers` WHERE USERID = ? and ISDELETE = 0", ins::Disposition::getPtr()->getUserId());
    try
    {
        auto SqlResult = f.get(); // Block until we get the result or catch the exception;
        HttpResultMsg<KubeSphereServers, HttpNull> request;
        for(auto line: SqlResult){
            KubeSphereServers data;
            data.UID = line["UID"].as<std::string>();
            data.NAME = line["NAME"].as<std::string>();
            data.NAMESPACE = line["NAMESPACE"].as<std::string>();
            data.LABELS = line["LABELS"].as<std::string>();
            data.PORTS = line["PORTS"].as<std::string>();
            data.CLUSTERIP = line["CLUSTERIP"].as<std::string>();
            data.TYPE = line["TYPE"].as<std::string>();
            request.datas.push_back(data);
        }
        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: 
 * @param {HttpRequestPtr&} req
 * @param {function<void (HttpResponsePtr &)>} &
 * @param {string} token
 * @return {*}
 */
void K8s::postServers(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr &)> &&callback,  std::string token){
    ins::Disposition::Ptr disposition = ins::Disposition::getPtr();
    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() +  "/services");
    send_req->addHeader("Authorization", disposition->KsToken.token_type + " " + disposition->KsToken.access_token);
    send_req->setContentTypeCode(req->getContentType());
    send_req->setBody(req->getBody().data());
    auto result = client->sendRequest(send_req);
    auto *pluginPtr=app().getPlugin<httpHelper>();
    auto request = pluginPtr->replyRequest(result,send_req->getMethod());
    callback(request);
}

/**
 * @description: 更新Servers
 * @param {HttpRequestPtr&} req
 * @param {function<void (HttpResponsePtr &)>} &
 * @param {string} token
 * @return {*}
 */
void K8s::putServers(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr &)> &&callback,  std::string token, std::string name){
    ins::Disposition::Ptr disposition = ins::Disposition::getPtr();
    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() +  "/services/" + name);
    send_req->addHeader("Authorization", disposition->KsToken.token_type + " " + disposition->KsToken.access_token);
    send_req->setContentTypeCode(req->getContentType());
    send_req->setBody(req->getBody().data());
    auto result = client->sendRequest(send_req);
    auto *pluginPtr=app().getPlugin<httpHelper>();
    auto request = pluginPtr->replyRequest(result,send_req->getMethod());
    callback(request);
}

/**
 * @description: 删除Servers
 * @param {HttpRequestPtr&} req
 * @param {function<void (HttpResponsePtr &)>} &
 * @param {string} token
 * @return {*}
 */
void K8s::deleteServers(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr &)> &&callback,  std::string token, std::string name){
    ins::Disposition::Ptr disposition = ins::Disposition::getPtr();
    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::Delete);
    send_req->setPath("/apis/apps/v1/namespaces/" + disposition->getWorkspace() +  "/services/" + 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);
}

/**
 * @description: 获取Pods
 * @param {HttpRequestPtr&} req
 * @param {function<void (HttpResponsePtr &)>} &
 * @param {string} token
 * @return {*}
 */
void K8s::getPods(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr &)> &&callback, std::string token){
    auto clientPtr = drogon::app().getDbClient();
    auto f = clientPtr->execSqlAsyncFuture("SELECT UID,NAME,NAMESPACE,LABELS,CONTAINERS,PHASE,CONDITIONS \
         FROM InsServerDB.`InsKsPods` WHERE USERID = ? and ISDELETE = 0",ins::Disposition::getPtr()->getUserId());
    try
    {
        auto SqlResult = f.get(); // Block until we get the result or catch the exception;
        HttpResultMsg<KubeSpherePods, HttpNull> request;
        for(auto line: SqlResult){
            KubeSpherePods data;
            data.UID = line["UID"].as<std::string>();
            data.NAME = line["NAME"].as<std::string>();
            data.NAMESPACE = line["NAMESPACE"].as<std::string>();
            data.LABELS = line["LABELS"].as<std::string>();
            data.CONTAINERS = line["CONTAINERS"].as<std::string>();
            data.PHASE = line["PHASE"].as<std::string>();
            data.CONDITIONS = line["CONDITIONS"].as<std::string>();
            request.datas.push_back(data);
        }
        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: 
 * @param {HttpRequestPtr&} req
 * @param {function<void (HttpResponsePtr &)>} &
 * @param {string} token
 * @return {*}
 */
void K8s::deletePods(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr &)> &&callback, std::string token, std::string name){
    ins::Disposition::Ptr disposition = ins::Disposition::getPtr();
    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::Delete);
    send_req->setPath("/api/v1/namespaces/" + disposition->getWorkspace() +  "/pods/" + 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);
}

/**
 * @description: GET
 * @param {HttpRequestPtr&} req
 * @param {function<void (HttpResponsePtr &)>} &
 * @param {string} token
 * @return {*}
 */
void K8s::getDeployment(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr &)> &&callback, std::string token){
    auto clientPtr = drogon::app().getDbClient();
    auto f = clientPtr->execSqlAsyncFuture("SELECT UID,NAME,NAMESPACE,LABELS,CONTAINERS,PHASE,CONDITIONS \
         FROM InsServerDB.`InsKsDeployments` WHERE USERID = ? and ISDELETE = 0",ins::Disposition::getPtr()->getUserId());
    try
    {
        auto SqlResult = f.get(); // Block until we get the result or catch the exception;
        HttpResultMsg<KubeSphereDeployments, HttpNull> request;
        for(auto line: SqlResult){
            KubeSphereDeployments data;
            data.UID = line["UID"].as<std::string>();
            data.NAME = line["NAME"].as<std::string>();
            data.NAMESPACE = line["NAMESPACE"].as<std::string>();
            data.LABELS = line["LABELS"].as<std::string>();
            data.CONTAINERS = line["CONTAINERS"].as<std::string>();
            data.PHASE = line["PHASE"].as<std::string>();
            data.CONDITIONS = line["CONDITIONS"].as<std::string>();
            request.datas.push_back(data);
        }
        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: post
 * @param {HttpRequestPtr&} req
 * @param {function<void (HttpResponsePtr &)>} &
 * @param {string} token
 * @return {*}
 */
void K8s::postDeployment(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr &)> &&callback, std::string token){
    ins::Disposition::Ptr disposition = ins::Disposition::getPtr();
    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(req->getContentType());
    send_req->setBody(req->getBody().data());
    auto result = client->sendRequest(send_req);
    auto *pluginPtr=app().getPlugin<httpHelper>();
    auto request = pluginPtr->replyRequest(result,send_req->getMethod());
    callback(request);
}

/**
 * @description: Put
 * @param {HttpRequestPtr&} req
 * @param {function<void (HttpResponsePtr &)>} &
 * @param {string} token
 * @return {*}
 */
void K8s::putDeployment(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr &)> &&callback, std::string token, std::string name){
    ins::Disposition::Ptr disposition = ins::Disposition::getPtr();
    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::Put);
    send_req->setPath("/apis/apps/v1/namespaces/" + disposition->getWorkspace() +  "/deployments/" + name);
    send_req->addHeader("Authorization", disposition->KsToken.token_type + " " + disposition->KsToken.access_token);
    send_req->setContentTypeCode(req->getContentType());
    send_req->setBody(req->getBody().data());
    auto result = client->sendRequest(send_req);
    auto *pluginPtr=app().getPlugin<httpHelper>();
    auto request = pluginPtr->replyRequest(result,send_req->getMethod());
    callback(request);
}

/**
 * @description: delete
 * @param {HttpRequestPtr&} req
 * @param {HttpResponsePtr} &
 * @return {*}
 */
void K8s::deleteDeployment(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr &)> &&callback, std::string token, \
     std::string name){
    ins::Disposition::Ptr disposition = ins::Disposition::getPtr();
    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::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);
}