#ifndef CONFIG_H_H
#define CONFIG_H_H
#include "../DSP/export.h"
#include "../Data_Feed/export.h"
#include "Core/spdlog/export.h"
#include "../Data_Source/export.h"
#include "MLAT.h"
#include "Source_Feed_Relation.h"

#include <fstream>
inline bool delete_log = false;

extern std::string default_config_path;
std::string get_config_path();

struct Log_Config {
    DELETE_COPY(Log_Config)
    Log_Config() = default;
    ~Log_Config() {
        if (delete_log) std::cout << "~Log_Config()" << std::endl;
    }
    enum class Open_Mode {
        Append,
        Delete,
        Rename
    };
    Open_Mode open_mode = Open_Mode::Rename;
    std::uint16_t piece_num{};
    std::uint16_t size_MB{};
    void init(const Psc::JSON* that_json) {
        open_mode = Psc::to_enum<Open_Mode>(that_json->get_string("open_mode"));
        Get_J(piece_num)
        Get_J(size_MB)
    }
    [[nodiscard]] Psc::JSON to_json() const {
        Psc::JSON ret = Psc::JSON::object();
        Ret_J(open_mode);
        Ret_J(piece_num);
        Ret_J(size_MB);
        return ret;
    }
};

struct Console_Config {
    DELETE_COPY(Console_Config)
    Console_Config() = default;
    ~Console_Config() {
        if (delete_log) std::cout << "~Console_Config()" << std::endl;
    }
    bool record_playback;
    bool mode_s_console;
    bool post_request;
    bool mlat_server;
    void init(const Psc::JSON* that_json) {
        Get_J(record_playback)
        Get_J(mode_s_console)
        Get_J(post_request)
        Get_J(mlat_server)
    }
    [[nodiscard]] Psc::JSON to_json() const {
        Psc::JSON ret = Psc::JSON::object();
        Ret_J(record_playback)
        Ret_J(mode_s_console)
        Ret_J(post_request)
        Ret_J(mlat_server)
        return ret;
    }
};

struct Http_Monitor_Config {
    bool access_log = true;
    std::size_t slow_request_threshold_ms = 1000;
    std::size_t slow_scope_threshold_ms = 100;

    void init(const Psc::JSON* that_json) {
        if (!that_json) return;
        Get_J(access_log)
        Get_J(slow_request_threshold_ms)
        Get_J(slow_scope_threshold_ms)
    }

    [[nodiscard]] Psc::JSON to_json() const {
        Psc::JSON ret = Psc::JSON::object();
        Ret_J(access_log)
        Ret_J(slow_request_threshold_ms)
        Ret_J(slow_scope_threshold_ms)
        return ret;
    }
};





struct Mode_ACS_Config {
    DELETE_COPY(Mode_ACS_Config)
    std::atomic<std::size_t> timeout_seconds{};
    std::atomic<std::size_t> max_track_point_size{};
    std::atomic<std::size_t> max_speed_m_s{};
    std::atomic<std::size_t> air_pos_timeout = 8;
    std::atomic<std::size_t> surface_pos_timeout = 32;
    //   static I air_time = 8;
    //   static I surface_time = 8 * 4;
    std::atomic<std::size_t> read_milliseconds{};
    std::atomic<std::size_t> mode_s_max_num{};
    std::atomic<std::size_t> mode_other_max_num{};
    std::atomic<std::size_t> report_data_feed_msg_mum{};
    std::atomic<std::size_t> Report_Data_Feed_Message_Num{};
    std::atomic<std::size_t> default_min_aircraft_list_num{};

    std::atomic<bool> ignore_df_11{};
    std::atomic<bool> monitor_msg_live{};



    Data_feed_Config data_feed_config;
    Data_Source_Config data_source_config;
    Source_Feed_Relation_Config source_feed_relation_config;
    Mode_ACS_Config() = default;

    ~Mode_ACS_Config() {
        if(delete_log) std::cout << " ~Mode_S_Config()" << std::endl;
    }


    Psc::JSON to_base_json() const {
        Psc::JSON ret = Psc::JSON::object();
        Ret_J(timeout_seconds)
        Ret_J(max_speed_m_s)
        Ret_J(air_pos_timeout)
        Ret_J(surface_pos_timeout)
        Ret_J(read_milliseconds)
        return ret;
    }

    void init_base_json(const Psc::JSON* that_json) {
        Get_J(timeout_seconds)
        Get_J(max_speed_m_s)
        Get_J(air_pos_timeout)
        Get_J(surface_pos_timeout)
        Get_J(read_milliseconds)
    }







    void init(const Psc::JSON* that_json) {
        init_base_json(that_json);
        Get_J(max_track_point_size)
        Get_J(mode_s_max_num)
        Get_J(mode_other_max_num)
        Get_J(report_data_feed_msg_mum)
        Get_J(default_min_aircraft_list_num)
        Get_J(ignore_df_11)
        Get_J(monitor_msg_live)

        data_feed_config.init(that_json->get("data_feed"));
        data_source_config.init(that_json->get("data_source"));
        source_feed_relation_config.from_json(that_json->get("source_feed_relation"));
        if (monitor_msg_live) {
            SSR::Monitor_Mode_ACS_Message_Num = this->monitor_msg_live;
        }
    }

