#include "Gallery_Protocol.h"
#include "Gallery_Enum.h"
#include "Gallery_Observer_Adminive.h"
#include "Gallery_Renderables.h"
#include "Gallery_Session_Control_Adminive.h"

#include "adminive/adminive.hpp"
#include "adminive/adapters/nlohmann_json.hpp"

#include <algorithm>
#include <array>
#include <cctype>
#include <cmath>
#include <limits>
#include <stdexcept>
#include <tuple>
#include <type_traits>
#include <utility>
#include <vector>

namespace renderive::web::gallery_detail {

using Json = nlohmann::json;

struct Case_Model {
    std::string id;
    std::string title;
    std::string component;
    std::string category;
    std::string description;
    int order{};
    int preferred_width = 560;
    int preferred_height = 320;
};

using Action_Model = Gallery_Action_Model;

const std::vector<Case_Model>& cases() {
    static const std::vector<Case_Model> value{
        {"axis_lab", "坐标轴实验室", "Axis / Frequency_Axis / Time_Axis", "基础控件",
         "普通轴、频率轴和时间轴的布局、格式化、滚轮与拖拽 API。", 10},
        {"spectrum", "实时频谱", "Spectrum", "三种频率图",
         "频率控制模式 1：曲线、保持线、扫频区、峰值和自定义 Marker。", 20},
        {"afterglow", "余辉频谱", "Afterglow", "三种频率图",
         "频率控制模式 2：二维功率密度、衰减和功率 bin 插值。", 30},
        {"sweep_spectrum", "扫频频谱", "Sweep_Spectrum", "三种频率图",
         "频率控制模式 3：分块扫频、当前频率游标和六种线插值。", 40},
        {"waterfall", "瀑布图", "Waterfall", "热力图控件",
         "逐行时频热力图；Nearest、Bilinear、Bicubic 三种图像模式均可切换。", 50},
        {"frequency_trace", "时间轨迹", "Frequency_Trace", "曲线控件",
         "Time_Axis 驱动的连续轨迹，覆盖时间格式和属性化笔刷 API。", 60},
        {"selection_overlay", "框选叠层", "Selection_Rectangle_Overlay", "交互控件",
         "鼠标框选、多区域保留、标注样式和清空。", 70},
        {"constellation", "星座图", "Constellation_Diagram", "点图控件",
         "PSK4/PSK8/PSK16 模式、相位、寿命、坐标范围和方形拟合。", 80}
    };
    return value;
}

const Case_Model* find_case(std::string_view id) {
    const auto& all = cases();
    const auto found = std::find_if(all.begin(), all.end(),
                                    [id](const Case_Model& item) { return item.id == id; });
    return found == all.end() ? nullptr : &*found;
}

void append_session_actions(Gallery_Frame_Mode frame_mode,
                            std::vector<Action_Model>& result) {
    switch (frame_mode) {
    case Gallery_Frame_Mode::Manual:
        append_gallery_actions<Gallery_Session_Control<Manual_Scene2D>>(result);
        return;
    case Gallery_Frame_Mode::Low_Latency:
        append_gallery_actions<Gallery_Session_Control<Scene2D>>(result);
        return;
    case Gallery_Frame_Mode::Playback:
        append_gallery_actions<Gallery_Session_Control<Playback_Scene2D>>(result);
        return;
    }
    throw std::invalid_argument("unknown gallery frame mode");
}
std::size_t session_control_count(Gallery_Frame_Mode frame_mode) {
    switch (frame_mode) {
    case Gallery_Frame_Mode::Manual:
        return gallery_control_count<Gallery_Session_Control<Manual_Scene2D>>();
    case Gallery_Frame_Mode::Low_Latency:
        return gallery_control_count<Gallery_Session_Control<Scene2D>>();
    case Gallery_Frame_Mode::Playback:
        return gallery_control_count<Gallery_Session_Control<Playback_Scene2D>>();
    }
    throw std::invalid_argument("unknown gallery frame mode");
}
std::vector<Action_Model> registered_actions(std::string_view case_id,
                                             Gallery_Frame_Mode frame_mode) {
    std::vector<Action_Model> result;
    append_session_actions(frame_mode, result);
    for (auto& action : gallery_frame_actions(frame_mode))
        result.push_back(std::move(action));
    append_gallery_renderable_actions(case_id, result);
    return result;
}

Json parse_request(std::string_view message) {
    return Json::parse(message.begin(), message.end());
}
adminive::Table_View action_view();

} // namespace renderive::web::gallery_detail

