#include "Database.h"
#include "../server/Global.h"
#include "../server/Performance_Monitor.h"

#include <chrono>
#include <functional>
#include <map>

Aircraft::Aircraft(const std::string &icao)  : Aircraft_Info(icao) {
    auto size = Global::instance()->mode_acs.max_track_point_size.load();
    air_pos_track_list.init(size);
    surface_pos_track_list.init(size);
}

void Aircraft::refresh_external_database_info() {
    auto& manager = Global::instance()->external_resources_manager;
    if (!external_database_info_loaded) {
        external_database_info = manager.query_aircraft_external_databases(icao);
        external_database_info_loaded = true;
    }

    auto callsign = flight();
    if (!callsign) callsign = bds20_call_sign();
    if (last_external_database_callsign == callsign) {
        return;
    }

    callsign_external_database_info =
        manager.query_callsign_external_databases(callsign);
    last_external_database_callsign = std::move(callsign);
}

std::shared_ptr<SSR::Aircraft_Info> DataBase::get_aircraft(const std::string& icao) {
    return aircraft_map.get(icao);
}




std::shared_ptr<SSR::Aircraft_Info> DataBase::create_aircraft(const std::string& icao) {
    auto ret = aircraft_map.create(icao);
    ret->refresh_external_database_info();
    return ret;
}

void DataBase::delete_timeout_aircraft() {
    aircraft_map.remove_cond([](const std::shared_ptr<SSR::Aircraft_Info>& item) {
        if (item->timestamp == 0) {
            std::cout << "未初始化的  timestamp " << LOG_POS << std::endl;
        }
        long long time = std::time(nullptr) - item->timestamp;
        return time > Global::instance()->mode_acs.timeout_seconds;
    });
}


JSON DataBase::get_aircraftlist() {
    JSON json = JSON::array();
    for (auto& it : aircraft_map.values()) {
        auto o = Aircraft_List_JSON_Service_O::to_That(this, it.get());
        json.children.push_back(o.toJson());
    }
    return json;
}

Psc::JSON DataBase::get_aircraftlist(int limit_msg_num) {
    JSON json = JSON::array();
    for (auto& it : aircraft_map.values()) {
        if (it->times < limit_msg_num) continue;
        auto o = Aircraft_List_JSON_Service_O::to_That(this, it.get());
        json.children.push_back(o.toJson());
    }
    return json;
}

JSON DataBase::get_all_aircraft_json() {
    JSON json = JSON::array();
    auto g = Global::instance();
    size_t num = 0;
    for (auto& it : aircraft_map.values()) {
        auto vto = Flight_VTO::to_VTO(it.get());
        bool have_pos = !it.get()->air_pos_track_list.empty();
        if (have_pos) {
            json.children.push_back(vto.toJson());
            num++;
        }
    }
    have_pos_aircraft_num = num;
    return json;
}





JSON DataBase::get_aircraft_list_after(time_t timestamp) {
    JSON json = JSON::array();
    auto g = Global::instance();
    for (auto& it : aircraft_map.values()) {
        auto vto = Flight_VTO::to_VTO(it.get());
        bool have_pos = !it.get()->air_pos_track_list.empty();
        if (have_pos && vto.time_stamp  > timestamp) {
            json.children.push_back(vto.toJson());
        }
    }
    return json;
}

#ifdef Cache_Some_Mode_S
Psc::JSON DataBase::get_limit_mode_s_msg_info() {

    JSON ret = JSON::object();
    JSON list = JSON::array();
    std::map<int, size_t> map;
    std::map<int, size_t> num_test;
    for (auto& air : aircraft_map.values()) {
        if (air->total_num > Cache_Some_Mode_S_Num) continue;
        Psc::JSON air_json = Psc::JSON::object();
        {
            Psc::JSON ms = Psc::JSON::array();
            int n = air->cache.size();
            for (auto msg : air->cache) {
                Psc::JSON cur = Psc::JSON::object({
                    {"hex", msg->msg_hex},
                    {"df", to_string(msg->df)}
                });
                if (msg->df == Downlink_Format::Extended_Squitter_17) {

                    auto tc = type_code(msg->msg_bin);
                    cur.children.push_back({"tc", tc});
                    map[tc]++;
                    num_test[air->total_num] = n;
                }
                ms.append(cur);
            }
            air_json.children.push_back({"icao", air->icao});
            air_json.children.push_back({"total_num", air->total_num});
            air_json.children.push_back({"ms", ms});
        }
        list.children.push_back(air_json);
    }
    ret.children.push_back({"key", key});
    for (auto pair : map) {
        ret.children.push_back({std::to_string(pair.first), pair.second});
    }
    Psc::JSON t = Psc::JSON::object();
    for (auto pair : num_test) {
        t.children.push_back({std::to_string(pair.first), pair.second});
    }
    ret.children.push_back({"数量统计", t});
    ret.children.push_back({"list", list});
    return ret;
}
#endif

size_t DataBase::get_aircraft_num() { return aircraft_map.size(); }

#define _init_db \
HTTP_REQUIRE_VALUE(data_source_key, params.try_get_string("data_source_key")) \
auto db = Global::instance()->source(data_source_key); \
if (db == nullptr) { \
    res->setStatusCode(drogon::k503ServiceUnavailable); \
    JSON ret; \
    res->setBody(ret.to_json_string());   \
    return; \
}



