#include "Adminive_Config.h"
#include "Global.h"
#include "adminive/adminive.hpp"
#include "adminive/adapters/drogon.hpp"
#include "adminive/adapters/magic_enum.hpp"
#include "adminive/adapters/nlohmann_json.hpp"
#include <algorithm>
#include <charconv>
#include <cstdint>
#include <map>
#include <memory>
#include <mutex>
#include <stdexcept>
#include <string>
#include <utility>
#include <vector>
namespace ecap::adminive_config {
enum class Data_Source_Type {
    Serial_Data_Source,
    TCP_Client_Data_Source,
    File_Data_Source,
    Dll_Data_Source,
    Shared_Memory_Data_Source
};
enum class Data_Feed_Type {
    Data_Feed_TCP_Server,
    Data_Feed_UDP_Server,
    Data_Feed_TCP_Client,
    Data_Feed_UDP_Client
};
enum class Source_Feed_Relation_Type {
    One_to_One_Relation,
    Name_One_To_Many_Relation,
    First_Source_To_All_Feed_Relation
};
struct Data_Source_Row {
    std::string key;
    Data_Source_Type type = Data_Source_Type::TCP_Client_Data_Source;
    bool enable{};
    Data_Source_Data config;
    std::string ip;
    std::uint16_t port{};
    std::string port_name;
    Baud_Rate_Type baud_rate{};
    std::string file_path;
    File_Data_Type data_type = File_Data_Type::BIN_Blank_Text;
    Play_Mode play_mode = Play_Mode::one;
    std::string library_path;
    std::string function_name;
    std::size_t buffer_size{};
    std::string shared_memory_name;
    std::uint64_t shared_memory_size{};
    std::string state;
};
struct Data_Feed_Row {
    std::string key;
    Data_Feed_Type type = Data_Feed_Type::Data_Feed_TCP_Server;
    bool enable{};
    Output_Format output_format;
    Output_Data_Format format = Output_Data_Format::BIN;
    std::uint16_t port{};
    std::string url;
    std::size_t connect_user_buffer_size = 409600;
    std::size_t connect_system_buffer_size = 409600;
    std::string state;
};
struct Source_Feed_Relation_Row {
    std::string key;
    Source_Feed_Relation_Type type = Source_Feed_Relation_Type::One_to_One_Relation;
    bool enable{};
    std::string source_key;
    std::string feed_key;
    std::string feed_name;
};
struct External_Resource_Row {
    std::string name;
    std::string description;
    std::string download_url;
    std::uint64_t update_interval_seconds{};
    std::int64_t last_updated_at{};
    std::size_t row_count{};
    std::string state;
};
}
namespace adminive {
template <>
struct Type_Descriptor<ecap::adminive_config::External_Resource_Row> {
    static auto get() {
        using T = ecap::adminive_config::External_Resource_Row;
        return object<T>("external_resource", "外部数据源管理",
                         ADMINIVE_FIELD_LABEL(T, name, "数据表"),
                         ADMINIVE_FIELD_LABEL(T, description, "说明"),
                         ADMINIVE_FIELD_LABEL(T, download_url, "在线来源"),
                         ADMINIVE_FIELD_LABEL(T, update_interval_seconds, "建议更新周期（秒）"),
                         ADMINIVE_FIELD_LABEL(T, last_updated_at, "上次更新时间"),
                         ADMINIVE_FIELD_LABEL(T, row_count, "行数"),
                         ADMINIVE_FIELD_LABEL(T, state, "状态"));
    }
};
template <>
struct Type_View_Descriptor<ecap::adminive_config::External_Resource_Row> {
    static Table_View table() {
        using T = ecap::adminive_config::External_Resource_Row;
        return table_view<T>(column<&T::name>("数据表").search(), column<&T::description>("说明"), column<&T::download_url>("在线来源"), column<&T::row_count>("行数").sort(), column<&T::last_updated_at>("上次更新时间").sort(), column<&T::update_interval_seconds>("建议更新周期（秒）"), column<&T::state>("状态")).titled("外部数据源管理");
    }
};
template <>
struct Type_Descriptor<ecap::adminive_config::Data_Source_Row> {
    static auto get() {
        using T = ecap::adminive_config::Data_Source_Row;
        using E = ecap::adminive_config::Data_Source_Type;
        auto type = ADMINIVE_FIELD_LABEL(T, type, "数据源类型").creatable().required().select_input();
        type = type.enum_label<E::Serial_Data_Source>("串口数据源")
                   .enum_label<E::TCP_Client_Data_Source>("TCP 客户端数据源")
                   .enum_label<E::File_Data_Source>("文件数据源")
                   .enum_label<E::Dll_Data_Source>("DLL 数据源")
                   .enum_label<E::Shared_Memory_Data_Source>("共享内存数据源");
        return object<T>("data_source", "数据源",
                         ADMINIVE_FIELD_LABEL(T, key, "名称").creatable().required().text_input(),
                         type,
                         ADMINIVE_FIELD_LABEL(T, enable, "启用").creatable().editable().boolean_input(),
                         ADMINIVE_FIELD_LABEL(T, config, "公共与地图配置").creatable().editable(),
                         ADMINIVE_FIELD_LABEL(T, ip, "IP 地址").creatable().editable().text_input().visible_on("${$self.type == 'TCP_Client_Data_Source'}"),
                         ADMINIVE_FIELD_LABEL(T, port, "端口").creatable().editable().number_input().visible_on("${$self.type == 'TCP_Client_Data_Source'}"),
                         ADMINIVE_FIELD_LABEL(T, port_name, "串口名称").creatable().editable().text_input().visible_on("${$self.type == 'Serial_Data_Source'}"),
                         ADMINIVE_FIELD_LABEL(T, baud_rate, "波特率").creatable().editable().select_input().visible_on("${$self.type == 'Serial_Data_Source'}"),
                         ADMINIVE_FIELD_LABEL(T, file_path, "文件路径").creatable().editable().text_input().visible_on("${$self.type == 'File_Data_Source'}"),
                         ADMINIVE_FIELD_LABEL(T, data_type, "数据格式").creatable().editable().select_input().visible_on("${$self.type == 'File_Data_Source' || $self.type == 'Dll_Data_Source' || $self.type == 'Shared_Memory_Data_Source'}"),
                         ADMINIVE_FIELD_LABEL(T, play_mode, "播放模式").creatable().editable().select_input().visible_on("${$self.type == 'File_Data_Source'}"),
                         ADMINIVE_FIELD_LABEL(T, library_path, "库路径").creatable().editable().text_input().visible_on("${$self.type == 'Dll_Data_Source'}"),
                         ADMINIVE_FIELD_LABEL(T, function_name, "函数名").creatable().editable().text_input().visible_on("${$self.type == 'Dll_Data_Source'}"),
                         ADMINIVE_FIELD_LABEL(T, buffer_size, "读取缓冲区大小").creatable().editable().number_input().visible_on("${$self.type == 'Dll_Data_Source'}"),
                         ADMINIVE_FIELD_LABEL(T, shared_memory_name, "共享内存名称").creatable().editable().text_input().visible_on("${$self.type == 'Shared_Memory_Data_Source'}"),
                         ADMINIVE_FIELD_LABEL(T, shared_memory_size, "共享内存大小").creatable().editable().number_input().visible_on("${$self.type == 'Shared_Memory_Data_Source'}"),
                         ADMINIVE_FIELD_LABEL(T, state, "运行状态").text_input());
    }
};
template <>
struct Type_View_Descriptor<ecap::adminive_config::Data_Source_Row> {
    static Table_View table() {
        using T = ecap::adminive_config::Data_Source_Row;
        return table_view<T>(column<&T::key>("名称").search(), column<&T::type>("类型").filter(), column<&T::enable>("启用").filter(), column<&T::state>("状态"))
            .titled("数据源")
            .id_title("序号")
            .create_title("添加数据源")
            .edit_title("编辑")
            .delete_title("删除")
            .delete_confirmation("确定删除该数据源？存在关系依赖时后端会拒绝删除。")
            .reorderable()
            .create_layout(vertical(grid(2, use<&T::key>(), use<&T::type>(), use<&T::enable>()), use<&T::config>(), grid(2, use<&T::ip>(), use<&T::port>(), use<&T::port_name>(), use<&T::baud_rate>(), use<&T::file_path>(), use<&T::data_type>(), use<&T::play_mode>(), use<&T::library_path>(), use<&T::function_name>(), use<&T::buffer_size>(), use<&T::shared_memory_name>(), use<&T::shared_memory_size>())))
            .edit_layout(vertical(grid(2, use<&T::key>(), use<&T::type>(), use<&T::enable>(), use<&T::state>()), use<&T::config>(), grid(2, use<&T::ip>(), use<&T::port>(), use<&T::port_name>(), use<&T::baud_rate>(), use<&T::file_path>(), use<&T::data_type>(), use<&T::play_mode>(), use<&T::library_path>(), use<&T::function_name>(), use<&T::buffer_size>(), use<&T::shared_memory_name>(), use<&T::shared_memory_size>())));
    }
};
template <>
struct Type_Descriptor<ecap::adminive_config::Data_Feed_Row> {
    static auto get() {
        using T = ecap::adminive_config::Data_Feed_Row;
        using E = ecap::adminive_config::Data_Feed_Type;
        auto type = ADMINIVE_FIELD_LABEL(T, type, "数据馈送类型").creatable().required().select_input();
        type = type.enum_label<E::Data_Feed_TCP_Server>("TCP 服务端")
                   .enum_label<E::Data_Feed_UDP_Server>("UDP 服务端")
                   .enum_label<E::Data_Feed_TCP_Client>("TCP 客户端")
                   .enum_label<E::Data_Feed_UDP_Client>("UDP 客户端");
        return object<T>("data_feed", "数据馈送",
                         ADMINIVE_FIELD_LABEL(T, key, "名称").creatable().required().text_input(),
                         type,
                         ADMINIVE_FIELD_LABEL(T, enable, "启用").creatable().editable().boolean_input(),
                         ADMINIVE_FIELD_LABEL(T, output_format, "输出格式").creatable().editable(),
                         ADMINIVE_FIELD_LABEL(T, format, "数据格式").select_input(),
                         ADMINIVE_FIELD_LABEL(T, port, "端口").creatable().editable().number_input(),
                         ADMINIVE_FIELD_LABEL(T, url, "IP 地址").creatable().editable().text_input().visible_on("${$self.type == 'Data_Feed_TCP_Client' || $self.type == 'Data_Feed_UDP_Client'}"),
                         ADMINIVE_FIELD_LABEL(T, connect_user_buffer_size, "TCP 用户缓冲区").creatable().editable().number_input().visible_on("${$self.type == 'Data_Feed_TCP_Server'}"),
                         ADMINIVE_FIELD_LABEL(T, connect_system_buffer_size, "TCP 系统缓冲区").creatable().editable().number_input().visible_on("${$self.type == 'Data_Feed_TCP_Server'}"),
                         ADMINIVE_FIELD_LABEL(T, state, "运行状态").text_input());
    }
};
template <>
struct Type_View_Descriptor<ecap::adminive_config::Data_Feed_Row> {
    static Table_View table() {
        using T = ecap::adminive_config::Data_Feed_Row;
        return table_view<T>(column<&T::key>("名称").search(), column<&T::type>("类型").filter(), column<&T::format>("输出格式").filter(), column<&T::port>("端口").sort(), column<&T::enable>("启用").filter(), column<&T::state>("状态"))
            .titled("数据馈送")
            .id_title("序号")
            .create_title("添加数据馈送")
            .edit_title("编辑")
            .delete_title("删除")
            .delete_confirmation("确定删除该数据馈送？存在关系依赖时后端会拒绝删除。")
            .reorderable()
            .create_layout(vertical(grid(2, use<&T::key>(), use<&T::type>(), use<&T::enable>()), use<&T::output_format>(), grid(2, use<&T::url>(), use<&T::port>(), use<&T::connect_user_buffer_size>(), use<&T::connect_system_buffer_size>())))
            .edit_layout(vertical(grid(2, use<&T::key>(), use<&T::type>(), use<&T::enable>(), use<&T::state>()), use<&T::output_format>(), grid(2, use<&T::url>(), use<&T::port>(), use<&T::connect_user_buffer_size>(), use<&T::connect_system_buffer_size>())));
    }
};
template <>
struct Type_Descriptor<ecap::adminive_config::Source_Feed_Relation_Row> {
    static auto get() {
        using T = ecap::adminive_config::Source_Feed_Relation_Row;
        using E = ecap::adminive_config::Source_Feed_Relation_Type;
        auto type = ADMINIVE_FIELD_LABEL(T, type, "关系类型").creatable().required().select_input();
        type = type.enum_label<E::One_to_One_Relation>("一对一")
                   .enum_label<E::Name_One_To_Many_Relation>("按名称一对多")
                   .enum_label<E::First_Source_To_All_Feed_Relation>("默认：首个数据源到未匹配馈送");
        return object<T>("source_feed_relation", "数据源-数据馈送关系",
                         ADMINIVE_FIELD_LABEL(T, key, "关系名称").creatable().required().text_input(),
                         type,
                         ADMINIVE_FIELD_LABEL(T, enable, "启用").creatable().editable().boolean_input(),
                         ADMINIVE_FIELD_LABEL(T, source_key, "数据源名称").creatable().editable().text_input().visible_on("${$self.type == 'One_to_One_Relation' || $self.type == 'Name_One_To_Many_Relation'}"),
                         ADMINIVE_FIELD_LABEL(T, feed_key, "数据馈送名称").creatable().editable().text_input().visible_on("${$self.type == 'One_to_One_Relation'}"),
                         ADMINIVE_FIELD_LABEL(T, feed_name, "数据馈送名称前缀").description("按名称扫描全部数据馈送；为空时使用数据源名称作为前缀。默认关系只接管前面规则没有匹配到的数据馈送。").creatable().editable().text_input().visible_on("${$self.type == 'Name_One_To_Many_Relation'}"));
    }
};
template <>
struct Type_View_Descriptor<ecap::adminive_config::Source_Feed_Relation_Row> {
    static Table_View table() {
        using T = ecap::adminive_config::Source_Feed_Relation_Row;
        return table_view<T>(column<&T::key>("关系名称").search(), column<&T::type>("类型").filter(), column<&T::source_key>("数据源"), column<&T::feed_key>("数据馈送"), column<&T::feed_name>("名称前缀"), column<&T::enable>("启用").filter())
            .titled("数据源-数据馈送关系")
            .id_title("序号")
            .create_title("添加关系")
            .edit_title("编辑")
            .delete_title("删除")
            .delete_confirmation("确定删除该关系？")
            .reorderable()
            .create_layout(vertical(grid(2, use<&T::key>(), use<&T::type>(), use<&T::enable>()), grid(2, use<&T::source_key>(), use<&T::feed_key>(), use<&T::feed_name>())))
            .edit_layout(vertical(grid(2, use<&T::key>(), use<&T::type>(), use<&T::enable>()), grid(2, use<&T::source_key>(), use<&T::feed_key>(), use<&T::feed_name>())));
    }
};
template <>
struct Type_View_Descriptor<Mode_ACS_Config_Data> {
    static Form_View edit() {
        using T = Mode_ACS_Config_Data;
        return edit_form<T>(vertical(
            group("基础时序", grid(2, use<&T::timeout_seconds>(), use<&T::air_pos_timeout>(), use<&T::surface_pos_timeout>())),
            group("过滤参数", grid(2, use<&T::max_speed_m_s>(), use<&T::time_space_filter>(), use<&T::speed_filter>(), use<&T::aircraft_change_list_adsb_range_filter>(), use<&T::aircraft_change_list_adsb_range_factor>(), use<&T::adsb_theoretical_target_altitude_meters>())),
            group("容量与上报", grid(2, use<&T::max_track_point_size>(), use<&T::mode_s_max_num>(), use<&T::mode_other_max_num>(), use<&T::report_data_feed_msg_mum>(), use<&T::default_min_aircraft_list_num>(), use<&T::aircraft_change_list_min_position_points>())),
            group("运行开关", grid(2, use<&T::wait_process_msg>(), use<&T::monitor_msg_live>())))).submit("保存 Mode ACS 配置");
    }
};
template <>
struct Type_View_Descriptor<Cesium_Graphics_Config_Data> {
    static Form_View edit() {
        using T = Cesium_Graphics_Config_Data;
        return edit_form<T>(vertical(
            group("渲染质量", grid(2, use<&T::debug_show_frames_per_second>(), use<&T::target_frame_rate>(), use<&T::use_browser_recommended_resolution>(), use<&T::resolution_scale>(), use<&T::msaa_samples>(), use<&T::fxaa>(), use<&T::maximum_screen_space_error>())),
            group("光照与阴影", grid(2, use<&T::shadows>(), use<&T::enable_lighting>(), use<&T::solar_lighting>(), use<&T::solar_light_intensity>())),
            group("地形", grid(2, use<&T::terrain_enabled_in_3d>(), use<&T::terrain_exaggeration>(), use<&T::terrain_limit_maximum_level>(), use<&T::terrain_maximum_level>(), use<&T::terrain_cache_tiles>(), use<&T::terrain_occlusion_enabled>(), use<&T::occlusion_sample_spacing_meters>(), use<&T::occlusion_clearance_margin_meters>())),
            group("辅助显示", grid(2, use<&T::surface_navigation_reference_visible>(), use<&T::view_axes_visible>(), use<&T::performance_panel_x>(), use<&T::performance_panel_y>(), use<&T::view_axes_panel_x>(), use<&T::view_axes_panel_y>(), use<&T::view_axes_panel_size>())))).submit("保存 Cesium 图形配置");
    }
};
template <>
struct Type_View_Descriptor<Data_feed_Config_Data> {
    static Form_View edit() {
        using T = Data_feed_Config_Data;
        return edit_form<T>(grid(2, use<&T::packet_byte_size>())).submit("保存数据馈送全局配置");
    }
};
template <>
struct Type_View_Descriptor<MLAT_Config_Data> {
    static Form_View edit() {
        using T = MLAT_Config_Data;
        return edit_form<T>(grid(2, use<&T::merge>())).submit("保存 MLAT 配置");
    }
};
}
namespace ecap::adminive_config {
namespace {
using Json = nlohmann::json;
class Conflict_Error final : public std::runtime_error {
public:
    using std::runtime_error::runtime_error;
};
class Bad_Request_Error final : public std::runtime_error {
public:
    using std::runtime_error::runtime_error;
};
template <class Model>
adminive::Resource_Transaction<Model> value_section_transaction(Config_Section section) {
    adminive::Resource_Transaction<Model> transaction;
    transaction.commit = [section](const Model& value, const adminive::Request_Context&) {
        Config::save(section, value.to_base_json());
    };
    transaction.rollback = transaction.commit;
    return transaction;
}
adminive::Resource_Transaction<Mode_ACS_Config_Data> mode_acs_transaction() {
    adminive::Resource_Transaction<Mode_ACS_Config_Data> transaction;
    const auto persist = [](const Mode_ACS_Config_Data& value, const adminive::Request_Context&) {
        SSR::Monitor_Mode_ACS_Message_Num = value.monitor_msg_live;
        Config::merge(Config_Section::mode_acs, value.to_base_json());
    };
    transaction.commit = persist;
    transaction.rollback = persist;
    return transaction;
}
adminive::Resource_Transaction<Data_feed_Config_Data> data_feed_settings_transaction() {
    adminive::Resource_Transaction<Data_feed_Config_Data> transaction;
    const auto persist = [](const Data_feed_Config_Data& value, const adminive::Request_Context&) {
        auto patch = Psc::JSON::object();
        patch.append({"data_feed", value.to_base_json()});
        Config::merge(Config_Section::mode_acs, patch);
    };
    transaction.commit = persist;
    transaction.rollback = persist;
    return transaction;
}
adminive::Resource_Transaction<Map_View_Config> map_view_transaction(Global* global) {
    adminive::Resource_Transaction<Map_View_Config> transaction;
    transaction.prepare = [global](const Map_View_Config& value, const adminive::Request_Context&) {
        if(!Map_View_Config::is_scene_mode(value.scene_mode))
            throw adminive::Field_Validation_Error("scene_mode", "场景模式必须为 2d 或 3d");
        global->map_resources_config.read([&](const auto& resources) {
            if(!resources.is_imagery_key(value.map2d.current_imagery_key))
                throw adminive::Field_Validation_Error("map2d.current_imagery_key", "影像源不存在");
            if(!resources.is_terrain_key(value.map2d.current_terrain_key))
                throw adminive::Field_Validation_Error("map2d.current_terrain_key", "地形源不存在");
            if(!resources.is_imagery_key(value.map3d.current_imagery_key))
                throw adminive::Field_Validation_Error("map3d.current_imagery_key", "影像源不存在");
            if(!resources.is_terrain_key(value.map3d.current_terrain_key))
                throw adminive::Field_Validation_Error("map3d.current_terrain_key", "地形源不存在");
        });
    };
    const auto persist = [global](const Map_View_Config& value, const adminive::Request_Context&) {
        global->map_resources_config.write([&](auto& resources) {
            resources.current_imagery_key = value.scene_mode == "2d" ? value.map2d.current_imagery_key : value.map3d.current_imagery_key;
        });
        Config::save(Config_Section::map_view, value.to_base_json());
        Config::save(Config_Section::map_resources);
    };
    transaction.commit = persist;
    transaction.rollback = persist;
    return transaction;
}
void save_data_sources(Global* global) {
    auto patch = Psc::JSON::object();
    patch.append({"data_source", global->mode_acs.data_source_config.to_json()});
    Config::merge(Config_Section::mode_acs, patch);
}
void save_data_feeds(Global* global) {
    auto feed = Psc::JSON::object();
    feed.append({"list", global->mode_acs.data_feed_config.list()});
    auto patch = Psc::JSON::object();
    patch.append({"data_feed", feed});
    Config::merge(Config_Section::mode_acs, patch);
}
void save_source_feed_relations(Global* global) {
    auto patch = Psc::JSON::object();
    patch.append({"source_feed_relation", global->mode_acs.source_feed_relation_config.to_json()});
    Config::merge(Config_Section::mode_acs, patch);
}
template <class Function>
adminive::Http_Response<Json> business_response(Function&& function) noexcept {
    try {
        return std::forward<Function>(function)();
    } catch(const Bad_Request_Error& error) {
        return adminive::make_http_error<Json>(400, error.what());
    } catch(const Conflict_Error& error) {
        return adminive::make_http_error<Json>(409, error.what());
    } catch(const std::out_of_range& error) {
        return adminive::make_http_error<Json>(404, error.what());
    } catch(const std::invalid_argument& error) {
        return adminive::make_http_error<Json>(422, error.what());
    } catch(const std::exception& error) {
        return adminive::make_http_error<Json>(500, error.what());
    } catch(...) {
        return adminive::make_http_error<Json>(500, "unknown server error");
    }
}
Json read_request_body(std::string_view body) {
    try {
        auto input = adminive::parse_json<Json>(body);
        adminive::Json_Adapter<Json>::erase(input, "id");
        return input;
    } catch(const std::exception& error) {
        throw Bad_Request_Error(error.what());
    }
}
template <class Function>
void complete_business_request(std::function<void(const drogon::HttpResponsePtr&)>& callback, Function&& function) noexcept {
    callback(adminive::make_drogon_response(business_response(std::forward<Function>(function))));
}
adminive::Collection_Query read_collection_query(const drogon::HttpRequestPtr& request) {
    adminive::Collection_Query query;
    query.page = adminive::read_drogon_size_parameter(request, "page", 1);
    query.per_page = adminive::read_drogon_size_parameter(request, "perPage", 20);
    query.order_by = request->getParameter("orderBy");
    query.order_dir = request->getParameter("orderDir");
    for(const auto& [name, value] : request->getParameters()) {
        if(name != "page" && name != "perPage" && name != "orderBy" && name != "orderDir")
            query.fields.insert_or_assign(name, value);
    }
    return query;
}
std::vector<std::uint64_t> read_order_ids(std::string_view body) {
    const Json input = adminive::parse_json<Json>(body);
    if(!input.contains("ids"))
        throw std::invalid_argument("missing ids");
    const auto& value = input.at("ids");
    std::vector<std::uint64_t> result;
    if(value.is_array()) {
        result.reserve(value.size());
        for(const auto& item : value)
            result.push_back(item.is_string() ? std::stoull(item.get<std::string>()) : item.get<std::uint64_t>());
        return result;
    }
    const std::string text = value.get<std::string>();
    std::size_t begin{};
    while(begin < text.size()) {
        const auto end = text.find(',', begin);
        const auto token = std::string_view(text).substr(begin, end == std::string::npos ? text.size() - begin : end - begin);
        std::uint64_t id{};
        const auto [position, error] = std::from_chars(token.data(), token.data() + token.size(), id);
        if(error != std::errc{} || position != token.data() + token.size())
            throw std::invalid_argument("invalid order id");
        result.push_back(id);
        if(end == std::string::npos)
            break;
        begin = end + 1;
    }
    return result;
}
template <class Value>
std::shared_ptr<Value> item_by_id(const std::vector<std::shared_ptr<Value>>& list, std::uint64_t id) {
    if(id == 0 || id > list.size())
        throw std::out_of_range("record not found");
    return list[id - 1];
}
template <class Value>
std::vector<std::string> ordered_keys(const std::vector<std::shared_ptr<Value>>& list, const std::vector<std::uint64_t>& ids) {
    if(ids.size() != list.size())
        throw std::invalid_argument("order must contain every record");
    std::vector<bool> used(list.size());
    std::vector<std::string> keys;
    keys.reserve(ids.size());
    for(const auto id : ids) {
        if(id == 0 || id > list.size() || used[id - 1])
            throw std::invalid_argument("invalid order id");
        used[id - 1] = true;
        keys.push_back(list[id - 1]->key);
    }
    return keys;
}
std::string source_type_name(Data_Source_Type value) {
    return std::string(magic_enum::enum_name(value));
}
std::string feed_type_name(Data_Feed_Type value) {
    return std::string(magic_enum::enum_name(value));
}
std::string relation_type_name(Source_Feed_Relation_Type value) {
    return std::string(magic_enum::enum_name(value));
}
Data_Source_Type source_type(std::string_view value) {
    const auto result = magic_enum::enum_cast<Data_Source_Type>(value);
    if(!result)
        throw std::invalid_argument("未知数据源类型: " + std::string(value));
    return *result;
}
Data_Feed_Type feed_type(std::string_view value) {
    const auto result = magic_enum::enum_cast<Data_Feed_Type>(value);
    if(!result)
        throw std::invalid_argument("未知数据馈送类型: " + std::string(value));
    return *result;
}
Source_Feed_Relation_Type relation_type(std::string_view value) {
    const auto result = magic_enum::enum_cast<Source_Feed_Relation_Type>(value);
    if(!result)
        throw std::invalid_argument("未知关系类型: " + std::string(value));
    return *result;
}
Data_Source_Row source_row(const std::shared_ptr<Data_Source>& source) {
    Data_Source_Row row;
    row.key = source->key;
    row.type = source_type(source->type);
    row.enable = source->enabled();
    source->settings.read([&](const auto& value) {
        row.config = value;
    });
    row.state = Psc::to_string(source->state);
    if(const auto source_value = dynamic_cast<TCP_Client_Data_Source*>(source.get())) {
        source_value->specific.read([&](const auto& value) {
            row.ip = value.ip;
            row.port = value.port;
        });
    } else if(const auto source_value = dynamic_cast<Serial_Data_Source*>(source.get())) {
        source_value->specific.read([&](const auto& value) {
            row.port_name = value.port_name;
            row.baud_rate = value.baud_rate;
        });
    } else if(const auto source_value = dynamic_cast<File_Data_Source*>(source.get())) {
        source_value->specific.read([&](const auto& value) {
            row.file_path = value.file_path;
            row.data_type = value.data_type;
            row.play_mode = value.play_mode;
        });
    } else if(const auto source_value = dynamic_cast<Dll_Data_Source*>(source.get())) {
        source_value->specific.read([&](const auto& value) {
            row.library_path = value.library_path;
            row.function_name = value.function_name;
            row.data_type = value.data_type;
            row.buffer_size = value.buffer_size;
        });
    } else if(const auto source_value = dynamic_cast<Shared_Memory_Data_Source*>(source.get())) {
        source_value->specific.read([&](const auto& value) {
            row.shared_memory_name = value.shared_memory_name;
            row.shared_memory_size = value.shared_memory_size;
            row.data_type = value.data_type;
        });
    }
    return row;
}
void apply_source_row(const std::shared_ptr<Data_Source>& source, const Data_Source_Row& row) {
    source->set_enabled(row.enable);
    source->settings.write([&](auto& value) {
        value = row.config;
    });
    if(auto source_value = dynamic_cast<TCP_Client_Data_Source*>(source.get())) {
        source_value->specific.write([&](auto& value) {
            value.ip = row.ip;
            value.port = row.port;
        });
    } else if(auto source_value = dynamic_cast<Serial_Data_Source*>(source.get())) {
        source_value->specific.write([&](auto& value) {
            value.port_name = row.port_name;
            value.baud_rate = row.baud_rate;
        });
    } else if(auto source_value = dynamic_cast<File_Data_Source*>(source.get())) {
        source_value->specific.write([&](auto& value) {
            value.file_path = row.file_path;
            value.data_type = row.data_type;
            value.play_mode = row.play_mode;
        });
    } else if(auto source_value = dynamic_cast<Dll_Data_Source*>(source.get())) {
        source_value->specific.write([&](auto& value) {
            value.library_path = row.library_path;
            value.function_name = row.function_name;
            value.data_type = row.data_type;
            value.buffer_size = row.buffer_size;
        });
        source_value->buffer.resize(row.buffer_size);
    } else if(auto source_value = dynamic_cast<Shared_Memory_Data_Source*>(source.get())) {
        source_value->specific.write([&](auto& value) {
            value.shared_memory_name = row.shared_memory_name;
            value.shared_memory_size = row.shared_memory_size;
            value.data_type = row.data_type;
        });
    }
}
Data_Feed_Row feed_row(const std::shared_ptr<Data_Feed>& feed) {
    Data_Feed_Row row;
    row.key = feed->key;
    row.type = feed_type(feed->type);
    row.enable = feed->enabled();
    feed->output_format.read([&](const auto& value) {
        row.output_format = value;
        row.format = value.type;
    });
    row.state = Psc::to_string(feed->state);
    if(const auto feed_value = dynamic_cast<Data_Feed_TCP_Server*>(feed.get())) {
        feed_value->specific.read([&](const auto& value) {
            row.port = value.port;
            row.connect_user_buffer_size = value.connect_user_buffer_size;
            row.connect_system_buffer_size = value.connect_system_buffer_size;
        });
    } else if(const auto feed_value = dynamic_cast<Data_Feed_UDP_Server*>(feed.get())) {
        feed_value->specific.read([&](const auto& value) {
            row.port = value.port;
        });
    } else if(const auto feed_value = dynamic_cast<Data_Feed_TCP_Client*>(feed.get())) {
        feed_value->specific.read([&](const auto& value) {
            row.url = value.url;
            row.port = value.port;
        });
    } else if(const auto feed_value = dynamic_cast<Data_Feed_UDP_Client*>(feed.get())) {
        feed_value->specific.read([&](const auto& value) {
            row.url = value.url;
            row.port = value.port;
        });
    }
    return row;
}
void apply_feed_row(const std::shared_ptr<Data_Feed>& feed, const Data_Feed_Row& row) {
    feed->set_enabled(row.enable);
    feed->output_format.write([&](auto& value) {
        value = row.output_format;
    });
    if(auto feed_value = dynamic_cast<Data_Feed_TCP_Server*>(feed.get())) {
        feed_value->specific.write([&](auto& value) {
            value.port = row.port;
            value.connect_user_buffer_size = row.connect_user_buffer_size;
            value.connect_system_buffer_size = row.connect_system_buffer_size;
        });
    } else if(auto feed_value = dynamic_cast<Data_Feed_UDP_Server*>(feed.get())) {
        feed_value->specific.member<&Data_Feed_UDP_Server_Data::port>().write([&](auto& value) {
            value = row.port;
        });
    } else if(auto feed_value = dynamic_cast<Data_Feed_TCP_Client*>(feed.get())) {
        feed_value->specific.write([&](auto& value) {
            value.url = row.url;
            value.port = row.port;
        });
    } else if(auto feed_value = dynamic_cast<Data_Feed_UDP_Client*>(feed.get())) {
        feed_value->specific.write([&](auto& value) {
            value.url = row.url;
            value.port = row.port;
        });
    }
}
Source_Feed_Relation_Row relation_row(const std::shared_ptr<Source_Feed_Relation>& relation) {
    Source_Feed_Relation_Row row;
    row.key = relation->key;
    row.type = relation_type(relation->type);
    relation->settings.read([&](const auto& value) {
        row.enable = value.enable;
        row.source_key = value.source_key;
        row.feed_key = value.feed_key;
        row.feed_name = value.feed_name;
    });
    return row;
}
void apply_relation_row(const std::shared_ptr<Source_Feed_Relation>& relation, const Source_Feed_Relation_Row& row) {
    relation->settings.write([&](auto& value) {
        value.enable = row.enable;
        value.source_key = row.source_key;
        value.feed_key = row.feed_key;
        value.feed_name = row.feed_name;
    });
}
template <class Row>
adminive::Http_Response<Json> list_response(std::string path, std::vector<Row> rows, adminive::Collection_Query query) {
    adminive::Collection_Service<Row, Json> collection(std::move(path), std::move(rows));
    return collection.list_response(std::move(query));
}
template <class Row>
adminive::Http_Response<Json> item_response(std::string path, std::vector<Row> rows, std::uint64_t id) {
    adminive::Collection_Service<Row, Json> collection(std::move(path), std::move(rows));
    return collection.item_response(id);
}
template <class Row, class Descriptor_Factory, class Rows_Factory, class Schema_Factory>
void bind_collection_read_handlers(drogon::HttpAppFramework& app, std::string path,
                                   Descriptor_Factory descriptor_factory, Rows_Factory rows_factory,
                                   Schema_Factory schema_factory, bool bind_item) {
    const auto get = adminive::make_drogon_constraints(drogon::Get, {});
    app.registerHandler(path + "/descriptor", [descriptor_factory](const drogon::HttpRequestPtr&, std::function<void(const drogon::HttpResponsePtr&)>&& callback) {
        callback(adminive::make_drogon_response(adminive::make_http_success<Json>(descriptor_factory())));
    }, get);
    app.registerHandler(path + "/view", [](const drogon::HttpRequestPtr&, std::function<void(const drogon::HttpResponsePtr&)>&& callback) {
        callback(adminive::make_drogon_response(adminive::make_http_success<Json>(adminive::to_view_json<Json, Row>(adminive::describe_table_view<Row>()))));
    }, get);
    app.registerHandler(path + "/amis", [schema_factory](const drogon::HttpRequestPtr&, std::function<void(const drogon::HttpResponsePtr&)>&& callback) {
        callback(adminive::make_drogon_response(adminive::make_http_success<Json>(schema_factory())));
    }, get);
    app.registerHandler(path, [path, rows_factory](const drogon::HttpRequestPtr& request, std::function<void(const drogon::HttpResponsePtr&)>&& callback) {
        callback(adminive::make_drogon_response(list_response<Row>(path, rows_factory(), read_collection_query(request))));
    }, get);
    if(bind_item) {
        app.registerHandler(path + "/{1:id}", [path, rows_factory](const drogon::HttpRequestPtr&, std::function<void(const drogon::HttpResponsePtr&)>&& callback, std::uint64_t id) {
            callback(adminive::make_drogon_response(item_response<Row>(path, rows_factory(), id)));
        }, get);
    }
}
std::vector<Data_Source_Row> source_rows(Global* global) {
    std::vector<Data_Source_Row> rows;
    for(const auto& source : global->mode_acs.data_source_config.map.list())
        rows.push_back(source_row(source));
    return rows;
}
std::vector<Data_Feed_Row> feed_rows(Global* global) {
    std::vector<Data_Feed_Row> rows;
    for(const auto& feed : global->mode_acs.data_feed_config.map.list())
        rows.push_back(feed_row(feed));
    return rows;
}
std::vector<Source_Feed_Relation_Row> relation_rows(Global* global) {
    std::vector<Source_Feed_Relation_Row> rows;
    for(const auto& relation : global->mode_acs.source_feed_relation_config.map.list())
        rows.push_back(relation_row(relation));
    return rows;
}
std::vector<External_Resource_Row> external_resource_rows(Global* global) {
    std::map<std::string, External_Resource_Status> status_by_name;
    for(auto status : global->external_resources_manager.external_database_status())
        status_by_name.emplace(status.name, std::move(status));
    const auto config = global->external_resources_manager.to_base_json();
    const auto* list = config.get("list");
    std::vector<External_Resource_Row> rows;
    if(!list)
        return rows;
    rows.reserve(list->children.size());
    for(const auto& item : list->children) {
        External_Resources_Data value;
        value.from_base_json(&item, false);
        External_Resource_Row row;
        row.name = value.name;
        row.description = value.description;
        row.download_url = value.download_url;
        row.update_interval_seconds = value.update_interval_seconds;
        row.last_updated_at = static_cast<std::int64_t>(value.last_updated_at);
        const auto status = status_by_name.find(value.name);
        if(status != status_by_name.end()) {
            row.row_count = status->second.row_count;
            row.state = status->second.message;
        }
        rows.push_back(std::move(row));
    }
    return rows;
}
Json source_amis_schema() {
    return adminive::to_amis_table_schema<Json, Data_Source_Row>("/api/adminive/config/data_sources", adminive::describe_table_view<Data_Source_Row>());
}
Json feed_amis_schema() {
    return adminive::to_amis_table_schema<Json, Data_Feed_Row>("/api/adminive/config/data_feeds", adminive::describe_table_view<Data_Feed_Row>());
}
Json relation_amis_schema() {
    return adminive::to_amis_table_schema<Json, Source_Feed_Relation_Row>("/api/adminive/config/source_feed_relations", adminive::describe_table_view<Source_Feed_Relation_Row>());
}
Json external_resource_amis_schema() {
    auto schema = adminive::to_amis_table_schema<Json, External_Resource_Row>("/api/adminive/config/external_resources", adminive::describe_table_view<External_Resource_Row>());
    auto& crud = schema["body"][0];
    const std::string crud_id = "external_resource_table_crud";
    crud["headerToolbar"] = Json::array({Json{{"type", "columns-toggler"}, {"draggable", true}}, "reload", Json{{"type", "button"}, {"label", "全部后端下载并导入"}, {"level", "primary"}, {"actionType", "ajax"}, {"api", Json{{"method", "post"}, {"url", "/api/refresh_external_databases"}}}, {"reload", crud_id}}});
    auto& columns = crud["columns"];
    if(!columns.empty())
        columns.erase(columns.end() - 1);
    const auto refresh_button = Json{{"type", "button"}, {"label", "后端下载并导入"}, {"level", "link"}, {"actionType", "ajax"}, {"api", Json{{"method", "post"}, {"url", "/api/refresh_external_database"}, {"data", Json{{"name", "${name}"}}}}}, {"reload", crud_id}};
    const auto download_button = Json{{"type", "button"}, {"label", "前端下载"}, {"level", "link"}, {"actionType", "url"}, {"url", "${download_url}"}, {"blank", true}, {"disabledOn", "!this.download_url"}};
    const auto upload_button = Json{{"type", "button"}, {"label", "离线导入"}, {"level", "link"}, {"actionType", "dialog"}, {"dialog", Json{{"title", "离线导入 ${name}"}, {"body", Json{{"type", "input-file"}, {"name", "file"}, {"label", "数据文件"}, {"accept", ".csv,.gz,.zip,.txt"}, {"receiver", Json{{"method", "post"}, {"url", "/api/upload_external_database"}, {"data", Json{{"name", "${name}"}}}}}}}}}};
    const auto clear_button = Json{{"type", "button"}, {"label", "清空数据表"}, {"level", "link"}, {"className", "text-danger"}, {"actionType", "ajax"}, {"confirmText", "确定清空 ${name}？"}, {"api", Json{{"method", "post"}, {"url", "/api/clear_external_database_table"}, {"data", Json{{"name", "${name}"}}}}}, {"reload", crud_id}};
    columns.push_back(Json{{"type", "operation"}, {"label", "操作"}, {"buttons", Json::array({refresh_button, download_button, upload_button, clear_button})}});
    return schema;
}
Json backend_config_schema() {
    return Json{{"title", "后端完整配置（只读）"}, {"data_api", "/api/adminive/config/backend_config"}};
}
Json archive_operations_schema() {
    const auto formats = Json::array({Json{{"label", "ZIP (.zip)"}, {"value", "zip"}, {"format", "zip"}, {"filter", ""}, {"extension", "zip"}}, Json{{"label", "TAR (.tar)"}, {"value", "tar"}, {"format", "pax"}, {"filter", ""}, {"extension", "tar"}}, Json{{"label", "TAR.GZ (.tar.gz)"}, {"value", "tar.gz"}, {"format", "pax"}, {"filter", "gzip"}, {"extension", "tar.gz"}}, Json{{"label", "TAR.XZ (.tar.xz)"}, {"value", "tar.xz"}, {"format", "pax"}, {"filter", "xz"}, {"extension", "tar.xz"}}, Json{{"label", "TAR.ZST (.tar.zst)"}, {"value", "tar.zst"}, {"format", "pax"}, {"filter", "zstd"}, {"extension", "tar.zst"}}, Json{{"label", "TAR.BZ2 (.tar.bz2)"}, {"value", "tar.bz2"}, {"format", "pax"}, {"filter", "bzip2"}, {"extension", "tar.bz2"}}, Json{{"label", "TAR.LZ4 (.tar.lz4)"}, {"value", "tar.lz4"}, {"format", "pax"}, {"filter", "lz4"}, {"extension", "tar.lz4"}}, Json{{"label", "7Z (.7z)"}, {"value", "7z"}, {"format", "7zip"}, {"filter", ""}, {"extension", "7z"}}});
    return Json{{"title", "导入导出"}, {"formats", std::move(formats)}, {"exports", Json::array({Json{{"name", "版本"}, {"api", "/api/export_version"}, {"allow_version_selection", true}}, Json{{"name", "日志"}, {"api", "/api/export_logs"}, {"allow_version_selection", false}}})}, {"import_api", "/api/import_version"}, {"import_accept", ".tar.zstd,.tar.zst,.tar.gz,.tgz,.tar.xz,.txz,.tar.bz2,.tbz2,.tar.lz4,.zip,.7z,.rar,.tar,.cpio,.iso,.xar"}};
}
Json data_source_descriptor() {
    auto descriptor = adminive::to_descriptor_json<Json, Data_Source_Row>();
    const auto tile_view_descriptor = adminive::to_descriptor_json<Json, Map_Tile_View_Config>();
    const auto map_view_descriptor = adminive::to_descriptor_json<Json, Map_View_Config>();
    const auto graphics_descriptor = adminive::to_descriptor_json<Json, Cesium_Graphics_Config_Data>();
    descriptor["sidebar"] = Json{
        {"source", Json{
            {"title", "数据源配置"},
            {"sections", Json::array({
                Json{{"layout", Json::array({Json{{"kind", "cards"}, {"fields", Json::array({"update_form_gps", "base_station_has_valid_position", "keep_mode", "ignore_msg_time"})}}})}},
                Json{{"layout", Json::array({Json{{"kind", "vertical"}, {"fields", Json::array({"lat", "lon", "alt"})}}})}},
                Json{
                {"title", "2D显示配置"},
                {"modes", Json::array({"map2d"})},
                {"object_path", "map_display.map2d"},
                {"layout", Json::array({
                    Json{{"kind", "cards"}, {"fields", Json::array({"aircraft_show", "base_station_show", "show_icao", "show_call_sign", "show_fly_status"})}},
                    Json{{"kind", "vertical"}, {"fields", Json::array({"aircraft_pixel_size", "base_station_pixel_size", "track_point_pixel_size", "color", "track_point_color", "base_station_color"})}}
                })}
                },
                Json{
                {"title", "3D显示配置"},
                {"modes", Json::array({"map3d"})},
                {"object_path", "map_display.map3d"},
                {"layout", Json::array({
                    Json{{"kind", "cards"}, {"fields", Json::array({"aircraft_show", "base_station_show", "constant_screen_size", "show_icao", "show_call_sign", "show_fly_status"})}},
                    Json{{"kind", "vertical"}, {"fields", Json::array({"aircraft_scale", "base_station_scale", "track_point_pixel_size", "color", "track_point_color", "base_station_color"})}}
                })}
                }
            })},
            {"rules", Json::array({
                Json{{"field", "base_station_has_valid_position"}, {"disabled_when", Json{{"field", "update_form_gps"}, {"equals", true}}}},
                Json{{"field", "lat"}, {"disabled_when", Json{{"field", "update_form_gps"}, {"equals", true}}}},
                Json{{"field", "lon"}, {"disabled_when", Json{{"field", "update_form_gps"}, {"equals", true}}}},
                Json{{"field", "alt"}, {"disabled_when", Json{{"field", "update_form_gps"}, {"equals", true}}}}
            })}
        }},
        {"tiles", Json{
            {"title", "瓦片显示"},
            {"layout", Json::array({Json{{"kind", "vertical"}, {"fields", Json::array({"tile_display_maximum_level"})}}})},
            {"descriptor_fields", tile_view_descriptor.at("fields")}
        }},
        {"view3d", Json{
            {"graphics", Json{
                {"title", "辅助显示"},
                {"layout", Json::array({Json{{"kind", "cards"}, {"fields", Json::array({"surface_navigation_reference_visible", "view_axes_visible"})}}})},
                {"descriptor_fields", graphics_descriptor.at("fields")}
            }},
            {"map_view", Json{
                {"title", "定位视图"},
                {"layout", Json::array({Json{{"kind", "vertical"}, {"fields", Json::array({"base_station_fly_to_height_offset_meters"})}}})},
                {"descriptor_fields", map_view_descriptor.at("fields")}
            }}
        }}
    };
    return descriptor;
}
Json cesium_models_schema(Global* global) {
    Json aircraft_types = Json::array();
    global->map_model_config.read([&](const auto& config) {
        for(const auto& [key, value] : config.aircraft_models) {
            static_cast<void>(value);
            auto label = key;
            for(std::uint8_t raw = 1; raw <= 21; ++raw) {
                const auto type = static_cast<SSR::Vortex_Type>(raw);
                if(SSR::Vortex_Type_to_key(type) == key) {
                    label = SSR::Vortex_Type_to_label(type);
                    break;
                }
            }
            aircraft_types.push_back(Json{{"key", key}, {"label", label}});
        }
    });
    const auto item_descriptor = adminive::to_descriptor_json<Json, Map_Model_Item_Config>();
    return Json{
        {"title", "Cesium 模型设置"},
        {"data_api", "/map/models"},
        {"upload_accept", ".glb"},
        {"item_descriptor", item_descriptor},
        {"groups", Json::array({
            Json{{"title", "默认飞机模型"}, {"path", "aircraft_model"}, {"upload", Json{{"model_type", "aircraft"}, {"label", "上传飞机模型"}, {"success_message", "默认飞机模型已更新"}}}},
            Json{{"title", "基站模型"}, {"path", "base_station_model"}, {"upload", Json{{"model_type", "base_station"}, {"label", "上传基站模型"}, {"success_message", "基站模型已更新"}}}},
            Json{{"title", "设备模型"}, {"path", "device_model"}, {"upload", Json{{"model_type", "device"}, {"label", "上传设备模型"}, {"success_message", "设备模型已更新"}}}}
        })},
        {"collections", Json::array({
            Json{{"title", "按涡流/目标类型选择飞机模型"}, {"path", "aircraft_models"}, {"upload_model_type", "aircraft_type"}, {"upload_label", "上传 GLB"}, {"upload_success_message", "分类飞机模型已更新"}, {"items", std::move(aircraft_types)}}
        })}
    };
}
Json system_actions_schema() {
    return Json{{"type", "panel"}, {"title", "设备操作"}, {"body", Json::array({Json{{"type", "button"}, {"label", "重启 FPGA 设备"}, {"level", "primary"}, {"actionType", "ajax"}, {"confirmText", "确定重启 FPGA 设备？"}, {"api", Json{{"method", "post"}, {"url", "/api/restart_device"}}}}})}};
}
class Adminive_Config_Resources {
public:
    explicit Adminive_Config_Resources(Global* global) : global_(global),
        mode_acs_resource_(global->mode_acs.settings, mode_acs_path, mode_acs_transaction()),
        data_feed_settings_resource_(global->mode_acs.data_feed_config.settings, data_feed_settings_path, data_feed_settings_transaction()),
        map_view_resource_(global->map_view_config, map_view_path, map_view_transaction(global)),
        mlat_resource_(global->mlat.settings, mlat_path, value_section_transaction<MLAT_Config_Data>(Config_Section::mlat)),
        cesium_graphics_resource_(global->cesium_graphics_config.settings, cesium_graphics_path, value_section_transaction<Cesium_Graphics_Config_Data>(Config_Section::cesium_graphics)) {
    }
    void bind() {
        auto& app = drogon::app();
        mode_acs_resource_.bind(app);
        data_feed_settings_resource_.bind(app);
        map_view_resource_.bind(app);
        mlat_resource_.bind(app);
        cesium_graphics_resource_.bind(app);
        bind_data_sources(app);
        bind_data_feeds(app);
        bind_relations(app);
        bind_external_resources(app);
        bind_backend_config(app);
        app.registerHandler(manifest_path, [this](const drogon::HttpRequestPtr&, std::function<void(const drogon::HttpResponsePtr&)>&& callback) {
            callback(adminive::make_drogon_response(adminive::make_http_success<Json>(manifest())));
        }, {drogon::Get});
    }
private:
    void bind_backend_config(drogon::HttpAppFramework& app) {
        const auto get = adminive::make_drogon_constraints(drogon::Get, {});
        app.registerHandler(backend_config_path, [this](const drogon::HttpRequestPtr&, std::function<void(const drogon::HttpResponsePtr&)>&& callback) {
            callback(adminive::make_drogon_response(adminive::make_http_success<Json>(Json::parse(global_->toJson().to_json_string()))));
        }, get);
    }
    void bind_external_resources(drogon::HttpAppFramework& app) {
        bind_collection_read_handlers<External_Resource_Row>(app, external_resources_path,
            [] { return adminive::to_descriptor_json<Json, External_Resource_Row>(); },
            [this] { return external_resource_rows(global_); },
            [] { return external_resource_amis_schema(); }, false);
    }
    void bind_data_sources(drogon::HttpAppFramework& app) {
        const auto post = adminive::make_drogon_constraints(drogon::Post, {});
        const auto put = adminive::make_drogon_constraints(drogon::Put, {});
        const auto patch = adminive::make_drogon_constraints(drogon::Patch, {});
        const auto remove = adminive::make_drogon_constraints(drogon::Delete, {});
        bind_collection_read_handlers<Data_Source_Row>(app, data_sources_path,
            [] { return data_source_descriptor(); }, [this] { return source_rows(global_); },
            [] { return source_amis_schema(); }, true);
        app.registerHandler(data_sources_path, [this](const drogon::HttpRequestPtr& request, std::function<void(const drogon::HttpResponsePtr&)>&& callback) {
            complete_business_request(callback, [this, body = std::string(request->getBody())] {
                std::lock_guard lock(topology_mutex_);
                auto input = read_request_body(body);
                Data_Source_Row row;
                const auto result = adminive::apply_frontend_create<Json>(row, input);
                if(!result.success)
                    return adminive::make_http_error<Json>(422, result);
                if(global_->mode_acs.data_source_config.map.get(row.key))
                    return adminive::make_http_error<Json>(409, "数据源名称已存在: " + row.key);
                auto source = create_data_source_from_type(source_type_name(row.type));
                source->key = row.key;
                apply_source_row(source, row);
                global_->mode_acs.data_source_config.map.push_back(source);
                Source_Feed_Relation_Config::set_need_refresh();
                save_data_sources(global_);
                return adminive::make_http_success<Json>(adminive::to_frontend_json<Json>(source_row(source)), "created");
            });
        }, post);
        const auto update = [this](const drogon::HttpRequestPtr& request, std::function<void(const drogon::HttpResponsePtr&)>&& callback, std::uint64_t id) {
            complete_business_request(callback, [this, id, body = std::string(request->getBody())] {
                std::lock_guard lock(topology_mutex_);
                const auto list = global_->mode_acs.data_source_config.map.list();
                auto source = item_by_id(list, id);
                auto input = read_request_body(body);
                auto row = source_row(source);
                const auto result = adminive::apply_frontend_patch<Json>(row, input);
                if(!result.success)
                    return adminive::make_http_error<Json>(422, result);
                apply_source_row(source, row);
                Source_Feed_Relation_Config::set_need_refresh();
                save_data_sources(global_);
                return adminive::make_http_success<Json>(adminive::to_frontend_json<Json>(source_row(source)), result.message);
            });
        };
        app.registerHandler(data_sources_path + "/{1:id}", update, put);
        app.registerHandler(data_sources_path + "/{1:id}", update, patch);
        app.registerHandler(data_sources_path + "/{1:id}", [this](const drogon::HttpRequestPtr&, std::function<void(const drogon::HttpResponsePtr&)>&& callback, std::uint64_t id) {
            complete_business_request(callback, [this, id] {
                std::lock_guard lock(topology_mutex_);
                const auto list = global_->mode_acs.data_source_config.map.list();
                auto source = item_by_id(list, id);
                if(global_->mode_acs.source_feed_relation_config.source_has_dependency(source->key))
                    throw Conflict_Error("数据源存在数据馈送关系依赖，不能删除: " + source->key);
                source->async_stop();
                if(!global_->mode_acs.data_source_config.map.remove(id - 1))
                    throw std::out_of_range("record not found");
                Source_Feed_Relation_Config::set_need_refresh();
                save_data_sources(global_);
                return adminive::make_http_success<Json>(adminive::json_object<Json>(), "deleted");
            });
        }, remove);
        app.registerHandler(data_sources_path + "/order", [this](const drogon::HttpRequestPtr& request, std::function<void(const drogon::HttpResponsePtr&)>&& callback) {
            complete_business_request(callback, [this, body = std::string(request->getBody())] {
                std::lock_guard lock(topology_mutex_);
                const auto list = global_->mode_acs.data_source_config.map.list();
                const auto keys = ordered_keys(list, read_order_ids(body));
                if(!global_->mode_acs.data_source_config.map.set_order(keys))
                    throw std::invalid_argument("invalid order");
                Source_Feed_Relation_Config::set_need_refresh();
                save_data_sources(global_);
                return adminive::make_http_success<Json>(adminive::json_object<Json>(), "reordered");
            });
        }, post);
    }
    void bind_data_feeds(drogon::HttpAppFramework& app) {
        const auto post = adminive::make_drogon_constraints(drogon::Post, {});
        const auto put = adminive::make_drogon_constraints(drogon::Put, {});
        const auto patch = adminive::make_drogon_constraints(drogon::Patch, {});
        const auto remove = adminive::make_drogon_constraints(drogon::Delete, {});
        bind_collection_read_handlers<Data_Feed_Row>(app, data_feeds_path,
            [] { return adminive::to_descriptor_json<Json, Data_Feed_Row>(); },
            [this] { return feed_rows(global_); }, [] { return feed_amis_schema(); }, true);
        app.registerHandler(data_feeds_path, [this](const drogon::HttpRequestPtr& request, std::function<void(const drogon::HttpResponsePtr&)>&& callback) {
            complete_business_request(callback, [this, body = std::string(request->getBody())] {
                std::lock_guard lock(topology_mutex_);
                auto input = read_request_body(body);
                Data_Feed_Row row;
                const auto result = adminive::apply_frontend_create<Json>(row, input);
                if(!result.success)
                    return adminive::make_http_error<Json>(422, result);
                if(global_->mode_acs.data_feed_config.map.get(row.key))
                    return adminive::make_http_error<Json>(409, "数据馈送名称已存在: " + row.key);
                auto feed = create_data_feed_from_type(feed_type_name(row.type));
                feed->key = row.key;
                apply_feed_row(feed, row);
                global_->mode_acs.data_feed_config.map.push_back(feed);
                Source_Feed_Relation_Config::set_need_refresh();
                save_data_feeds(global_);
                return adminive::make_http_success<Json>(adminive::to_frontend_json<Json>(feed_row(feed)), "created");
            });
        }, post);
        const auto update = [this](const drogon::HttpRequestPtr& request, std::function<void(const drogon::HttpResponsePtr&)>&& callback, std::uint64_t id) {
            complete_business_request(callback, [this, id, body = std::string(request->getBody())] {
                std::lock_guard lock(topology_mutex_);
                const auto list = global_->mode_acs.data_feed_config.map.list();
                auto feed = item_by_id(list, id);
                auto input = read_request_body(body);
                auto row = feed_row(feed);
                const auto result = adminive::apply_frontend_patch<Json>(row, input);
                if(!result.success)
                    return adminive::make_http_error<Json>(422, result);
                apply_feed_row(feed, row);
                Source_Feed_Relation_Config::set_need_refresh();
                save_data_feeds(global_);
                return adminive::make_http_success<Json>(adminive::to_frontend_json<Json>(feed_row(feed)), result.message);
            });
        };
        app.registerHandler(data_feeds_path + "/{1:id}", update, put);
        app.registerHandler(data_feeds_path + "/{1:id}", update, patch);
        app.registerHandler(data_feeds_path + "/{1:id}", [this](const drogon::HttpRequestPtr&, std::function<void(const drogon::HttpResponsePtr&)>&& callback, std::uint64_t id) {
            complete_business_request(callback, [this, id] {
                std::lock_guard lock(topology_mutex_);
                const auto list = global_->mode_acs.data_feed_config.map.list();
                auto feed = item_by_id(list, id);
                if(global_->mode_acs.source_feed_relation_config.feed_has_dependency(feed->key))
                    throw Conflict_Error("数据馈送存在数据源关系依赖，不能删除: " + feed->key);
                feed->async_stop();
                if(!global_->mode_acs.data_feed_config.map.remove(id - 1))
                    throw std::out_of_range("record not found");
                Source_Feed_Relation_Config::set_need_refresh();
                save_data_feeds(global_);
                return adminive::make_http_success<Json>(adminive::json_object<Json>(), "deleted");
            });
        }, remove);
        app.registerHandler(data_feeds_path + "/order", [this](const drogon::HttpRequestPtr& request, std::function<void(const drogon::HttpResponsePtr&)>&& callback) {
            complete_business_request(callback, [this, body = std::string(request->getBody())] {
                std::lock_guard lock(topology_mutex_);
                const auto list = global_->mode_acs.data_feed_config.map.list();
                const auto keys = ordered_keys(list, read_order_ids(body));
                if(!global_->mode_acs.data_feed_config.map.set_order(keys))
                    throw std::invalid_argument("invalid order");
                Source_Feed_Relation_Config::set_need_refresh();
                save_data_feeds(global_);
                return adminive::make_http_success<Json>(adminive::json_object<Json>(), "reordered");
            });
        }, post);
    }
    void bind_relations(drogon::HttpAppFramework& app) {
        const auto post = adminive::make_drogon_constraints(drogon::Post, {});
        const auto put = adminive::make_drogon_constraints(drogon::Put, {});
        const auto patch = adminive::make_drogon_constraints(drogon::Patch, {});
        const auto remove = adminive::make_drogon_constraints(drogon::Delete, {});
        bind_collection_read_handlers<Source_Feed_Relation_Row>(app, relations_path,
            [] { return adminive::to_descriptor_json<Json, Source_Feed_Relation_Row>(); },
            [this] { return relation_rows(global_); }, [] { return relation_amis_schema(); }, true);
        app.registerHandler(relations_path, [this](const drogon::HttpRequestPtr& request, std::function<void(const drogon::HttpResponsePtr&)>&& callback) {
            complete_business_request(callback, [this, body = std::string(request->getBody())] {
                std::lock_guard lock(topology_mutex_);
                auto input = read_request_body(body);
                Source_Feed_Relation_Row row;
                const auto result = adminive::apply_frontend_create<Json>(row, input);
                if(!result.success)
                    return adminive::make_http_error<Json>(422, result);
                auto relation = create_source_feed_relation_from_type(relation_type_name(row.type));
                relation->key = row.key;
                apply_relation_row(relation, row);
                global_->mode_acs.source_feed_relation_config.validate(*relation);
                global_->mode_acs.source_feed_relation_config.map.push_back(relation);
                Source_Feed_Relation_Config::set_need_refresh();
                save_source_feed_relations(global_);
                return adminive::make_http_success<Json>(adminive::to_frontend_json<Json>(relation_row(relation)), "created");
            });
        }, post);
        const auto update = [this](const drogon::HttpRequestPtr& request, std::function<void(const drogon::HttpResponsePtr&)>&& callback, std::uint64_t id) {
            complete_business_request(callback, [this, id, body = std::string(request->getBody())] {
                std::lock_guard lock(topology_mutex_);
                const auto list = global_->mode_acs.source_feed_relation_config.map.list();
                auto relation = item_by_id(list, id);
                auto input = read_request_body(body);
                auto row = relation_row(relation);
                const auto result = adminive::apply_frontend_patch<Json>(row, input);
                if(!result.success)
                    return adminive::make_http_error<Json>(422, result);
                auto candidate = create_source_feed_relation_from_type(relation->type);
                candidate->key = relation->key;
                apply_relation_row(candidate, row);
                global_->mode_acs.source_feed_relation_config.validate(*candidate, relation->key);
                apply_relation_row(relation, row);
                Source_Feed_Relation_Config::set_need_refresh();
                save_source_feed_relations(global_);
                return adminive::make_http_success<Json>(adminive::to_frontend_json<Json>(relation_row(relation)), result.message);
            });
        };
        app.registerHandler(relations_path + "/{1:id}", update, put);
        app.registerHandler(relations_path + "/{1:id}", update, patch);
        app.registerHandler(relations_path + "/{1:id}", [this](const drogon::HttpRequestPtr&, std::function<void(const drogon::HttpResponsePtr&)>&& callback, std::uint64_t id) {
            complete_business_request(callback, [this, id] {
                std::lock_guard lock(topology_mutex_);
                const auto list = global_->mode_acs.source_feed_relation_config.map.list();
                item_by_id(list, id);
                if(!global_->mode_acs.source_feed_relation_config.map.remove(id - 1))
                    throw std::out_of_range("record not found");
                Source_Feed_Relation_Config::set_need_refresh();
                save_source_feed_relations(global_);
                return adminive::make_http_success<Json>(adminive::json_object<Json>(), "deleted");
            });
        }, remove);
        app.registerHandler(relations_path + "/order", [this](const drogon::HttpRequestPtr& request, std::function<void(const drogon::HttpResponsePtr&)>&& callback) {
            complete_business_request(callback, [this, body = std::string(request->getBody())] {
                std::lock_guard lock(topology_mutex_);
                const auto list = global_->mode_acs.source_feed_relation_config.map.list();
                const auto keys = ordered_keys(list, read_order_ids(body));
                if(!global_->mode_acs.source_feed_relation_config.map.set_order(keys))
                    throw std::invalid_argument("invalid order");
                Source_Feed_Relation_Config::set_need_refresh();
                save_source_feed_relations(global_);
                return adminive::make_http_success<Json>(adminive::json_object<Json>(), "reordered");
            });
        }, post);
    }
    Json manifest() const {
        const auto view = adminive::composition_view("ecap_config", adminive::compose::frontend(adminive::compose::slot("mode_acs"), adminive::compose::slot("data_feed_settings"), adminive::compose::slot("data_sources"), adminive::compose::slot("data_feeds"), adminive::compose::slot("source_feed_relations"), adminive::compose::slot("mlat"), adminive::compose::slot("map_view"), adminive::compose::slot("cesium_graphics"), adminive::compose::slot("external_resources"), adminive::compose::slot("archive_operations"), adminive::compose::slot("cesium_models"), adminive::compose::slot("backend_config"), adminive::compose::slot("system_actions"))).titled("ECAP 配置");
        const std::vector<adminive::Composition_Slot_Contract> contracts = {
            {"mode_acs", "amis_schema", mode_acs_path + "/descriptor", mode_acs_path + "/view", mode_acs_path + "/data", mode_acs_path + "/amis"},
            {"data_feed_settings", "amis_schema", data_feed_settings_path + "/descriptor", data_feed_settings_path + "/view", data_feed_settings_path + "/data", data_feed_settings_path + "/amis"},
            {"data_sources", "amis_schema", data_sources_path + "/descriptor", data_sources_path + "/view", data_sources_path, data_sources_path + "/amis"},
            {"data_feeds", "amis_schema", data_feeds_path + "/descriptor", data_feeds_path + "/view", data_feeds_path, data_feeds_path + "/amis"},
            {"source_feed_relations", "amis_schema", relations_path + "/descriptor", relations_path + "/view", relations_path, relations_path + "/amis"},
            {"mlat", "amis_schema", mlat_path + "/descriptor", mlat_path + "/view", mlat_path + "/data", mlat_path + "/amis"},
            {"map_view", "amis_schema", map_view_path + "/descriptor", map_view_path + "/view", map_view_path + "/data", map_view_path + "/amis"},
            {"cesium_graphics", "amis_schema", cesium_graphics_path + "/descriptor", cesium_graphics_path + "/view", cesium_graphics_path + "/data", cesium_graphics_path + "/amis"},
            {"external_resources", "amis_schema", external_resources_path + "/descriptor", external_resources_path + "/view", external_resources_path, external_resources_path + "/amis"},
            {"archive_operations", "ecap_archive_operations", {}, {}, {}, {}},
            {"cesium_models", "ecap_cesium_models", {}, {}, "/map/models", {}},
            {"backend_config", "ecap_backend_config", {}, {}, backend_config_path, {}},
            {"system_actions", "amis_schema", {}, {}, {}, {}}
        };
        const std::map<std::string, Json> schemas = {
            {"mode_acs", mode_acs_resource_.amis_schema()},
            {"data_feed_settings", data_feed_settings_resource_.amis_schema()},
            {"data_sources", source_amis_schema()},
            {"data_feeds", feed_amis_schema()},
            {"source_feed_relations", relation_amis_schema()},
            {"mlat", mlat_resource_.amis_schema()},
            {"map_view", map_view_resource_.amis_schema()},
            {"cesium_graphics", cesium_graphics_resource_.amis_schema()},
            {"external_resources", external_resource_amis_schema()},
            {"archive_operations", archive_operations_schema()},
            {"cesium_models", cesium_models_schema(global_)},
            {"backend_config", backend_config_schema()},
            {"system_actions", system_actions_schema()}
        };
        return adminive::to_composition_manifest_json<Json>(view, contracts, schemas);
    }
    static inline const std::string mode_acs_path = "/api/adminive/config/mode_acs";
    static inline const std::string data_feed_settings_path = "/api/adminive/config/data_feed_settings";
    static inline const std::string map_view_path = "/api/adminive/config/map_view";
    static inline const std::string data_sources_path = "/api/adminive/config/data_sources";
    static inline const std::string data_feeds_path = "/api/adminive/config/data_feeds";
    static inline const std::string relations_path = "/api/adminive/config/source_feed_relations";
    static inline const std::string external_resources_path = "/api/adminive/config/external_resources";
    static inline const std::string backend_config_path = "/api/adminive/config/backend_config";
    static inline const std::string mlat_path = "/api/adminive/config/mlat";
    static inline const std::string cesium_graphics_path = "/api/adminive/config/cesium_graphics";
    static inline const std::string manifest_path = "/api/adminive/config/manifest";
    Global* global_;
    std::mutex topology_mutex_;
    adminive::Drogon_Resource<Mode_ACS_Config_Data, Json> mode_acs_resource_;
    adminive::Drogon_Resource<Data_feed_Config_Data, Json> data_feed_settings_resource_;
    adminive::Drogon_Resource<Map_View_Config, Json> map_view_resource_;
    adminive::Drogon_Resource<MLAT_Config_Data, Json> mlat_resource_;
    adminive::Drogon_Resource<Cesium_Graphics_Config_Data, Json> cesium_graphics_resource_;
};
}
void register_adminive_config(Global* global) {
    static auto resources = std::make_unique<Adminive_Config_Resources>(global);
    resources->bind();
}
}