namespace adminive {

template <>
struct Type_Descriptor<renderive::web::gallery_detail::Case_Model> {
    static auto get() {
        using T = renderive::web::gallery_detail::Case_Model;
        return object<T>("renderive_gallery_case",
                         ADMINIVE_FIELD_LABEL(T, id, "标识"),
                         ADMINIVE_FIELD_LABEL(T, title, "标题"),
                         ADMINIVE_FIELD_LABEL(T, component, "Core2 控件"),
                         ADMINIVE_FIELD_LABEL(T, category, "分类"),
                         ADMINIVE_FIELD_LABEL(T, description, "说明"),
                         ADMINIVE_FIELD_LABEL(T, order, "顺序"),
                         ADMINIVE_FIELD_LABEL(T, preferred_width, "建议宽度"),
                         ADMINIVE_FIELD_LABEL(T, preferred_height, "建议高度"))
            .label("Renderive 控件用例");
    }
};

template <>
struct Type_Descriptor<renderive::web::gallery_detail::Action_Model> {
    static auto get() {
        using T = renderive::web::gallery_detail::Action_Model;
        return object<T>("renderive_gallery_action",
                         ADMINIVE_FIELD_LABEL(T, id, "动作"),
                         ADMINIVE_FIELD_LABEL(T, label, "名称"),
                         ADMINIVE_FIELD_LABEL(T, api, "Core2 API"),
                         ADMINIVE_FIELD_LABEL(T, description, "说明"),
                         ADMINIVE_FIELD_LABEL(T, group, "分组"),
                         ADMINIVE_FIELD_LABEL(T, argument_input, "参数类型"),
                         ADMINIVE_FIELD_LABEL(T, argument_label, "参数名称"),
                         ADMINIVE_FIELD_LABEL(T, argument_default, "参数默认值"),
                         ADMINIVE_FIELD_LABEL(T, request_frame, "执行后请求像素帧"))
            .label("后端动作菜单");
    }
};

} // namespace adminive

namespace renderive::web::gallery_detail {

adminive::Table_View action_view() {
    using T = Action_Model;
    return adminive::table_view<T>(
               adminive::column<&T::label>("动作"),
               adminive::column<&T::group>("分组"),
               adminive::column<&T::api>("Core2 API"))
        .titled("保留 API 动作");
}

} // namespace renderive::web::gallery_detail