void database_server(Global* g) {
    auto& svr = g->svr;
    auto& api = g->api;
    // g->load_aircraft_csv(g->mode_acs.aircraft_csv_path);
    g->external_resources_manager.load_sqlite_db(
        Psc::get_abs_path(g->external_resources_manager.ecap_sqlite_path));


#ifdef Cache_Some_Mode_S
    svr.Post(api + "get_cache_some_mode_s_info", [](HTTP_Param) {
        CHECK_JSON_PARAM
        _init_db
        auto g = Global::instance();
        auto ret = JSON::object();
        if (db) {
            ret = db->get_limit_mode_s_msg_info();
        }
        res->setBody(warp(ret).to_json_string());
    });
#endif

    svr.Post(api + "get_base_station_location", [](HTTP_Param) {
        CHECK_JSON_PARAM
        _init_db
        auto g = Global::instance();
        auto ret = JSON::object();
        if (db) {
            ret = db->base_station.to_Json();
        }
        res->setBody(warp(ret).to_json_string());
    });
    svr.Post(api + "get_aircraft_base_info", [](HTTP_Param) {
        CHECK_JSON_PARAM
        _init_db
        HTTP_REQUIRE_VALUE(icao, params.try_get_string("icao"))
        auto aircraft = db->get_aircraft(icao);
        JSON ret;
        if (aircraft != nullptr) {
            auto vto = Flight_VTO::to_VTO(aircraft.get());
            ret = vto.toJson();
        }
        res->setBody(ret.to_json_string());
    });
    svr.Post(api + "get_aircraft_detail_info", [](HTTP_Param) {
        CHECK_JSON_PARAM
        _init_db
        HTTP_REQUIRE_VALUE(icao, params.try_get_string("icao"))
        auto aircraft = db->get_aircraft(icao);
        JSON ret;
        if (aircraft != nullptr) {
            ret = aircraft->toJson();
        }
        res->setBody(ret.to_json_string());
    });
    svr.Post(api + "get_aircraft_track_list", [](HTTP_Param) {
        CHECK_JSON_PARAM
        _init_db
        HTTP_REQUIRE_VALUE(icao, params.try_get_string("icao"))
        HTTP_REQUIRE_VALUE(last_size, params.try_get_number<std::size_t>("last_size"))
        auto aircraft = db->get_aircraft(icao);
        JSON ret;
        if (aircraft != nullptr)
        {
            ret = aircraft->air_pos_track_list.get_last_array_json(last_size);
            ret.children.insert(ret.children.begin(), JSON("ds", data_source_key));
            ret.children.insert(ret.children.begin(), JSON("icao", icao));
        }
        res->setBody(ret.to_json_string());
    });
    svr.Post(api + "get_aircraft_list_after", [](HTTP_Param) {
        CHECK_JSON_PARAM
        _init_db
        HTTP_REQUIRE_VALUE(timestamp, params.try_get_number<std::uint32_t>("timestamp"))
        auto ret = db->get_aircraft_list_after(timestamp);
        res->setBody(ret.to_json_string());
    });

    svr.Post(api + "aircraft_change_list", [](HTTP_Param) {
        CHECK_JSON_PARAM
        _init_db
        JSON ret = JSON::array();
        if (db) {
           ret = db->get_all_aircraft_json();
        } else
        {

        }
        res->setBody(warp(ret).to_json_string());
    });


    svr.Get(R"(/aircraftlist.json)", [](HTTP_Param) {
        auto list = Global::instance()->mode_acs.data_source_config.map.list();
        std::shared_ptr<Data_Source> ts = nullptr;
        auto ret = JSON::array();
        for (const auto& li : list) {
            if (li->enable) {
                ret = li->get_aircraftlist();
                break;
            }
        }
        res->setBody(ret.to_json_string("", "\n", ""));
    });

    // aircraftlist.json 的带数据源版本
    svr.Post(api + "aircraft_list", [](HTTP_Param) {
        CHECK_JSON_PARAM
        auto g = Global::instance();
        HTTP_REQUIRE_VALUE(data_source_key, params.try_get_string("data_source_key"))
        std::shared_ptr<Data_Source> db;
        {
            db = g->source(data_source_key);
        }
        if (db == nullptr) {
            res->setStatusCode(drogon::k503ServiceUnavailable);
            JSON ret;
            res->setBody(ret.to_json_string());
            return;
        }


        auto limit_msg_num = g->mode_acs.default_min_aircraft_list_num.load();
        auto t = params.get("limit_msg_num");
        if (t) {
            HTTP_REQUIRE_VALUE(requested_limit_msg_num, t->try_number_val<int>())
            limit_msg_num = requested_limit_msg_num;
        }
        JSON ret = JSON::array();
        {
            Scope_Timer timer(
                "aircraft_list.db_query",
                g->http_monitor_config.slow_scope_threshold_ms);
            ret = db->get_aircraftlist(limit_msg_num);
        }
        std::string body;
        {
            Scope_Timer timer(
                "aircraft_list.json_serialization",
                g->http_monitor_config.slow_scope_threshold_ms);
            body = warp(ret).to_json_string();
        }
        res->setBody(body);
    });

}




static std::string output;

static void log_i(const std::string& label, const std::string& value,
                  const std::string& unit = "") {
    std::ostringstream oss;
    // Format the label and value
    oss << std::left << std::setw(30) << label << ": " << value;
    // Add unit if not empty
    if (!unit.empty()) {
        oss << " " << unit << "\n";
    } else {
        oss << "\n";
    }
    // Append formatted string to output
    output += oss.str();
}

static void log_i(const std::string& label, double value,
                  const std::string& unit = "") {
    log_i(label, std::to_string(value), unit);
}
