#include "client.h"
#include "config.h"
#include "version.h"
#include <CLI11.hpp>
#include <iostream>
#include <regex>

#ifdef _WIN32
#include <fcntl.h>
#include <io.h>
#include <windows.h>
#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
#endif
#endif

std::shared_ptr<CServerConfig> g_Config = nullptr;

int parse_cmd(int argc, char** argv, CmdParam& param)
{
    std::string intro("transmc cmd introduce.");
    CLI::App app(intro);

    app.add_option("-n, --number", param.use_config, "使用服务器地址组(值为使用--show中显示的序号)");
    app.add_option("-a, --append", param.appendValue, "添加服务器地址组(地址格式：127.0.0.1:9898)");
    app.add_flag("-s, --show", param.showValue, "查看服务器地址组");
    app.add_option("-r, --remove", param.removeValue, "移除服务器地址组(值为使用--show中显示的序号)");

    if (argc == 1) {
        std::cout << app.help() << std::endl;
        return 0;
    }
    // 这里的 CLI11_PARSE 在程序没有输入或者仅输入--help(-h)时，会直接返回，后面代码都不会执行。
    // 当有自定义的参数被输入时，后面代码会执行。
    try {
        CLI11_PARSE(app, argc, argv);
    } catch (const CLI::ParseError& e) {
        return app.exit(e);
    }
    param.parsed = true;
    return 0;
}

bool exec_cmd(const CmdParam& param, bool& run)
{
    run = false;
    // 如果是展示
    if (param.showValue) {
        std::vector<TransmSet> set;
        if (!g_Config->read_ini(set)) {
            return false;
        }
        for (const auto& item : set) {
            mpinfo("{} => {}:{}", item.group, item.ip, item.port);
        }
        return true;
    }
    if (param.use_config != -1) {
        run = true;
        return true;
    }
    if (!param.appendValue.empty() && !param.removeValue.empty()) {
        mperror("append and remove can't simultaneous operate!");
        return false;
    }
    if (!param.appendValue.empty()) {
        std::regex rg(R"(([^:]+):(\d+))");
        std::smatch match;
        if (!std::regex_search(param.appendValue, match, rg)) {
            mperror("append invalid format!");
            return false;
        }
        std::string ip = match[1].str();
        std::string port = match[2].str();
        if (!g_Config->append_ini(ip, std::stol(port))) {
            mperror("add {}:{} failed.", ip, port);
            return false;
        }
        mpinfo("add {}:{} success.", ip, port);
        return true;
    }
    if (!param.removeValue.empty()) {
        if (!g_Config->remove_ini(std::stol(param.removeValue))) {
            mperror("remove config num=[{}] failed, please check!", param.removeValue);
            return false;
        }
        mpinfo("remove config num=[{}] success!", param.removeValue);
        return true;
    }
    mperror("not matched!", param.removeValue);
    return false;
}

int main(int argc, char* argv[])
{

#ifdef _WIN32
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    DWORD mode;
    GetConsoleMode(hConsole, &mode);
    mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
    SetConsoleMode(hConsole, mode);
#endif

    g_Config = std::make_shared<CServerConfig>();
    if (!g_Config->baseInit()) {
        return -1;
    }

    bool run = false;
    CmdParam param;
    parse_cmd(argc, argv, param);
    if (!param.parsed) {
        return 0;
    }
    if (!exec_cmd(param, run)) {
        mperror("exec_cmd failed!");
        return -1;
    }
    if (!run) {
        return 0;
    }

    std::vector<TransmSet> set;
    if (!g_Config->read_ini(set)) {
        return -1;
    }
    TransmSet use;
    if (!g_Config->get_ini(set, param.use_config, use)) {
        mperror("Not found config by num:[{}]", param.use_config);
        return -1;
    }
    mpinfo("Build At {} {} under {} on {}", __DATE__, __TIME__, VERSION_GIT_COMMIT, VERSION_GIT_BRANCH);
    mpinfo("use ip => [{}], port => [{}]", use.ip, use.port);
    CClient client;
    client.run(use.ip, std::to_string(use.port));
    mpinfo("exit ==========");
    return 0;
}