#include "KMKill.h"

#include "common/KMFolder.h"
#include "common/KMInstance.h"
#include "common/KMLogger.h"

#include "common/KMContainer.h"
#include "common/KMCrun.h"
#include "common/KMConfigData.h"

using namespace std;
namespace opt = boost::program_options;

class KMKill::Options : public KMOptions
{
public:
    Options() = default;
    virtual ~Options() = default;

protected:
    /**
     * @brief 命令行参数解析后操作
     */
    void preParseHook() override;

    /**
     * @brief 命令行参数解析后操作
     */
    void postParseHook() override;

private:
    /**
     * @brief 命令行参数添加描述选项
     */
    void addOptions();

    /**
     * @brief 命令行参数检查项
     */
    void checkOptions(const opt::variables_map &varsMap);

public:
    bool m_bHelp;
    std::string args;
};

void KMKill::Options::preParseHook()
{
    addOptions();
}

/**
 * @brief 命令行参数解析后操作
 */
void KMKill::Options::postParseHook()
{
    checkOptions(m_varsMap);

    if (m_bHelp)
    {
        showUsage();
        exit(EXIT_SUCCESS);
    }
}

/**
 * @brief 命令行参数添加描述选项
 */
void KMKill::Options::addOptions()
{
    m_optionsDescription = std::make_unique<opt::options_description>(_("\nUsage:\n \tkaiming kill [OPTION…] containerid/pid/appid - 停止正在运行的容器应用程序"));

    opt::options_description helpOptions(_("Help Options"));
    helpOptions.add_options()("help,h", _("显示帮助选项"));

    opt::options_description positionalOptions(_(""));
    positionalOptions.add_options()("ref", opt::value<string>(&args), _("ref support:\ncontainerId 容器ID \npid 进程ID \nid 应用ID"));
    m_optionsDescription->add(helpOptions).add(positionalOptions);

    m_optionsPositionalDescription->add("ref", 1);
}

/**
 * @brief 命令行参数检查项
 */
void KMKill::Options::checkOptions(const opt::variables_map &varsMap)
{
    checkOption(varsMap, "help", "h", m_bHelp);
}

REGISTER_SUBCOMMAND_DYNCREATE(kill, KMKill)

class KMKill::Private
{
public:
    std::unique_ptr<Options> options;
};

KMKill::KMKill()
    : m_dPtr(make_shared<Private>())
{
    m_dPtr->options = std::make_unique<Options>();
}

KMKill::~KMKill()
{
}

/**
 * @brief 子命令运行
 * @param argc 参数个数
 * @param argv 参数数组
 * @return int 0 成功
 */
int KMKill::despose(int argc, char **argv)
{
    m_dPtr->options->parseCommandLine(argc, argv);
    string app = m_dPtr->options->args;

    std::vector<ContainerListItem> item;
    std::vector<string> arg = { "list", "--format=json" };
    //这里调用了crun函数 exec族函数
    if (!KMCrun::exec<std::vector<ContainerListItem>>(arg, item))
    {
        KMError(string("can not find ") + app);
        return EXIT_FAILURE;
    }

    bool bFind = false;
    for (auto &i : item)
    {
        State itemContainerId;
        std::vector<string> argContainerId = { "state", i.id };
        KMCrun::exec<State>(argContainerId, itemContainerId);

        if (app == itemContainerId.id || app == itemContainerId.annotations.value().at("kaiming.app.id") || app == std::to_string(itemContainerId.pid.value()))
        {
            std::vector<string> args_kill = { "kill", i.id, "SIGKILL" };
            if (!KMCrun::exec(args_kill))
            {
                KMError(string("can not kill ") + app);
                return EXIT_FAILURE;
            }
            bFind = true;
            break;
        }
    }

    if (!bFind)
    {
        KMError(string("can not find ") + app);
        return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
}
