#include "Config.h"
#include "../../../../../core_library/Core/Core/Base/Check.h"
#include "Core/Net_Adapter/Net_Adapter.h"
#include "Global.h"
#include <filesystem>
#undef interface

std::string default_config_path;


std::string get_config_path() {
#ifdef WIN32
    return "D:/ae/proj/projects/ECAP_Server/config/config.json";
#endif
    static bool first = true;
    if (!default_config_path.empty()) return default_config_path;
    std::string ret;
    std::ostringstream oss;
    std::string file_name = "config.json";
    ret =  get_exe_dir() + "/" + file_name;
    if (first)
    {
        std::cout << oss.str() << std::endl;
        first = false;
    }
    return ret;
}




void Mode_ACS_Config::server(Global* g)  {
    auto& svr = g->svr;
    auto& api = g->api;
    data_source_config.server(g);
    data_feed_config.server(g);
    source_feed_relation_config.server(g);

    svr.Post(api + "get_mode_s_basic_config", [this](HTTP_Param) {
        CHECK_JSON_PARAM
        res->setBody(warp(to_base_json()).to_json_string());
    });
    svr.Post(api + "set_mode_s_basic_config", [this](HTTP_Param) {
        CHECK_JSON_PARAM
        auto& j = o_params.value();
        init_base_json(&j);
        res->setBody(warp(to_base_json()).to_json_string());
    });
}


void Device_Config::server(Global* g) {
    auto& svr = g->svr;
    auto& api = g->api;
     svr.Post(api + "get_device_config", [this](HTTP_Param) {
         res->setBody(warp(to_json()).to_json_string());
    });

    svr.Post(api + "get_net_adapter_list", [this](HTTP_Param) {
       JSON ret = JSON::object();
       auto arr = JSON::array();
        for (auto& it :  Psc::get_net_adapter_info_map())
        {
            arr.append(it.second.to_Json());
        }
        ret.append({"list", arr});
        res->setBody(warp(ret).to_json_string());
   });


    svr.Post(api + "set_device_config", [this](HTTP_Param) {
        CHECK_JSON_PARAM
        JSON old_device_config;
        {

            old_device_config = to_json();
        }
        HTTP_REQUIRE_PTR(net, params.get("net"))
        Net_Config device, wifi;
        bool has_device = false;
        bool has_wifi = false;
        for (const auto& it : net->children)
        {
            HTTP_REQUIRE_VALUE(net_key, it.try_get_string("key"))
            if (net_key == "device")
            {
                device.init_from_json(&it);
                has_device = true;
            }
            if (net_key == "wifi")
            {
                wifi.init_from_json(&it);
                has_wifi = true;
            }
        }
        HTTP_REQUIRE_TRUE(has_device && has_wifi, "net")


        bool it1 = check_ip_netmask_gateway(device.ip, device.netmask, device.gateway);
        bool it2 = check_ip_netmask_gateway(wifi.ip, wifi.netmask, wifi.gateway);
        bool p1 = check_port(device.port);
        bool p2 = check_port(wifi.port);
        if (!it1 || !it2 || !p1 || !p2)
        {
            server_logger->error("", {}, LOG_POS + "  ip port! " + device.ip + ":" + std::to_string(device.port));
            res->setBody(warp(old_device_config).to_json_string());
            return;
        }


#if WIN32
        bool use = false;
#else
        bool use = true;
#endif
        {

            auto& w = *this;
            *w.list.get("device").value() = device;
            *w.list.get("wifi").value() = wifi;
        }
        Global::save();
        if (use)
        {
            std::string interface;
            {
                std::string path = get_exe_dir() + "/interface";
                std::ifstream ifs(path);
                if (!ifs.is_open())
                {
                    server_logger->error("", {}, LOG_POS + "  无法打开文件! " + path);
                    res->setBody(warp(old_device_config).to_json_string());
                    return;
                }
                std::stringstream buffer;
                buffer << ifs.rdbuf();
                interface = buffer.str();
            }
            static auto set = [](std::string& interface, const std::string& token, const std::string& value) {
                std::string var_name = "${" + token + "}";
                auto size = var_name.size();
                size_t pos = interface.find(var_name);
                while (pos != std::string::npos)
                {
                    interface.replace(pos, size, value);
                    pos = interface.find(var_name);
                }
            };
            set(interface, "ip", device.ip);
            set(interface, "gateway", device.gateway);
            set(interface, "netmask", device.netmask);
            set(interface, "wifi_ip", wifi.ip);
            set(interface, "wifi_gateway", wifi.gateway);
            set(interface, "wifi_netmask", wifi.netmask);
            std::cout << interface << std::endl;
            std::string path = "/etc/network/interfaces";
            std::ofstream outfile(path);
            if (!outfile.is_open())
            {
                server_logger->error("", {}, LOG_POS + "  无法打开文件!" + path);
                res->setBody(warp(old_device_config).to_json_string());
                return;
            }
            outfile << interface;
            outfile.close();
            std::string bash_path = get_exe_dir() + "/restart_net_service.sh";
            if (!std::filesystem::exists(bash_path))
            {
                server_logger->error("", {}, LOG_POS + "  !" + bash_path);
                res->setBody(warp(old_device_config).to_json_string());
                return;
            }
            int result = system(bash_path.c_str());
            if (result != 0)
            {
                server_logger->error("", {}, LOG_POS + "  脚本执行失败!" + bash_path);
                res->setBody(warp(old_device_config).to_json_string());
                return;
            }
        }
        res->setBody(warp(params).to_json_string());
    });
}


void Config::save() {
    std::ofstream config_file;
    config_file.open(get_config_path());
    std::string json = Global::instance()->toJson().to_json_string();
    config_file.write(json.c_str(), static_cast<long long>(json.size()));
    config_file.close();
}