namespace renderive::web {
namespace {

using gallery_detail::Json;

Json protocol_base() {
    return {{"category", "gallery"},
            {"protocol", "renderive.control-gallery"},
            {"protocol_version", 4}};
}

Json case_contract(std::string_view case_id) {
    const auto* item = gallery_detail::find_case(case_id);
    return item ? adminive::to_frontend_json<Json>(*item) : Json::object();
}

Json dashboard_field(std::string_view label, std::string_view source,
                     std::string_view format = "integer", int digits = -1) {
    Json result{{"label", label}, {"source", source}, {"format", format}};
    if (digits >= 0)
        result["digits"] = digits;
    return result;
}

template <class Object>
const Json& described_field(std::string_view name) {
    static const Json descriptor = adminive::to_descriptor_json<Json, Object>();
    const auto& fields = descriptor.at("fields");
    const auto found = std::find_if(fields.begin(), fields.end(), [name](const Json& field) {
        return field.at("name").template get<std::string>() == name;
    });
    if (found == fields.end())
        throw std::logic_error("missing Adminive dashboard field: " + std::string(name));
    return *found;
}

template <class Object>
std::string described_source(std::string_view prefix, std::string_view name) {
    static_cast<void>(described_field<Object>(name));
    return std::string(prefix) + "." + std::string(name);
}

template <class Object>
Json described_dashboard_field(std::string_view prefix, std::string_view name) {
    const Json& field = described_field<Object>(name);
    const std::string value_type = field.at("value_type");
    std::string format = "integer";
    if (name.ends_with("_ns"))
        format = "nanoseconds";
    else if (name.ends_with("_fps"))
        format = "fps";
    else if (name.ends_with("frequency_hz"))
        format = "frequency";
    else if (name == "source")
        format = "flags";
    else if (value_type == "boolean" || name == "limit_state")
        format = "enum";
    else if (value_type == "string" || value_type == "enum")
        format = "text";
    Json result = dashboard_field(
        field.at("presentation").at("label").template get<std::string>(),
        described_source<Object>(prefix, name), format,
        name.ends_with("_fps") ? 2 : -1);
    if (value_type == "boolean")
        result["value_map"] = "enabled";
    else if (name == "limit_state")
        result["value_map"] = "limit_state";
    else if (name == "source")
        result["value_map"] = "consumer_feedback_source";
    return result;
}

bool observer_header_field(std::string_view name) {
    return name == "mode" || name == "last_event" || name == "limit_state";
}

bool observer_counter_field(std::string_view name) {
    return name == "frequency_hz" || name == "latest_sequence" ||
           name.ends_with("_count");
}

bool observer_detail_field(std::string_view name) {
    return name.ends_with("_wait_ns") || name == "frame_age_at_render_ns";
}

template <class Predicate>
Json observer_fields(Predicate&& predicate) {
    const Json descriptor =
        adminive::to_descriptor_json<Json, renderive::Frame_Observer_Snapshot>();
    Json result = Json::array();
    for (const Json& field : descriptor.at("fields")) {
        const std::string name = field.at("name");
        if (predicate(name)) {
            Json field = described_dashboard_field<renderive::Frame_Observer_Snapshot>(
                "kernel_observer", name);
            if (name == "frequency_hz") {
                field["enabled_source"] =
                    described_source<renderive::Frame_Observer_Snapshot>(
                        "kernel_observer", "frequency_limit_enabled");
                field["disabled_label"] = "已关闭";
            } else if (name == "end_to_end_ns") {
                field["cell_class"] = "critical";
            }
            result.push_back(std::move(field));
        }
    }
    return result;
}

Json consumer_feedback_fields() {
    const Json descriptor =
        adminive::to_descriptor_json<Json, Gallery_Consumer_Feedback_Snapshot>();
    Json result = Json::array();
    for (const Json& field : descriptor.at("fields")) {
        const std::string name = field.at("name");
        result.push_back(described_dashboard_field<Gallery_Consumer_Feedback_Snapshot>(
            "consumer_feedback", name));
    }
    return result;
}

Json observer_summary_fields() {
    Json result = observer_fields([](std::string_view name) {
        return !observer_header_field(name) && !observer_counter_field(name) &&
               !observer_detail_field(name);
    });
    for (Json& field : consumer_feedback_fields())
        result.push_back(std::move(field));
    return result;
}

Json dashboard_contract() {
    Json point_pair{{"label", "输入→绘制"}, {"format", "pair"},
                    {"sources", Json::array({"data_shape.input_points", "data_shape.rendered_elements"})},
                    {"separator", "→"}};
    Json bottleneck = described_dashboard_field<renderive::Frame_Observer_Snapshot>(
        "kernel_observer", "limit_state");
    bottleneck["format"] = "duration_enum";
    bottleneck["duration_sources"] = {
        {"frequency_limited", described_source<renderive::Frame_Observer_Snapshot>(
                                  "kernel_observer", "target_interval_ns")},
        {"paint_limited", described_source<renderive::Frame_Observer_Snapshot>(
                              "kernel_observer", "paint_duration_ns")},
        {"render_limited", described_source<renderive::Frame_Observer_Snapshot>(
                               "kernel_observer", "render_duration_ns")},
        {"consumer_limited", described_source<renderive::Frame_Observer_Snapshot>(
                                 "kernel_observer", "consumer_interval_ns")}
    };
    Json dashboard{
        {"value_maps", {
            {"enabled", {{"true", "启用"}, {"false", "关闭"}}},
            {"consumer_feedback_source", {
                {"disabled", "总开关关闭"}, {"none", "无"}, {"pixel", "像素响应"},
                {"presentation", "浏览器呈现"}, {"manual", "手动"}
            }},
            {"limit_state", {
                {"frequency_limited", "内核频率受限"}, {"paint_limited", "绘制事件受限"},
                {"render_limited", "后台渲染受限"}, {"consumer_limited", "消费者反馈受限"},
                {"unlimited", "无限制"}, {"not_applicable", "N/A"}
            }}
        }},
        {"performance", {
            {"fields", Json::array({
                dashboard_field("后端渲染 FPS", "performance.measured_fps", "fixed", 1),
                dashboard_field("像素响应 FPS", "performance.pixel_response_fps", "fixed", 1),
                dashboard_field("浏览器呈现 FPS", "client_performance.presentation_fps", "fixed", 1),
                dashboard_field("WS 往返 ms", "client_performance.frame_round_trip_ms", "fixed", 2),
                dashboard_field("未呈现覆盖", "client_performance.overwritten_pixel_frames"),
                dashboard_field("Core 渲染 ms", "performance.last_render_ms", "fixed", 2),
                dashboard_field("Core 滑动平均 ms", "performance.average_render_ms", "fixed", 2),
                dashboard_field("Core P95 ms", "performance.render_p95_ms", "fixed", 2),
                dashboard_field("Core P99 ms", "performance.render_p99_ms", "fixed", 2),
                dashboard_field("像素编码 ms", "performance.last_pixel_encode_ms", "fixed", 2),
                dashboard_field("编码 P95 ms", "performance.pixel_encode_p95_ms", "fixed", 2),
                dashboard_field("编码 P99 ms", "performance.pixel_encode_p99_ms", "fixed", 2),
                dashboard_field("WS 平均 ms", "client_performance.frame_round_trip_average_ms", "fixed", 2),
                dashboard_field("WS P95 ms", "client_performance.frame_round_trip_p95_ms", "fixed", 2),
                dashboard_field("WS P99 ms", "client_performance.frame_round_trip_p99_ms", "fixed", 2),
                dashboard_field("呈现平均 ms", "client_performance.display_interval_average_ms", "fixed", 2),
                dashboard_field("呈现 P95 ms", "client_performance.display_interval_p95_ms", "fixed", 2),
                dashboard_field("呈现 P99 ms", "client_performance.display_interval_p99_ms", "fixed", 2),
                dashboard_field("响应负载 MB/s", "performance.pixel_payload_megabytes_per_second", "fixed", 1),
                described_dashboard_field<renderive::Frame_Observer_Snapshot>(
                    "kernel_observer", "pending_frame_count"),
                described_dashboard_field<renderive::Frame_Observer_Snapshot>(
                    "kernel_observer", "dropped_frame_count"),
                std::move(point_pair), std::move(bottleneck),
                described_dashboard_field<renderive::Frame_Observer_Snapshot>(
                    "kernel_observer", "last_event"),
                dashboard_field("像素超时", "client_performance.frame_request_timeout_count"),
                dashboard_field("最近像素龄", "client_performance.last_pixel_receive_age_ms", "milliseconds", 0)
            })}
        }},
        {"menu_views", {
            {"observer", {
                {"kernel", {
                    {"title", "内核帧观察器"},
                    {"source", "kernel_observer"},
                    {"descriptor", adminive::to_descriptor_json<
                        Json, renderive::Frame_Observer_Snapshot>()}
                }},
                {"renderables_source", "renderable_observers"},
                {"renderable_fields", Json::array({
                    "event", "event_time_ns", "cache_update_count", "publish_count"
                })}
            }},
            {"performance", {
                {"renderables_source", "renderable_observers"},
                {"renderable_fields", Json::array({
                    "event", "event_time_ns", "cache_update_count", "publish_count"
                })},
                {"resources", Json::array({
                    {
                        {"title", "渲染性能"},
                        {"source", "performance"},
                        {"descriptor", adminive::to_descriptor_json<
                            Json, Gallery_Render_Performance>()}
                    },
                    {
                        {"title", "浏览器性能"},
                        {"source", "client_performance"},
                        {"descriptor", adminive::to_descriptor_json<
                            Json, Gallery_Client_Performance>()}
                    }
                })}
            }}
        }},
        {"limits", {
            {"aria_label", "低延迟限速来源"}, {"title", "限速来源"},
            {"current_source", described_source<renderive::Frame_Observer_Snapshot>(
                                   "kernel_observer", "limit_state")},
            {"active_label", "当前瓶颈"}, {"inactive_label", "未受限"},
            {"disabled_label", "已关闭"},
            {"fields", Json::array({
                {{"label", "内核用户频率"}, {"active_value", "frequency_limited"},
                 {"duration_source", described_source<renderive::Frame_Observer_Snapshot>(
                                         "kernel_observer", "target_interval_ns")},
                 {"enabled_source", described_source<renderive::Frame_Observer_Snapshot>(
                                        "kernel_observer", "frequency_limit_enabled")}},
                {{"label", "内核绘制事件"}, {"active_value", "paint_limited"},
                 {"duration_source", described_source<renderive::Frame_Observer_Snapshot>(
                                         "kernel_observer", "paint_duration_ns")}},
                {{"label", "内核后台渲染"}, {"active_value", "render_limited"},
                 {"duration_source", described_source<renderive::Frame_Observer_Snapshot>(
                                         "kernel_observer", "render_duration_ns")}},
                {{"label", "消费者反馈"}, {"active_value", "consumer_limited"},
                 {"duration_source", described_source<renderive::Frame_Observer_Snapshot>(
                                         "kernel_observer", "consumer_interval_ns")},
                 {"enabled_source", described_source<renderive::Frame_Observer_Snapshot>(
                                        "kernel_observer", "consumer_feedback_enabled")}}
            })}
        }},
        {"observer", {
            {"aria_label", "内核低延迟全量统计"},
            {"header", {
                {"prefix", "内核"}, {"suffix", "观察器"}, {"event_label", "事件"},
                {"mode", described_dashboard_field<renderive::Frame_Observer_Snapshot>(
                             "kernel_observer", "mode")},
                {"limit", described_dashboard_field<renderive::Frame_Observer_Snapshot>(
                              "kernel_observer", "limit_state")},
                {"event", described_dashboard_field<renderive::Frame_Observer_Snapshot>(
                              "kernel_observer", "last_event")}
            }},
            {"sections", Json::array({
                {{"class_name", "observer-counters"},
                 {"fields", observer_fields(observer_counter_field)}},
                {{"class_name", "latency-summary"},
                 {"fields", observer_summary_fields()}},
                {{"class_name", "client-summary"}, {"aria_label", "浏览器消费者反馈全量统计"},
                 {"fields", Json::array({
                    dashboard_field("RAF 最新周期", "client_performance.display_interval_latest_ms", "milliseconds", 3),
                    dashboard_field("RAF 中位周期", "client_performance.display_interval_ms", "milliseconds", 3),
                    dashboard_field("RAF 平均周期", "client_performance.display_interval_average_ms", "milliseconds", 3),
                    dashboard_field("RAF P95 周期", "client_performance.display_interval_p95_ms", "milliseconds", 3),
                    dashboard_field("RAF P99 周期", "client_performance.display_interval_p99_ms", "milliseconds", 3),
                    dashboard_field("RAF 周期标准差", "client_performance.display_interval_deviation_ms", "milliseconds", 3),
                    dashboard_field("WS 往返", "client_performance.frame_round_trip_ms", "milliseconds", 3),
                    dashboard_field("WS 往返平均", "client_performance.frame_round_trip_average_ms", "milliseconds", 3),
                    dashboard_field("WS 往返 P95", "client_performance.frame_round_trip_p95_ms", "milliseconds", 3),
                    dashboard_field("WS 往返 P99", "client_performance.frame_round_trip_p99_ms", "milliseconds", 3),
                    dashboard_field("WS 往返标准差", "client_performance.frame_round_trip_deviation_ms", "milliseconds", 3),
                    dashboard_field("像素响应 FPS", "client_performance.transport_fps", "fps", 2),
                    dashboard_field("浏览器呈现 FPS", "client_performance.presentation_fps", "fps", 2),
                    dashboard_field("WS 缓冲", "client_performance.websocket_buffered_bytes", "bytes"),
                    dashboard_field("未呈现覆盖", "client_performance.overwritten_pixel_frames"),
                    dashboard_field("变化像素帧", "client_performance.changed_pixel_frames"),
                    dashboard_field("重复像素帧", "client_performance.duplicate_pixel_frames"),
                    dashboard_field("像素请求超时", "client_performance.frame_request_timeout_count"),
                    dashboard_field("最近像素龄", "client_performance.last_pixel_receive_age_ms", "milliseconds", 3),
                    dashboard_field("最近变化龄", "client_performance.last_pixel_change_age_ms", "milliseconds", 3)
                })}},
                {{"class_name", "latency-details"}, {"aria_label", "内核各阶段等待耗时"},
                 {"fields", observer_fields(observer_detail_field)}}
            })}
        }}
    };
    dashboard["observer"]["descriptor"] =
        adminive::to_descriptor_json<Json, renderive::Frame_Observer_Snapshot>();
    dashboard["observer"]["consumer_feedback_descriptor"] =
        adminive::to_descriptor_json<Json, Gallery_Consumer_Feedback_Snapshot>();
    return dashboard;
}

Json frame_mode_contract(Gallery_Frame_Mode mode) {
    switch (mode) {
    case Gallery_Frame_Mode::Manual:
        return {{"id", gallery_enum_id(mode)}, {"title", "手动刷新"},
                {"strategy", "Manual_Refresh_Strategy"},
                {"description", "显式准备、刷新和渲染；页面不会自动拉取像素。"},
                {"automatic", false}, {"request_after_response", false},
                {"request_on_animation_frame", false}, {"observer_visible", false},
                {"frame_button_label", "手动刷新一帧"}, {"accent", "#ffd166aa"}, {"order", 10}};
    case Gallery_Frame_Mode::Low_Latency:
        return {{"id", gallery_enum_id(mode)}, {"title", "低延迟"},
                {"strategy", "Low_Latency_Strategy"},
                {"description", "以最大 FPS 自动发布并消费最新帧，可观测丢帧与端到端延迟。"},
                {"automatic", true}, {"request_after_response", true},
                {"request_on_animation_frame", false}, {"observer_visible", true},
                {"frame_button_label", "立即刷新"}, {"accent", "#45ddbeaa"}, {"order", 20}};
    case Gallery_Frame_Mode::Playback:
        return {{"id", gallery_enum_id(mode)}, {"title", "回放队列"},
                {"strategy", "Flow_Refresh_Strategy"},
                {"description", "所有帧按队列顺序入队和消费，可观测队深与排队时间。"},
                {"automatic", true}, {"request_after_response", true},
                {"request_on_animation_frame", true}, {"observer_visible", false},
                {"frame_button_label", "消费下一帧"}, {"accent", "#6aa9ffaa"}, {"order", 30}};
    }
    return Json::object();
}

} // namespace

std::string Gallery_Protocol::catalog_json() {
    Json result = protocol_base();
    result["type"] = "catalog";
    result["transport"] = {{"events", "websocket-text"}, {"pixels", "websocket-binary-rvp1"},
                           {"http_api", false}, {"socket_per_canvas", true}};
    result["navigation"] = {
        {"default_mode", gallery_enum_id(Gallery_Frame_Mode::Low_Latency)},
        {"all_categories_label", "全部"},
        {"catalog_loaded_text", "Kernel 策略目录已加载"},
        {"hero_eyebrow", "REAL KERNEL STRATEGIES"},
        {"hero_title", "对称策略页面，同一批控件，直接比较"}
    };
    result["dashboard"] = dashboard_contract();
    result["case_descriptor"] =
        adminive::to_descriptor_json<Json, gallery_detail::Case_Model>();
    result["frame_modes"] = Json::array();
    constexpr auto frame_modes = magic_enum::enum_values<Gallery_Frame_Mode>();
    for (const auto mode : frame_modes)
        result["frame_modes"].push_back(frame_mode_contract(mode));
    result["cases"] = Json::array();
    std::size_t controls_total{};
    std::size_t actions_total{};
    for (const auto& item : gallery_detail::cases()) {
        Json entry = adminive::to_frontend_json<Json>(item);
        entry["control_count_by_mode"] = Json::object();
        entry["action_count_by_mode"] = Json::object();
        const std::size_t renderable_controls = gallery_renderable_control_count(item.id);
        for (const auto mode : frame_modes) {
            const std::string key = gallery_enum_id(mode);
            const std::size_t controls =
                gallery_detail::session_control_count(mode) + renderable_controls;
            const std::size_t actions =
                gallery_detail::registered_actions(item.id, mode).size();
            entry["control_count_by_mode"][key] = controls;
            entry["action_count_by_mode"][key] = actions;
            controls_total += controls;
            actions_total += actions;
        }
        entry["control_count"] =
            gallery_detail::session_control_count(Gallery_Frame_Mode::Low_Latency) +
            renderable_controls;
        entry["action_count"] =
            gallery_detail::registered_actions(
                item.id, Gallery_Frame_Mode::Low_Latency).size();
        result["cases"].push_back(std::move(entry));
    }
    result["coverage"] = {{"case_count", gallery_detail::cases().size()},
                          {"page_count", std::size(frame_modes)},
                          {"canvas_count", gallery_detail::cases().size() * std::size(frame_modes)},
                          {"manual_control_count", controls_total},
                          {"manual_action_count", actions_total},
                          {"frequency_modes", Json::array({"spectrum", "afterglow", "sweep_spectrum"})},
                          {"image_interpolation_modes", magic_enum::enum_names<Image_Interpolation_Mode>()}};
    return result.dump();
}

bool Gallery_Protocol::is_case(std::string_view case_id) {
    return gallery_detail::find_case(case_id) != nullptr;
}

std::string Gallery_Protocol::case_json_from_controls(
    std::string_view case_id,
    std::string_view controls_json,
    std::string_view telemetry_json,
    std::string_view notice,
    Gallery_Frame_Mode frame_mode,
    bool manual_refresh) {
    Json result = protocol_base();
    result["type"] = manual_refresh ? "refresh_state" : "case_state";
    result["case"] = case_contract(case_id);
    result["frame_mode"] = frame_mode_contract(frame_mode);
    try {
        result["controls"] = Json::parse(controls_json.begin(), controls_json.end());
    } catch (const std::exception&) {
        result["controls"] = {
            {"resources", Json::array()},
            {"observers", Json::array()},
            {"render_plan", Json::object()}
        };
    }
    result["actions"] = {
        {"descriptor", adminive::to_descriptor_json<Json, gallery_detail::Action_Model>()},
        {"view", adminive::to_view_json<Json, gallery_detail::Action_Model>(
                     gallery_detail::action_view())},
        {"data", Json::array()}
    };
    for (const auto& action : gallery_detail::registered_actions(case_id, frame_mode))
        result["actions"]["data"].push_back(
            adminive::to_frontend_json<Json>(action));
    try {
        result["telemetry"] = Json::parse(telemetry_json.begin(), telemetry_json.end());
    } catch (const std::exception&) {
        result["telemetry"] = Json::object();
    }
    if (!notice.empty())
        result["notice"] = notice;
    return result.dump();
}

std::string Gallery_Protocol::error_json(std::string_view message,
                                         std::string_view field) {
    Json result = protocol_base();
    result["type"] = "error";
    result["message"] = message;
    result["field_errors"] = Json::object();
    if (!field.empty())
        result["field_errors"][std::string(field)] = message;
    return result.dump();
}

std::string Gallery_Protocol::observer_json(std::string_view case_id,
                                            Gallery_Frame_Mode frame_mode,
                                            std::string_view telemetry_json) {
    Json result = protocol_base();
    result["type"] = "observer_state";
    result["case_id"] = case_id;
    result["frame_mode"] = frame_mode_contract(frame_mode);
    try {
        result["telemetry"] = Json::parse(telemetry_json.begin(), telemetry_json.end());
    } catch (const std::exception&) {
        result["telemetry"] = Json::object();
    }
    return result.dump();
}

std::optional<Gallery_Open_Request> Gallery_Protocol::open_request(std::string_view message) {
    try {
        const Json request = gallery_detail::parse_request(message);
        if (!request.is_object() || request.value("category", "") != "event" ||
            request.value("type", "") != "gallery_open" ||
            !request.contains("case") || !request.at("case").is_string())
            return std::nullopt;
        const std::string value = request.at("case").get<std::string>();
        if (!is_case(value) || !request.contains("frame_mode") ||
            !request.at("frame_mode").is_string())
            return std::nullopt;
        const auto mode = gallery_enum_cast<Gallery_Frame_Mode>(
            request.at("frame_mode").get<std::string>());
        return mode ? std::optional<Gallery_Open_Request>(Gallery_Open_Request{value, *mode})
                    : std::nullopt;
    } catch (const std::exception&) {
        return std::nullopt;
    }
}

std::optional<Gallery_Action_Request> Gallery_Protocol::action_request(
    std::string_view message) {
    try {
        const Json request = gallery_detail::parse_request(message);
        if (!request.is_object() || request.value("category", "") != "event" ||
            request.value("type", "") != "gallery_action" ||
            !request.contains("action") || !request.at("action").is_string())
            return std::nullopt;
        Gallery_Action_Request result{request.at("action").get<std::string>()};
        if (request.contains("argument")) {
            const Json& argument = request.at("argument");
            if (argument.is_boolean())
                result.argument = argument.get<bool>();
            else if (argument.is_number()) {
                const double value = argument.get<double>();
                if (!std::isfinite(value))
                    return std::nullopt;
                result.argument = value;
            } else if (argument.is_string())
                result.argument = argument.get<std::string>();
            else
                return std::nullopt;
        }
        return result;
    } catch (const std::exception&) {
        return std::nullopt;
    }
}

std::optional<Gallery_Control_Patch_Request> Gallery_Protocol::control_patch_request(
    std::string_view message) {
    try {
        const Json request = gallery_detail::parse_request(message);
        if (!request.is_object() || request.value("category", "") != "event" ||
            request.value("type", "") != "gallery_patch" ||
            !request.contains("target") || !request.at("target").is_string() ||
            !request.contains("patch") || !request.at("patch").is_object())
            return std::nullopt;
        return Gallery_Control_Patch_Request{
            request.at("target").get<std::string>(), request.at("patch").dump()};
    } catch (const std::exception&) {
        return std::nullopt;
    }
}

bool Gallery_Protocol::action_available(std::string_view case_id,
                                        Gallery_Frame_Mode frame_mode,
                                        std::string_view action_id) {
    const auto available = gallery_detail::registered_actions(case_id, frame_mode);
    return std::any_of(available.begin(), available.end(),
                       [action_id](const gallery_detail::Action_Model& item) {
                           return item.id == action_id;
                       });
}

} // namespace renderive::web
