/*
 * @Description: 数据中心
 * @Version: 1.0
 * @Autor: lishengyin
 * @Date: 2022-04-02 13:58:50
 * @LastEditors: lishengyin
 * @LastEditTime: 2022-04-26 17:09:21
 */
#include "GetCenter.hpp"
#include "Disposition.hpp"
#include "Sectorpower.hpp"
#include <vector>
#include <httplib.h>
using namespace httplib;

namespace ins{

    static std::shared_ptr<GetCenter> m_GetCenter = nullptr;

    /**
     * @description: 初始化
     * @param {*}
     * @return {*}
     */    
    int8_t GetCenter::Init() {
        if(this->valid) return OK;
        Disposition::Ptr disposition = Disposition::getPtr();
        #if defined(SUPPORT_DYNAMIC_TEMPLATE)
            //初始化数据
            SqlPool::Instance().Init(disposition->mysql_IP,disposition->mysql_port,"","root",""/*,character*/);
        #else
            //由于需要编译器对可变参数模板的支持，所以gcc5.0以下一般都不支持，否则编译报错
            ErrorL << "your compiler does not support variable parameter templates!" << endl;
            return ERR;
        #endif //defined(SUPPORT_DYNAMIC_TEMPLATE)
        // 初始化数据库连接池
        SqlPool::Instance().setSize(2 + thread::hardware_concurrency());
        this->valid = true;
        return OK;
    }

    /**
     * @description: 释放
     * @param {*}
     * @return {*}
     */    
    void GetCenter::Destroy() {
        return;
    }

    /**
     * @description: 创建新的实例
     * @param {*}
     * @return {*}
     */    
    std::shared_ptr<GetCenter> GetCenter::CreateNew(){
        if(m_GetCenter == nullptr) m_GetCenter = std::shared_ptr<GetCenter>(new GetCenter);
        return m_GetCenter;
    }
    
    /**
     * @description: 获取ptr
     * @param {*}
     * @return {*}
     */    
    std::shared_ptr<GetCenter> GetCenter::getPtr(){
        return m_GetCenter;
    }

    /**
     * @description: 获取服务
     * @param {*}
     * @return {*}
     */    
    bool GetCenter::getKsServices(){
        Disposition::Ptr disposition = Disposition::getPtr();
        httplib::Client cli(disposition->k8s_IP, disposition->k8s_port);
        httplib::Headers headers;
        headers.emplace("Authorization", disposition->KsToken.token_type + " " + disposition->KsToken.access_token);
        if (auto res = cli.Get("/kapis/resources.kubesphere.io/v1alpha3/namespaces/system-base/services", headers)){
            if(res->status != 200) return false;
        }
        return true;
    }

    /**
     * @description: 获取pods
     * @param {*}
     * @return {*}
     */    
    bool GetCenter::getKsPods(){
        Disposition::Ptr disposition = Disposition::getPtr();
        httplib::Client cli(disposition->k8s_IP, disposition->k8s_port);
        httplib::Headers headers;
        headers.emplace("Authorization", disposition->KsToken.token_type + " " + disposition->KsToken.access_token);
        if (auto res = cli.Get("/kapis/resources.kubesphere.io/v1alpha3/namespaces/system-base/pods", headers)){
            if(res->status != 200) return false;
        }
        return true;
    }