    Psc::JSON to_json() {
        Psc::JSON ret = to_base_json();
        Ret_J(max_track_point_size)
        Ret_J(mode_s_max_num)
        Ret_J(mode_other_max_num)
        Ret_J(report_data_feed_msg_mum)
        Ret_J(default_min_aircraft_list_num)
        Ret_J(ignore_df_11)
        Ret_J(monitor_msg_live)
        // Ret_J(aircraft_csv_path)

        ret.append(Psc::JSON("data_feed", data_feed_config.to_json()));
        ret.append(Psc::JSON("data_source", data_source_config.to_json()));
        ret.append(Psc::JSON("source_feed_relation", source_feed_relation_config.to_json()));
        return ret;
    }
    void server(Global* g);
};



struct Web_Server_Config {
    Web_Server_Config() = default;
    [[nodiscard]] std::string get_true_webapp() const {
        return Psc::get_abs_path(webapp);
    }
    [[nodiscard]] std::string get_true_tiles() const {
        return Psc::get_abs_path(tiles);
    }
    Psc::JSON to_json() {
        Psc::JSON ret = Psc::JSON::object();
        Ret_J(webapp)
        Ret_J(tiles)
        return ret;
    }
    void init(const Psc::JSON* that_json) {
        Get_J(webapp)
        Get_J(tiles)
    }
protected:
    std::string webapp;
    std::string tiles;
};

struct Net_Config {
    std::string key;
    std::string ip;
    std::uint16_t port{};
    std::string netmask;
    std::string gateway;
    Net_Config() = default;
    [[nodiscard]] Psc::JSON to_json() const {
        Psc::JSON ret = Psc::JSON::object();
        Ret_J(key)
        Ret_J(ip)
        Ret_J(netmask)
        Ret_J(gateway)
        Ret_J(port)
        return ret;
    }
    void init_from_json(const Psc::JSON* that_json) {
        Get_J(key)
        Get_J(ip)
        Get_J(netmask)
        Get_J(gateway)
        Get_J(port)
    }
};

struct Device_Config {
    Ordered_Map<std::string, Net_Config*> list;

    ~Device_Config() {
        if (delete_log) std::cout << "~Device_Config()" << std::endl;
        for (auto it : list.list()) {
            delete it;
        }
        list.clear();
    }


    Psc::JSON to_json() {
        Psc::JSON ret = Psc::JSON::object();
        Psc::JSON net = Psc::JSON::array();
        for (auto& li : list.list()) {
            net.append(li->to_json());
        }
        ret.append({"net", net});
        return ret;
    }

    Device_Config() = default;
    void init(const Psc::JSON* that_json) {
        for (auto& li : that_json->get("net")->children)
        {
            auto cur = new Net_Config();
            cur->init_from_json(&li);
            list.push_back(cur);
        }
    }

    Psc::JSON to_net_json() {
        Psc::JSON ret = Psc::JSON::object();
        Psc::JSON net = Psc::JSON::array();
        for (auto& li : list.list()) {
            net.append(li->to_json());
        }
        ret.append({"net", net});
        return ret;
    }
    void server(Global* g);
};




class Config {
public:
    Config() = default;
    DELETE_COPY(Config)
    MLAT_Config mlat;
    Device_Config device_config;
    Web_Server_Config web_server_config;
    Mode_ACS_Config mode_acs;
    Log_Config log_config;
    Console_Config console_config{};
    DSP_Config dsp_config;
    Psc::JSON drogon_config;
    Http_Monitor_Config http_monitor_config;
    std::string version;
    External_Resources_Manager external_resources_manager;
    static Psc::JSON load() {
        std::string config_path = get_config_path();

        std::ifstream iso(config_path);
        if (!iso.is_open())
        {
            std::cerr << config_path << " can not open!" << std::endl;
            Psc::fail_fast();
        } else {
            std::cout << get_current_date_string() << " 启动加载配置文件: 【" << config_path << "】" << std::endl;
        }
        std::stringstream ss;
        std::stringstream buffer;
        buffer << iso.rdbuf();
        std::string fileContents = buffer.str();
        return Psc::parse_json(fileContents);
    }

    void fromJson(Psc::JSON* that_json) {
        Get_J(version)
        mlat.init(that_json->get("mlat"));
        web_server_config.init(that_json->get("web_server"));
        device_config.init(that_json->get("device"));
        mode_acs.init(that_json->get("mode_acs"));
        console_config.init(that_json->get("console"));
        dsp_config.init(that_json->get("dsp"));
        drogon_config = *that_json->get("drogon");
        http_monitor_config.init(that_json->get("http_monitor"));
        external_resources_manager.init(that_json->get("external_database"));
    }

    Psc::JSON toJson() {
        auto ret = Psc::JSON::object({
            {"version", version},
            {"dsp", dsp_config.to_json()},
            {"drogon", drogon_config},
            {"http_monitor", http_monitor_config.to_json()},
            {"mlat", mlat.to_json()},
            {"web_server", web_server_config.to_json()},
            {"device", device_config.to_json()},
            {"mode_acs", mode_acs.to_json()},
            //{"ais", ais.to_json()},
            {"log", log_config.to_json()},
            {"console", console_config.to_json()},
            {"external_database", external_resources_manager.to_json()},
        });

        return ret;
    }
    static void save();
};







#endif
