#include "curlpp/Options.hpp"
#include "kubecontrol/Utils.hpp"
#include <kubecontrol/KubePod.hpp>


namespace kubecontrol 
{

    KubePod::KubePod(std::string Label, std::string Uuid, std::string ContainerImage):Label_(Utils::to_lower(Label)),Uuid_(Uuid),
    ContainerImage_(ContainerImage),EnvirmonentVars_()
    {
        ContainerRegistry_ = "kmaster.ti.unibw-hamburg.de:30808";
        EnvirmonentVars_ = std::map<std::string, std::string>();
        
        this->PathToYaml_ = "config/pods/" + this->Label_ + ".yaml";

        if( std::filesystem::directory_entry("config").exists() != true) 
        {
            std::filesystem::create_directory("config");
        }
        std::filesystem::directory_entry entry("config/pods");
        if(entry.exists() != true) 
        {
            std::filesystem::create_directory("config/pods");
        }


    }

    std::string KubePod::getUUID()
    {
        return this->Uuid_;
    }

    std::string KubePod::getLabel()
    {
        return this->Label_;
    }

    void  KubePod::setEnvironmentVar(std::string key, std::string val)
    {
        EnvirmonentVars_.emplace(key,val);
    }

    std::map<std::string, std::string> KubePod::GetEnvironmentVars()
    {
        return EnvirmonentVars_;
    }

    std::string KubePod::GetEnvironmentVar(std::string key)
    {
         if(EnvirmonentVars_.contains(key)) {
            return EnvirmonentVars_[key];
        } else {
            return nullptr;
        }
    }

    void KubePod::setArgs(std::string args)
    {
        Args_.emplace_back(Utils::to_lower(args));
    }

    std::vector<std::string> KubePod::GetArgs()
    {
        return Args_;
    }

    void KubePod::setCommand(std::string command)
    {
        PodCommand_ = Utils::to_lower(command);
    }

    std::string KubePod::getCommand()
    {
        return PodCommand_;
    }



    std::string  KubePod::createYAML()
    {
        YAML::Node node;

        node["apiVersion"] = "v1";
        node["kind"] = "Pod";
        node["metadata"]["name"] = this->Uuid_;
        node["metadata"]["labels"]["app.kubernetes.io/name"] = this->Label_;

        node["spec"]["containers"][0]["name"] = this->Label_+"-container";
        node["spec"]["containers"][0]["image"] = this->ContainerRegistry_ + "/" + this->ContainerImage_;
        node["spec"]["containers"][0]["imagePullPolicy"] = "Always";

        int i = 0;
        for (auto item :EnvirmonentVars_) {
            node["spec"]["containers"][0]["env"][i]["name"] = item.first;
            node["spec"]["containers"][0]["env"][i]["value"] = item.second;
            i++;
        }

        
        if (Args_.size() > 0) 
        {
            node["spec"]["containers"][0]["args"].SetStyle(YAML::EmitterStyle::Flow);
            for (auto item : Args_) {
                node["spec"]["containers"][0]["args"].push_back(item);
            }
        }

        if (!PodCommand_.empty()) 
        {
            
            node["spec"]["containers"][0]["command"].SetStyle(YAML::EmitterStyle::Flow);
            node["spec"]["containers"][0]["command"].push_back(PodCommand_);
        }


  
        node["spec"]["restartPolicy"] = "Never";

        std::ofstream fout(this->PathToYaml_);
        fout << node;
        fout.close();
        
        return this->PathToYaml_;

    }

    std::string  KubePod::start(std::string apiAddress,std::string token)
    {
        std::string curlURL = apiAddress;
        std::string AuthString = "Authorization: Bearer " + token;

        std::list<std::string> headers;
        headers.push_back(AuthString);
        headers.push_back("Content-Type: application/yaml");


        curlpp::Cleanup cleaner;
        curlpp::Easy request;

        WriterMemoryClass mWriterChunk;  
        curlpp::types::WriteFunctionFunctor functor = std::bind(&WriterMemoryClass::WriteMemoryCallback, &mWriterChunk, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
        curlpp::options::WriteFunction *test = new curlpp::options::WriteFunction(functor);
        request.setOpt(test);
        
        request.setOpt(new curlpp::options::HttpHeader(headers));

        request.setOpt(new curlpp::options::Url(curlURL));

        request.setOpt(new curlpp::options::SslVerifyPeer(false));

        // request.setOpt(new curlpp::options::Post(true));
        request.setOpt(new curlpp::options::CustomRequest("POST"));
        // request.setOpt(new curlpp::options::Verbose("POST"));


        
        this->createYAML();
        
        LOG_S(ERROR)<< this->PathToYaml_;
        
        std::ifstream is;
        is.open (this->PathToYaml_, std::ios::binary );
        is.seekg (0, std::ios::end);
        long length = is.tellg();
        is.seekg (0, std::ios::beg);
        char *buffer = new  char [length];
        is.read(buffer,length);
        is.close();

        request.setOpt(new curlpp::options::PostFields(buffer));

        request.perform();
        
        request.reset();
        auto response = mWriterChunk.getResponse();
        return  nlohmann::json::parse(response).dump();
    }

    std::string  KubePod::stop(std::string apiAddress,std::string token)
    {
        std::string curlURL = apiAddress+ this->Uuid_;
        std::string AuthString = "Authorization: Bearer " + token;

        std::list<std::string> headers;
        headers.push_back(AuthString);


        curlpp::Cleanup cleaner;
        curlpp::Easy request;

        WriterMemoryClass mWriterChunk;  
        curlpp::types::WriteFunctionFunctor functor = std::bind(&WriterMemoryClass::WriteMemoryCallback, &mWriterChunk, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
        curlpp::options::WriteFunction *writefunction = new curlpp::options::WriteFunction(functor);
        request.setOpt(writefunction);

        request.setOpt(new curlpp::options::HttpHeader(headers));
        request.setOpt(new curlpp::options::Url(curlURL));

        
        request.setOpt(new curlpp::options::SslVerifyPeer(false));


        request.setOpt(new curlpp::options::CustomRequest("DELETE"));
        // request.setOpt(new curlpp::options::Verbose(true));


        request.perform();
        auto response = mWriterChunk.getResponse();
        return  nlohmann::json::parse(response).dump();
    }

    std::string  KubePod::getInfo(std::string apiAddress,std::string token)
    {
        std::string curlURL = apiAddress+"/"+Uuid_;
        std::string AuthString = "Authorization: Bearer " + token;

        std::list<std::string> headers;
        headers.push_back(AuthString);


        curlpp::Cleanup cleaner;
        curlpp::Easy request;

        WriterMemoryClass mWriterChunk;  

        curlpp::types::WriteFunctionFunctor functor = std::bind(&WriterMemoryClass::WriteMemoryCallback, &mWriterChunk, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
        
        curlpp::options::WriteFunction *test = new curlpp::options::WriteFunction(functor);
        request.setOpt(test);
        
        request.setOpt(new curlpp::options::HttpHeader(headers));

        request.setOpt(new curlpp::options::Url(curlURL));
     
        request.setOpt(new curlpp::options::SslVerifyPeer(false));


        request.perform();
        auto response = mWriterChunk.getResponse();
        return nlohmann::json::parse(response).dump();
    }

}