    /**
     * @description: 获取ksNodes
     * @param {*}
     * @return {*}
     */    
    bool GetCenter::getKsNodes(){
        Disposition::Ptr disposition = Disposition::getPtr();
        httplib::Client cli(disposition->k8s_IP, disposition->k8s_port);
        httplib::Headers headers;

        // token认证
        headers.emplace("Authorization", disposition->KsToken.token_type + " " + disposition->KsToken.access_token);
        if (auto res = cli.Get("/kapis/resources.kubesphere.io/v1alpha3/nodes", headers)){
            if(res->status != 200) return false;
        }
        return false;
    }

    
    /**
     * @description: 获取ks token
     * @param {*}
     * @return {*}
     */    
    bool GetCenter::getKsToken(){
        Disposition::Ptr disposition = Disposition::getPtr();
        httplib::Client cli(disposition->k8s_IP, disposition->k8s_port);
        httplib::Params params;
        params.emplace("grant_type", "password");
        params.emplace("username", "admin");
        params.emplace("client_id", "kubesphere");
        params.emplace("client_secret", "kubesphere");
        params.emplace("password", "Yin981018109");
        if (auto res = cli.Post("/oauth/token", params)){
            if(res->status != 200) return false;
            KubusphrereToken token;
            if(token.jsonToObject(res->body)) disposition->KsToken = token;
            InsUniversalData::Ptr data = std::make_shared<InsUniversalData>();
            data->format = InsDataFormat::INS_DATA_FORMAT_JSON;
            data->data = res->body;
            std::shared_ptr<InsPacket> packet = InsPacket::CreateNew(ins::InsPacketTypes::INS_K8SSERVER_PACKET, ins::InsPacketTypes::INS_MYSQL_PACKET, data);
        }
        return true;  
    }

    /**
     * @description: 获取 apolloList
     * @param {*}
     * @return {*}
     */    
    bool GetCenter::getApolloList(){
        vector<ApolloLists>  apolloList;
        SqlStream sqlStream("SELECT APOLLONAMESPACEID,TYPE,AIID,APOLLOENV,APOLLOCLUSTER,APOLLONAMESPACE FROM InsServerDB.`InsApolloNameSpaceLIst` WHERE USERID = '?'");
        sqlStream << Disposition::getPtr()->getUserId();
        vector<vector<std::string>> result;
        std::string sql = (std::string)sqlStream;
        result = this->ExecuteSql(sql);
        if(result.empty()) return false;
        for(auto &line : result){
            ApolloLists apolloLists;
            apolloLists.APOLLONAMESPACEID = line[0];
            apolloLists.TYPE = std::atoi(line[1].c_str());
            apolloLists.AIID = line[2] != "" ? std::atoi(line[2].c_str()) : 999;
            apolloLists.APOLLOENV = line[3];
            apolloLists.APOLLOCLUSTER = line[4];
            apolloLists.APOLLONAMESPACE = line[5];
            apolloList.push_back(apolloLists);
        }
        Disposition::Ptr disposition = Disposition::getPtr();
        int id = 1;
        for(auto iter = apolloList.begin(); iter != apolloList.end(); iter++){
            std::string request = "http://" + disposition->apollo_IP + ":" + std::to_string(disposition->apollo_port) + "/configs/ins/" + \
                iter->APOLLOCLUSTER + "/" + iter->APOLLONAMESPACE;
            auto resp = requests::get(request.c_str());
            if(resp == nullptr) return false;
            if(resp->status_code != 200) return false;
         
            InsUniversalData::Ptr data = std::make_shared<InsUniversalData>();
            data->Id = id;
            data->format = InsDataFormat::INS_DATA_FORMAT_JSON;
            data->data = resp->body;
            data->type = (InsDataType)iter->TYPE;
            data->attr1 = std::to_string(iter->AIID);
            data->attr2 = iter->APOLLONAMESPACEID;
            data->attr3 = std::to_string(Disposition::getPtr()->getUserId());
            std::shared_ptr<InsPacket> packet = InsPacket::CreateNew(ins::InsPacketTypes::INS_APOLLO_PACKET, ins::InsPacketTypes::INS_MYSQL_PACKET, data);
            if(packet == nullptr) return false;
            if(Sectorpower::getPtr()->enqueue(packet) != OK) return false;
            id++;
        }
        return true;
    }
    
    /**
     * @description: 执行sqlz
     * @param {string&} sql
     * @return {vector<vector<std::string>>} result
     */    
    vector<vector<std::string>> GetCenter::ExecuteSql(std::string& sql){
        vector<vector<std::string>> result;
        SqlWriter sqlExecter(sql.c_str());
        sqlExecter << result;
        return result;
    }
};