#include "Gallery_Plot_Session.h"
#include "Gallery_Controls.h"
#include "Gallery_Enum.h"
#include "Gallery_Observer_Adminive.h"
#include "Gallery_Protocol.h"
#include "Gallery_Session_Control_Adminive.h"
#include "Pixel_Frame.h"
#include "Web_Performance_Log.h"
#include "render_2D/export.h"
#include <renderive/base/statistics/Rolling_Statistics.hpp>
#include <nlohmann/json.hpp>
#include <algorithm>
#include <array>
#include <atomic>
#include <chrono>
#include <cmath>
#include <condition_variable>
#include <cstdint>
#include <deque>
#include <limits>
#include <mutex>
#include <numbers>
#include <random>
#include <string>
#include <thread>
#include <type_traits>
#include <utility>
#include <vector>
namespace renderive::web {
namespace {
template <class Update>
void update_axis_state(const renderive_Owner<Abs_Axis>& axis, Update&& update) {
    if (const auto numeric = renderive_dynamic_owner_cast<Axis>(axis)) {
        numeric->update([&](Axis_Properties& state) {
            std::forward<Update>(update)(static_cast<Axis_Base_Properties&>(state));
        });
    } else if (const auto time = renderive_dynamic_owner_cast<Time_Axis>(axis)) {
        time->update([&](auto& state) {
            std::forward<Update>(update)(static_cast<Axis_Base_Properties&>(state));
        });
    }
}

std::uint64_t milliseconds_to_ns(double milliseconds) {
    return milliseconds > 0.0 ? static_cast<std::uint64_t>(std::llround(milliseconds * 1'000'000.0)) : 0;
}
std::uint64_t frequency_to_ns(double frequency_hz) {
    return frequency_hz > 0.0 ? static_cast<std::uint64_t>(std::llround(1'000'000'000.0 / frequency_hz)) : 0;
}
int hex_digit(char value) {
    if (value >= '0' && value <= '9')
        return value - '0';
    if (value >= 'a' && value <= 'f')
        return value - 'a' + 10;
    return value - 'A' + 10;
}
Color color_from_hex(std::string_view value, std::uint8_t alpha = 255) {
    const auto channel = [value](std::size_t offset) {
        return static_cast<std::uint8_t>(hex_digit(value[offset]) * 16 +
            hex_digit(value[offset + 1]));
    };
    return {channel(1), channel(3), channel(5), alpha};
}
Time_Of_Day current_time_of_day() {
    constexpr std::int64_t day_ms = 24LL * 60LL * 60LL * 1000LL;
    const auto now = std::chrono::duration_cast<std::chrono::milliseconds>(
        std::chrono::system_clock::now().time_since_epoch())
    .count();
    return {now % day_ms};
}
double gaussian(double x, double center, double width) {
    const double normalized = (x - center) / width;
    return std::exp(-0.5 * normalized * normalized);
}
std::optional<double> action_number(const Gallery_Action_Request& request) {
    if (!request.argument || !std::holds_alternative<double>(*request.argument))
        return std::nullopt;
    return std::get<double>(*request.argument);
}
} // namespace
class Gallery_Scene_Interface {
public:
    virtual ~Gallery_Scene_Interface() = default;
    [[nodiscard]] virtual const std::string& case_id() const noexcept = 0;
    [[nodiscard]] virtual nlohmann::json controls() const = 0;
    [[nodiscard]] virtual Gallery_Frame_Mode frame_mode() const noexcept = 0;
    virtual void reset_monitoring() = 0;
    [[nodiscard]] virtual bool can_render_automatically() const noexcept = 0;
    [[nodiscard]] virtual std::uint64_t kernel_refresh_interval_ns() const = 0;
    virtual void set_client_metrics(Gallery_Client_Performance metrics) noexcept = 0;
    [[nodiscard]] virtual adminive::Update_Result apply_patch(std::string_view target, const nlohmann::json& patch) = 0;
    virtual void resize(Size size) = 0;
    virtual void dispatch(const Event& event) = 0;
    virtual bool render_latest_frame() = 0;
    [[nodiscard]] virtual std::optional<std::string> encode_latest_pixels() = 0;
    virtual void record_pixel_response(std::chrono::steady_clock::time_point request_started, std::chrono::steady_clock::time_point encode_started, std::chrono::steady_clock::time_point encode_finished, std::size_t pixel_bytes) = 0;
    [[nodiscard]] virtual std::string action(const Gallery_Action_Request& request, bool& recognized) = 0;
    virtual void record_action_notice_if_empty(std::string_view notice) = 0;
    [[nodiscard]] virtual std::string telemetry_json() const = 0;
};
template <class Scene_Type>
class Gallery_Scene final : public Gallery_Scene_Interface {
public:
    Gallery_Scene(std::uint64_t session_id, std::string case_id, Gallery_Frame_Mode frame_mode, bool automatic_low_latency)
        : session_id_(session_id), case_id_(std::move(case_id)), frame_mode_(frame_mode), automatic_low_latency_(automatic_low_latency), performance_started_(std::chrono::steady_clock::now()) {
        plot_.init();
        plot_.set_viewport_size({560, 320});
        root_ = plot_.root_renderable();
        root_->set_object_name("画布根节点");
        {
            auto attach = plot_.attach_builder();
            const auto make_group = [&](std::string name) {
                auto group = detail::make_renderable_group(true);
                group->set_object_name(std::move(name));
                attach.attach(group);
                attach.add_display_parent(group, root_);
                attach.add_dependency_parent(group, root_);
                return group;
            };
            axes_node_ = make_group("坐标轴层");
            data_node_ = make_group("数据绘制层");
            overlay_node_ = make_group("交互覆盖层");
            axes_node_->set_cache_mode(Renderable_Cache_Mode::Local_Pixel);
            build_axes(attach);
            build_primary(attach);
        }
        attach_performance_overlay(plot_);
        apply_layout();
        session_control_ = std::make_unique<Gallery_Session_Control<Scene_Type>>(
            plot_, *primary_, feedback_policy_);
        register_controls();
        set_performance_plot_name(plot_, case_id_ + "/" + gallery_enum_id(frame_mode_));
        if (frame_mode_ == Gallery_Frame_Mode::Low_Latency)
            plot_.set_max_render_fps(30.0);
        plot_.activate_view();
        update_model();
        (void)plot_.render_frame(true);
    }
    ~Gallery_Scene() {
        plot_.deactivate_view();
    }
    Gallery_Scene(const Gallery_Scene&) = delete;
    Gallery_Scene& operator=(const Gallery_Scene&) = delete;
    [[nodiscard]] const std::string& case_id() const noexcept {
        return case_id_;
    }
    [[nodiscard]] nlohmann::json controls() const {
        return {
            {"resources", controls_.resources()},
            {"observers", controls_.observers(plot_)},
            {"render_plan", controls_.render_plan(plot_)},
            {"performance_capture", gallery_performance_capture_json(plot_)}
        };
    }
    [[nodiscard]] Gallery_Frame_Mode frame_mode() const noexcept {
        return frame_mode_;
    }
    void reset_monitoring() {
        performance_started_ = std::chrono::steady_clock::now();
        last_performance_log_ = performance_started_;
        render_attempt_count_ = 0;
        successful_render_count_ = 0;
        last_render_ms_ = 0.0;
        render_duration_statistics_.clear();
        render_history_.clear();
        pixel_frame_count_ = 0;
        last_pixel_snapshot_ms_ = 0.0;
        last_pixel_encode_ms_ = 0.0;
        last_pixel_request_ms_ = 0.0;
        last_pixel_bytes_ = 0;
        pixel_encode_statistics_.clear();
        pixel_request_statistics_.clear();
        pixel_history_.clear();
        client_performance_ = {};
        consumer_pixel_interval_ns_ = 0;
        consumer_presentation_interval_ns_ = 0;
        apply_consumer_feedback();
    }
    [[nodiscard]] bool can_render_automatically() const noexcept {
        return automatic_low_latency_ && frame_mode_ == Gallery_Frame_Mode::Low_Latency &&
        plot_.view_active();
    }
    [[nodiscard]] std::uint64_t kernel_refresh_interval_ns() const {
        return plot_.refresh_feedback_snapshot().next_refresh_interval_ns;
    }
    void set_client_metrics(Gallery_Client_Performance metrics) noexcept {
        const auto finite = [](double value, double maximum = 100000.0) {
            return std::isfinite(value) ? std::clamp(value, 0.0, maximum) : 0.0;
        };
        metrics.transport_fps = finite(metrics.transport_fps);
        metrics.presentation_fps = finite(metrics.presentation_fps);
        metrics.frame_round_trip_ms = finite(metrics.frame_round_trip_ms);
        metrics.frame_round_trip_average_ms = finite(metrics.frame_round_trip_average_ms);
        metrics.frame_round_trip_deviation_ms = finite(metrics.frame_round_trip_deviation_ms);
        metrics.frame_round_trip_p95_ms = finite(metrics.frame_round_trip_p95_ms);
        metrics.frame_round_trip_p99_ms = finite(metrics.frame_round_trip_p99_ms);
        metrics.display_interval_ms = finite(metrics.display_interval_ms);
        metrics.display_interval_average_ms = finite(metrics.display_interval_average_ms);
        metrics.display_interval_latest_ms = finite(metrics.display_interval_latest_ms);
        metrics.display_interval_p95_ms = finite(metrics.display_interval_p95_ms);
        metrics.display_interval_p99_ms = finite(metrics.display_interval_p99_ms);
        metrics.display_interval_deviation_ms = finite(metrics.display_interval_deviation_ms);
        metrics.last_pixel_receive_age_ms = finite(metrics.last_pixel_receive_age_ms);
        metrics.last_pixel_change_age_ms = finite(metrics.last_pixel_change_age_ms);
        client_performance_ = metrics;
        apply_consumer_feedback();
    }
    [[nodiscard]] adminive::Update_Result apply_patch(std::string_view target,
                                                       const nlohmann::json& patch) {
        auto result = controls_.apply(target, patch);
        if (!result.success)
            return result;
        if (target == "scene") {
            apply_consumer_feedback();
            render_history_.clear();
        }
        apply_layout();
        update_model();
        plot_.notify_model_dirty();
        return result;
    }
    void resize(Size size) {
        const Size previous = plot_.viewport_size();
        plot_.set_viewport_size(size);
        apply_layout();
        Resize_Event event;
        event.old_size = previous;
        event.new_size = size;
        plot_.dispatch_event(event);
    }
    void dispatch(const Event& event) {
        if (event.type == Event_Type::Show)
            plot_.activate_view();
        else if (event.type == Event_Type::Hide)
            plot_.deactivate_view();
        plot_.dispatch_event(event);
    }
    bool render_latest_frame() {
        if (!plot_.view_active())
            return false;
        update_model();
        const auto started = std::chrono::steady_clock::now();
        const bool rendered = plot_.render_frame(true);
        record_performance(started, rendered);
        if (rendered)
            rendered_since_last_pixel_ = true;
        return rendered;
    }
    [[nodiscard]] std::optional<std::string> encode_latest_pixels() {
        if (!plot_.view_active())
            return std::nullopt;
        if (!rendered_since_last_pixel_ && !can_render_automatically() &&
            !render_latest_frame())
            return std::nullopt;
        rendered_since_last_pixel_ = false;
        std::string pixels;
        const Color background = plot_.background_color();
        plot_.with_frame([&pixels, background](Image_View image) {
            pixels = encode_pixel_frame(image, background);
        });
        return pixels.empty() ? std::nullopt : std::optional<std::string>(std::move(pixels));
    }
    void record_pixel_response(std::chrono::steady_clock::time_point request_started,
                               std::chrono::steady_clock::time_point encode_started,
                               std::chrono::steady_clock::time_point encode_finished,
                               std::size_t pixel_bytes) {
        record_pixel_performance(request_started, encode_started, encode_finished, pixel_bytes);
    }
    [[nodiscard]] std::string action(const Gallery_Action_Request& request,
                                     bool& recognized) {
        last_action_result_.clear();
        recognized = true;
        if (request.id == "capture_next_frame") {
            const auto state = plot_.capture_state();
            if (state.enabled())
                return "A performance capture session is already active";
            const auto session_id = plot_.capture_next_frame();
            last_action_result_ = "capture session=" + std::to_string(session_id);
            return "Capture next render frame requested";
        }
        if (request.id == "capture_frames") {
            const auto argument = action_number(request);
            if (!argument)
                return invalid_argument(recognized);
            const std::size_t count = static_cast<std::size_t>(
                std::clamp(std::llround(*argument), 1LL, 1000LL));
            const auto state = plot_.capture_state();
            if (state.enabled())
                return "A performance capture session is already active";
            const auto session_id = plot_.capture_frames(count);
            last_action_result_ = "capture session=" + std::to_string(session_id) +
                                  ", frames=" + std::to_string(count);
            return "Consecutive render frame capture requested";
        }
        if (request.id == "mode_prepare" || request.id == "mode_enqueue") {
            update_model();
            const bool prepared = plot_.prepare_frame();
            last_action_result_ = prepared ? "frame prepared" : "prepare rejected";
            return prepared ? "Kernel 帧已准备/入队" : "Kernel 拒绝准备帧";
        }
        if (request.id == "mode_enqueue_burst") {
            const auto argument = action_number(request);
            if (!argument)
                return invalid_argument(recognized);
            const int count = std::clamp(static_cast<int>(std::lround(*argument)), 1, 256);
            int prepared{};
            for (int index = 0; index < count; ++index) {
                update_model();
                prepared += plot_.prepare_frame() ? 1 : 0;
            }
            last_action_result_ = "enqueued=" + std::to_string(prepared);
            return "回放帧已批量压入 Flow 队列";
        }
        if (request.id == "mode_refresh") {
            const bool refreshed = plot_.refresh_manual_frame();
            last_action_result_ = refreshed ? "manual refresh succeeded" : "manual refresh failed";
            return refreshed ? "Manual 待处理帧已提交刷新" : "当前没有可刷新的 Manual 帧";
        }
        if (request.id == "mode_render" || request.id == "mode_dequeue") {
            const auto started = std::chrono::steady_clock::now();
            const bool rendered = plot_.render_prepared_frame();
            record_performance(started, rendered);
            rendered_since_last_pixel_ = rendered;
            last_action_result_ = rendered ? "prepared frame rendered" : "no prepared frame";
            return rendered ? "Kernel 已渲染准备帧" : "当前没有可消费的准备帧";
        }
        if (request.id == "mode_discard") {
            const bool discarded = plot_.discard_pending_frame();
            last_action_result_ = discarded ? "pending frame discarded" : "no pending frame";
            return discarded ? "待处理帧已丢弃" : "当前没有可丢弃帧";
        }
        if (request.id == "mode_cycle") {
            update_model();
            const auto started = std::chrono::steady_clock::now();
            const bool rendered = plot_.render_frame(true);
            record_performance(started, rendered);
            rendered_since_last_pixel_ = rendered;
            last_action_result_ = rendered ? "full frame cycle rendered" : "frame cycle skipped";
            return rendered ? "完整帧控制周期已执行" : "完整帧控制周期未产生图像";
        }
        if (request.id == "read_data_shape") {
            last_action_result_ = "data shape refreshed in observer telemetry";
            return "输入点数、实际绘制点/单元数已刷新到观察者与性能面板";
        }
        if (request.id == "toggle_view") {
            if (plot_.view_active())
                plot_.deactivate_view();
            else
                plot_.activate_view();
            return plot_.view_active() ? "Plot view 已激活" : "Plot view 已停用；可再次执行恢复";
        }
        if (request.id == "axis_probe")
            return "坐标映射、刻度步长、次刻度数与标签结果已刷新到遥测区";
        if (request.id == "append_time" && time_axis_) {
            const int tick = time_axis_->append_time(current_time_of_day());
            last_action_result_ = "tick=" + std::to_string(tick) +
            ", ms=" + std::to_string(time_axis_->tick_to_time(tick).milliseconds);
            return "Time_Axis 时间点已追加并回读";
        }
        if (spectrum_) {
            if (request.id == "push_samples") {
                push_spectrum_samples();
                return "Spectrum 样本已手动推送";
            }
            if (request.id == "power_at") {
                const auto argument = action_number(request);
                if (!argument)
                    return invalid_argument(recognized);
                bool ok{};
                const double power = spectrum_->power_at(*argument, ok);
                last_action_result_ = ok ? std::to_string(power) + " dB" : "频率不在样本范围";
                return "Spectrum::power_at 查询完成";
            }
            if (request.id == "add_marker" || request.id == "add_line_marker" ||
                request.id == "remove_marker" || request.id == "set_marker_frequency") {
                const auto argument = action_number(request);
                if (!argument)
                    return invalid_argument(recognized);
                if (request.id == "add_marker")
                    spectrum_->add_custom_marker(*argument);
                else if (request.id == "add_line_marker")
                    spectrum_->add_custom_line_marker(*argument);
                else if (request.id == "remove_marker")
                    spectrum_->remove_custom_marker(*argument);
                else {
                    const int selected = spectrum_->selected_marker_index();
                    if (selected >= 0)
                        spectrum_->set_marker_frequency(selected, *argument);
                    spectrum_->set_current_marker_frequency(*argument);
                }
                return "Marker API 已执行";
            }
            if (request.id == "remove_selected_marker") {
                spectrum_->remove_selected_marker();
                return "选中 Marker 已删除";
            }
            if (request.id == "clear_markers") {
                spectrum_->clear_custom_markers();
                return "全部 Marker 已清空";
            }
            if (request.id == "select_marker") {
                const auto argument = action_number(request);
                if (!argument)
                    return invalid_argument(recognized);
                spectrum_->set_selected_marker_index(static_cast<int>(std::lround(*argument)));
                return "Marker 索引已选择";
            }
            if (request.id == "select_next_marker") {
                spectrum_->select_next_marker();
                return "已选择下一个 Marker";
            }
            if (request.id == "select_previous_marker") {
                spectrum_->select_previous_marker();
                return "已选择上一个 Marker";
            }
            if (request.id == "clear_marker_selection") {
                spectrum_->clear_marker_selection();
                return "Marker 选择已清除";
            }
        }
        if (selection_) {
            if (request.id == "clear_selection") {
                selection_->clear_selected_regions();
                return "框选区域已清空";
            }
        }
        if (waterfall_) {
            if (request.id == "append_row") {
                push_waterfall_row();
                return "Waterfall 行已手动追加";
            }
            if (request.id == "append_tick_row") {
                const int tick = time_axis_->append_time(current_time_of_day());
                waterfall_->append_row(tick, spectrum_values(waterfall_->get<&Waterfall::Properties::frequency_bin_count>(),
                                                             waterfall_->get<&Waterfall::Properties::power_range>()));
                return "Waterfall 已通过 int tick 重载追加一行";
            }
        }
        if (afterglow_) {
            if (request.id == "append_spectrum") {
                push_afterglow_spectrum();
                return "Afterglow 频谱已手动追加";
            }
        }
        if (sweep_) {
            if (request.id == "append_block") {
                push_sweep_block();
                return "Sweep_Spectrum 扫频块已手动追加";
            }
        }
        if (trace_) {
            if (request.id == "append_sample") {
                push_trace_sample();
                return "Frequency_Trace 样本已手动追加";
            }
            if (request.id == "append_tick_sample") {
                const int tick = time_axis_->append_time(current_time_of_day());
                trace_->append_sample(tick, std::sin(frame_index_ * 0.12));
                return "Frequency_Trace 已通过 int tick 重载追加样本";
            }
        }
        if (constellation_) {
            if (request.id == "append_points") {
                push_constellation_points();
                return "Constellation IQ 点已手动追加";
            }
            if (request.id == "fit_square") {
                constellation_->fit_square_to_axes();
                return "Constellation 已按轴拟合正方形";
            }
        }
        recognized = false;
        return {};
    }
    void record_action_notice_if_empty(std::string_view notice) {
        if (last_action_result_.empty())
            last_action_result_ = notice;
    }
    [[nodiscard]] std::string telemetry_json() const {
        const auto observer = plot_.frame_observer_snapshot();
        const auto telemetry_now = std::chrono::steady_clock::now();
        const double elapsed_seconds = std::max(
            std::chrono::duration<double>(telemetry_now - performance_started_).count(),
            1e-9);
        const double render_fps = recent_rate(render_history_, telemetry_now);
        const double pixel_fps = recent_pixel_rate(pixel_history_, telemetry_now);
        const double pixel_megabytes_per_second = recent_pixel_megabytes_per_second(
            pixel_history_, telemetry_now);
        const auto render_window = render_duration_statistics_.snapshot();
        const auto pixel_encode_window = pixel_encode_statistics_.snapshot();
        const auto pixel_request_window = pixel_request_statistics_.snapshot();
        const bool low_latency = frame_mode_ == Gallery_Frame_Mode::Low_Latency;
        const Gallery_Consumer_Feedback_Snapshot consumer_feedback{
            low_latency && feedback_policy_.enabled,
            low_latency && feedback_policy_.pixel,
            low_latency && feedback_policy_.presentation,
            low_latency && feedback_policy_.manual,
            low_latency ? feedback_policy_.manual_fps : 0.0,
            consumer_feedback_source_,
            consumer_pixel_interval_ns_,
            consumer_presentation_interval_ns_,
            consumer_manual_interval_ns_};
        Gallery_Render_Performance render_performance;
        render_performance.render_attempt_count = render_attempt_count_;
        render_performance.successful_render_count = successful_render_count_;
        render_performance.failed_render_count =
            render_attempt_count_ - successful_render_count_;
        render_performance.measured_fps = render_fps;
        render_performance.lifetime_average_fps =
            static_cast<double>(successful_render_count_) / elapsed_seconds;
        render_performance.last_render_ms = last_render_ms_;
        render_performance.average_render_ms = render_window.average;
        render_performance.maximum_render_ms = render_window.maximum;
        render_performance.render_deviation_ms = render_window.deviation;
        render_performance.render_p50_ms = render_window.p50;
        render_performance.render_p95_ms = render_window.p95;
        render_performance.render_p99_ms = render_window.p99;
        render_performance.render_sample_count = render_window.sample_count;
        render_performance.pixel_response_fps = pixel_fps;
        render_performance.last_pixel_snapshot_ms = last_pixel_snapshot_ms_;
        render_performance.last_pixel_encode_ms = last_pixel_encode_ms_;
        render_performance.average_pixel_encode_ms = pixel_encode_window.average;
        render_performance.maximum_pixel_encode_ms = pixel_encode_window.maximum;
        render_performance.pixel_encode_deviation_ms = pixel_encode_window.deviation;
        render_performance.pixel_encode_p50_ms = pixel_encode_window.p50;
        render_performance.pixel_encode_p95_ms = pixel_encode_window.p95;
        render_performance.pixel_encode_p99_ms = pixel_encode_window.p99;
        render_performance.pixel_encode_sample_count = pixel_encode_window.sample_count;
        render_performance.last_pixel_request_ms = last_pixel_request_ms_;
        render_performance.average_pixel_request_ms = pixel_request_window.average;
        render_performance.pixel_request_deviation_ms = pixel_request_window.deviation;
        render_performance.pixel_request_p95_ms = pixel_request_window.p95;
        render_performance.pixel_request_p99_ms = pixel_request_window.p99;
        render_performance.last_pixel_bytes = last_pixel_bytes_;
        render_performance.pixel_payload_megabytes_per_second =
            pixel_megabytes_per_second;
        render_performance.automatic_low_latency_scheduler =
            automatic_low_latency_ && frame_mode_ == Gallery_Frame_Mode::Low_Latency;
        const Gallery_Client_Performance client_performance = client_performance_;
        nlohmann::json observer_data =
            adminive::to_frontend_json<nlohmann::json>(observer);
        nlohmann::json consumer_feedback_data =
            adminive::to_frontend_json<nlohmann::json>(consumer_feedback);
        nlohmann::json render_performance_data =
            adminive::to_frontend_json<nlohmann::json>(render_performance);
        nlohmann::json client_performance_data =
            adminive::to_frontend_json<nlohmann::json>(client_performance);
        nlohmann::json telemetry{
            {"case", case_id_},
            {"frame_mode", gallery_enum_id(frame_mode_)},
            {"frame_index", frame_index_},
            {
                "viewport", {
                    {"width", plot_.viewport_size().width},
                    {"height", plot_.viewport_size().height}
                }
            },
            {"view_active", plot_.view_active()},
            {"kernel_frame_count", plot_.diagnostics().refresh.frame_count},
            {"performance", std::move(render_performance_data)},
            {"kernel_observer", std::move(observer_data)},
            {"consumer_feedback", std::move(consumer_feedback_data)},
            {"client_performance", std::move(client_performance_data)},
            {"renderable_observers", controls_.observers(plot_)},
            {"performance_capture", gallery_performance_capture_json(plot_)},
            {"last_action_result", last_action_result_}
        };
        if (primary_) {
            telemetry["renderable"] = {
                {"object_name", primary_->object_name()},
                {"visible", primary_->is_visible()},
                {
                    "cache_mode", magic_enum::enum_name(primary_->get_cache_mode())
                }
            };
        }
        if (const auto overlay = plot_.performance_overlay()) {
            telemetry["performance_overlay_enabled"] = overlay->enabled();
            if (const auto snapshot = overlay->display_snapshot())
                telemetry["performance_overlay_lines"] = snapshot->lines.size();
        }
        if (const auto axis = horizontal_axis()) {
            const Axis_Transform transform = axis->transform();
            const Range range = transform.coordinate_range;
            const double center = range.center();
            telemetry["axis"] = {
                {"origin", range.origin}, {"target", range.target},
                {"start_coord", range.origin},
                {"end_coord", range.target},
                {"center_pixel", transform.coord_to_pixel(center)},
                {
                    "center_roundtrip", transform.pixel_to_coord(
                        transform.coord_to_pixel(center))
                },
                {"pixel_samples", static_cast<int>(transform.pixel_length) +
                                      (transform.pixel_length > 0.0 ? 1 : 0)},
                {"tick_step", axis->tick_step(range)},
                {
                    "sub_tick_count", axis->sub_tick_count(axis->tick_step(range))
                },
                {"center_label", axis->tick_label(center)}
            };
        }
        if (spectrum_) {
            telemetry["spectrum"] = {
                {"selectable_line_markers", spectrum_->selectable_line_marker_count()},
                {"selected_marker_index", spectrum_->selected_marker_index()},
                {"configured_frequency_points", spectrum_->get<&Spectrum::Properties::frequency_point_size>()},
                {"input_sample_count", spectrum_->sample_count()},
                {"rendered_point_count", spectrum_->rendered_point_count()}
            };
            const int selected = spectrum_->selected_marker_index();
            if (selected >= 0 && selected < spectrum_->selectable_line_marker_count())
                telemetry["spectrum"]["selected_marker_frequency"] =
                spectrum_->marker_frequency(selected);
        }
        if (selection_)
            telemetry["selection_regions"] = selection_->selected_regions().size();
        if (waterfall_) {
            telemetry["waterfall"] = {
                {"configured_frequency_bins", waterfall_->get<&Waterfall::Properties::frequency_bin_count>()},
                {"row_count", waterfall_->row_count()},
                {"stored_point_count", waterfall_->stored_point_count()},
                {"rendered_cell_count", waterfall_->rendered_cell_count()},
                {"time_axis_point_count", time_axis_ ? time_axis_->time_point_count() : 0}
            };
        }
        if (afterglow_) {
            telemetry["afterglow"] = {
                {"configured_frequency_points", afterglow_->get<&Afterglow::Properties::frequency_point_size>()},
                {"configured_power_points", afterglow_->get<&Afterglow::Properties::power_point_size>()},
                {"history_frame_count", afterglow_->history_count()},
                {"latest_input_point_count", afterglow_->latest_spectrum_point_count()},
                {"rendered_cell_count", afterglow_->rendered_cell_count()}
            };
        }
        if (sweep_) {
            telemetry["sweep_spectrum"] = {
                {"configured_bins_per_block", sweep_->get<&Sweep_Spectrum::Properties::bins_per_block>()},
                {"configured_block_count", sweep_->get<&Sweep_Spectrum::Properties::block_count>()},
                {"stored_block_count", sweep_->stored_block_count()},
                {"stored_point_count", sweep_->stored_point_count()},
                {"rendered_point_count", sweep_->rendered_point_count()}
            };
        }
        if (trace_) {
            telemetry["frequency_trace"] = {
                {"sample_count", trace_->sample_count()},
                {"rendered_point_count", trace_->rendered_point_count()},
                {"time_axis_point_count", time_axis_ ? time_axis_->time_point_count() : 0}
            };
        }
        if (constellation_) {
            const int anchor_count = static_cast<int>(
                constellation_->get<&Constellation_Diagram::Properties::type>());
            telemetry["constellation"] = {
                {"point_count", constellation_->point_count()},
                {"anchor_count", anchor_count},
                {
                    "rendered_point_count", constellation_->point_count() +
                    static_cast<std::size_t>(anchor_count)
                },
                {"point_lifetime_ms", constellation_->get<&Constellation_Diagram::Properties::point_lifetime_ms>()}
            };
        }
        if (case_id_ == "axis_lab") {
            telemetry["axis_lab"] = {
                {"domain_axis_pixel_samples", horizontal_axis()
                    ? static_cast<int>(horizontal_axis()->transform().pixel_length) + 1
                    : 0},
                {"time_axis_point_count", time_axis_ ? time_axis_->time_point_count() : 0}
            };
        }
        if (spectrum_)
            telemetry["data_shape"] = {
                {"input_points", spectrum_->sample_count()},
                {"rendered_elements", spectrum_->rendered_point_count()},
                {"unit", "points"}
            };
        else if (waterfall_)
            telemetry["data_shape"] = {
                {"input_points", waterfall_->stored_point_count()},
                {"rendered_elements", waterfall_->rendered_cell_count()},
                {"unit", "cells"}
            };
        else if (afterglow_)
            telemetry["data_shape"] = {
                {"input_points", afterglow_->latest_spectrum_point_count()},
                {"rendered_elements", afterglow_->rendered_cell_count()},
                {"unit", "cells"}
            };
        else if (sweep_)
            telemetry["data_shape"] = {
                {"input_points", sweep_->stored_point_count()},
                {"rendered_elements", sweep_->rendered_point_count()},
                {"unit", "points"}
            };
        else if (trace_)
            telemetry["data_shape"] = {
                {"input_points", trace_->sample_count()},
                {"rendered_elements", trace_->rendered_point_count()},
                {"unit", "points"}
            };
        else if (constellation_) {
            const std::size_t anchors = static_cast<std::size_t>(
                constellation_->get<&Constellation_Diagram::Properties::type>());
            telemetry["data_shape"] = {
                {"input_points", constellation_->point_count()},
                {"rendered_elements", constellation_->point_count() + anchors},
                {"unit", "points"}
            };
        }
        else
            telemetry["data_shape"] = {
                {"input_points", 0},
                {"rendered_elements", horizontal_axis()
                    ? static_cast<int>(horizontal_axis()->transform().pixel_length) + 1
                    : 0},
                {"unit", "axis samples"}
            };
        return telemetry.dump();
    }
private:
    using Performance_Clock = std::chrono::steady_clock;
    struct Pixel_Performance_Sample {
        Performance_Clock::time_point time;
        std::size_t bytes;
    };
    static void record_timestamp(std::deque<Performance_Clock::time_point>& history,
                                 Performance_Clock::time_point now) {
        history.push_back(now);
        const auto oldest = now - std::chrono::seconds(1);
        while (history.size() > 2 && history.front() < oldest)
            history.pop_front();
    }
    static double recent_rate(const std::deque<Performance_Clock::time_point>& history,
                              Performance_Clock::time_point now) {
        if (history.size() < 2 || now - history.back() > std::chrono::seconds(1))
            return 0.0;
        const double seconds =
        std::chrono::duration<double>(history.back() - history.front()).count();
        return seconds > 0.0 ? static_cast<double>(history.size() - 1) / seconds : 0.0;
    }
    static void record_pixel_sample(std::deque<Pixel_Performance_Sample>& history,
                                    Performance_Clock::time_point now,
                                    std::size_t bytes) {
        history.push_back({now, bytes});
        const auto oldest = now - std::chrono::seconds(1);
        while (history.size() > 2 && history.front().time < oldest)
            history.pop_front();
    }
    static double recent_pixel_rate(const std::deque<Pixel_Performance_Sample>& history,
                                    Performance_Clock::time_point now) {
        if (history.size() < 2 || now - history.back().time > std::chrono::seconds(1))
            return 0.0;
        const double seconds =
        std::chrono::duration<double>(history.back().time - history.front().time).count();
        return seconds > 0.0 ? static_cast<double>(history.size() - 1) / seconds : 0.0;
    }
    static double recent_pixel_megabytes_per_second(
        const std::deque<Pixel_Performance_Sample>& history,
        Performance_Clock::time_point now) {
        if (history.size() < 2 || now - history.back().time > std::chrono::seconds(1))
            return 0.0;
        const double seconds =
        std::chrono::duration<double>(history.back().time - history.front().time).count();
        if (seconds <= 0.0)
            return 0.0;
        std::size_t bytes{};
        for (std::size_t index = 1; index < history.size(); ++index)
            bytes += history[index].bytes;
        return static_cast<double>(bytes) / seconds / 1e6;
    }
    void apply_consumer_feedback() {
        if (frame_mode_ != Gallery_Frame_Mode::Low_Latency)
            return;
        consumer_pixel_interval_ns_ = frequency_to_ns(client_performance_.transport_fps);
        consumer_presentation_interval_ns_ =
            milliseconds_to_ns(client_performance_.display_interval_ms);
        consumer_manual_interval_ns_ = frequency_to_ns(feedback_policy_.manual_fps);
        consumer_feedback_source_ = "none";
        if (!feedback_policy_.enabled) {
            plot_.clear_consumer_feedback();
            consumer_feedback_source_ = "disabled";
            return;
        }
        std::uint64_t interval_ns = 0;
        const auto select_source = [&interval_ns, this](bool enabled, std::uint64_t candidate,
                                                        std::string_view source) {
            if (!enabled || candidate == 0)
                return;
            if (candidate > interval_ns) {
                interval_ns = candidate;
                consumer_feedback_source_ = source;
                return;
            }
            if (candidate == interval_ns) {
                if (consumer_feedback_source_ != "none")
                    consumer_feedback_source_ += '+';
                consumer_feedback_source_ += source;
            }
        };
        select_source(feedback_policy_.pixel,
                      consumer_pixel_interval_ns_, "pixel");
        select_source(feedback_policy_.presentation,
                      consumer_presentation_interval_ns_, "presentation");
        select_source(feedback_policy_.manual,
                      consumer_manual_interval_ns_, "manual");
        if (interval_ns == 0) {
            plot_.clear_consumer_feedback();
            return;
        }
        plot_.set_consumer_feedback({interval_ns});
    }
    void record_performance(std::chrono::steady_clock::time_point started, bool rendered) {
        const auto finished = std::chrono::steady_clock::now();
        ++render_attempt_count_;
        const double duration_ms =
        std::chrono::duration<double, std::milli>(finished - started).count();
        last_render_ms_ = duration_ms;
        if (rendered) {
            ++successful_render_count_;
            render_duration_statistics_.add(duration_ms);
            record_timestamp(render_history_, finished);
        }
        maybe_log_performance(finished);
    }
    void record_pixel_performance(Performance_Clock::time_point request_started,
                                  Performance_Clock::time_point encode_started,
                                  Performance_Clock::time_point encode_finished,
                                  std::size_t pixel_bytes) {
        last_pixel_snapshot_ms_ =
        std::chrono::duration<double, std::milli>(encode_started - request_started).count();
        last_pixel_encode_ms_ =
        std::chrono::duration<double, std::milli>(encode_finished - encode_started).count();
        last_pixel_request_ms_ =
        std::chrono::duration<double, std::milli>(encode_finished - request_started).count();
        pixel_encode_statistics_.add(last_pixel_encode_ms_);
        pixel_request_statistics_.add(last_pixel_request_ms_);
        last_pixel_bytes_ = pixel_bytes;
        ++pixel_frame_count_;
        record_pixel_sample(pixel_history_, encode_finished, pixel_bytes);
    }
    void maybe_log_performance(Performance_Clock::time_point now) {
        if (now - last_performance_log_ < std::chrono::seconds(1))
            return;
        last_performance_log_ = now;
        const auto observer = plot_.frame_observer_snapshot();
        const auto unix_ms = std::chrono::duration_cast<std::chrono::milliseconds>(
            std::chrono::system_clock::now().time_since_epoch())
        .count();
        const double pixel_fps = recent_pixel_rate(pixel_history_, now);
        const double pixel_megabytes_per_second = recent_pixel_megabytes_per_second(
            pixel_history_, now);
        const bool low_latency = frame_mode_ == Gallery_Frame_Mode::Low_Latency;
        const auto scheduler_interval_ns = low_latency ? kernel_refresh_interval_ns() : 0;
        const nlohmann::json line{
            {"event", "gallery_performance"},
            {"unix_ms", unix_ms},
            {"session_id", session_id_},
            {"case", case_id_},
            {"frame_mode", gallery_enum_id(frame_mode_)},
            {"configured_fps", low_latency ? plot_.max_render_fps() : 0.0},
            {"automatic_scheduler_interval_ns", scheduler_interval_ns},
            {"automatic_scheduler_fps", scheduler_interval_ns == 0 ? 0.0 : 1'000'000'000.0 / static_cast<double>(scheduler_interval_ns)},
            {"automatic_scheduler_limit_source", low_latency ? observer.limit_state : "not_applicable"},
            {"frequency_limit_enabled", low_latency && observer.frequency_limit_enabled},
            {"consumer_feedback_enabled", low_latency && observer.consumer_feedback_enabled},
            {"consumer_feedback_sample_interval_ns", low_latency ? observer.consumer_sample_interval_ns : 0},
            {"consumer_feedback_smoothed_interval_ns", low_latency ? observer.consumer_smoothed_interval_ns : 0},
            {"consumer_feedback_variation_ns", low_latency ? observer.consumer_variation_ns : 0},
            {"consumer_feedback_safety_interval_ns", low_latency ? observer.consumer_safety_interval_ns : 0},
            {"consumer_feedback_interval_ns", low_latency ? observer.consumer_interval_ns : 0},
            {"backend_render_fps", recent_rate(render_history_, now)},
            {"pixel_response_fps", pixel_fps},
            {"client_transport_fps", client_performance_.transport_fps},
            {"client_presentation_fps", client_performance_.presentation_fps},
            {"client_changed_pixel_frames", client_performance_.changed_pixel_frames},
            {"client_duplicate_pixel_frames", client_performance_.duplicate_pixel_frames},
            {"client_frame_request_timeout_count", client_performance_.frame_request_timeout_count},
            {"client_frame_round_trip_ms", client_performance_.frame_round_trip_ms},
            {"client_display_interval_ms", client_performance_.display_interval_ms},
            {"client_display_interval_latest_ms", client_performance_.display_interval_latest_ms},
            {"client_display_interval_p95_ms", client_performance_.display_interval_p95_ms},
            {"client_display_interval_p99_ms", client_performance_.display_interval_p99_ms},
            {"client_display_interval_deviation_ms", client_performance_.display_interval_deviation_ms},
            {"client_overwritten_pixel_frames", client_performance_.overwritten_pixel_frames},
            {"client_last_pixel_receive_age_ms", client_performance_.last_pixel_receive_age_ms},
            {"client_last_pixel_change_age_ms", client_performance_.last_pixel_change_age_ms},
            {"last_render_ms", last_render_ms_},
            {"last_pixel_snapshot_ms", last_pixel_snapshot_ms_},
            {"last_pixel_encode_ms", last_pixel_encode_ms_},
            {"last_pixel_request_ms", last_pixel_request_ms_},
            {"pixel_payload_bytes", last_pixel_bytes_},
            {"pixel_payload_megabytes_per_second", pixel_megabytes_per_second},
            {"websocket_buffered_bytes", client_performance_.websocket_buffered_bytes},
            {
                "automatic_low_latency_scheduler",
                automatic_low_latency_ && frame_mode_ == Gallery_Frame_Mode::Low_Latency
            },
            {"successful_render_count", successful_render_count_},
            {"failed_render_count", render_attempt_count_ - successful_render_count_},
            {"pixel_frame_count", pixel_frame_count_},
            {"last_event", observer.last_event},
            {"limit_state", observer.limit_state},
            {"observation_count", observer.observation_count},
            {"latest_sequence", observer.latest_sequence},
            {"produced_frame_count", observer.produced_frame_count},
            {"consumed_frame_count", observer.consumed_frame_count},
            {"target_interval_ns", observer.target_interval_ns},
            {"paint_duration_ns", observer.paint_duration_ns},
            {"render_duration_ns", observer.render_duration_ns},
            {"bottleneck_duration_ns", observer.bottleneck_duration_ns},
            {"consumer_sample_interval_ns", observer.consumer_sample_interval_ns},
            {"consumer_smoothed_interval_ns", observer.consumer_smoothed_interval_ns},
            {"consumer_variation_ns", observer.consumer_variation_ns},
            {"consumer_safety_interval_ns", observer.consumer_safety_interval_ns},
            {"consumer_interval_ns", observer.consumer_interval_ns},
            {"next_refresh_interval_ns", observer.next_refresh_interval_ns},
            {"paint_lease_wait_ns", observer.paint_lease_wait_ns},
            {"paint_state_wait_ns", observer.paint_state_wait_ns},
            {"publish_state_wait_ns", observer.publish_state_wait_ns},
            {"ready_wait_ns", observer.ready_wait_ns},
            {"frame_age_at_render_ns", observer.frame_age_at_render_ns},
            {"render_lease_wait_ns", observer.render_lease_wait_ns},
            {"render_state_wait_ns", observer.render_state_wait_ns},
            {"render_finish_state_wait_ns", observer.render_finish_state_wait_ns},
            {"queue_wait_ns", observer.queue_wait_ns},
            {"end_to_end_ns", observer.end_to_end_ns},
            {"pending_frames", observer.pending_frame_count},
            {"dropped_frames", observer.dropped_frame_count},
            {"failed_operations", observer.failed_operation_count}
        };
        write_web_performance_log(line.dump());
    }
    void build_axes(::Scene_Base::Attach_Builder& attach) {
        constexpr Color axis_color{118, 145, 184, 255};
        Range coordinate_range{88'000'000.0, 108'000'000.0};
        if (case_id_ == "sweep_spectrum")
            coordinate_range = {0.0, 300.0};
        else if (case_id_ == "constellation")
            coordinate_range = {-1.25, 1.25};
        if (case_id_ == "frequency_trace") {
            time_axis_ = Gallery_Time_Axis::Builder(axes_node_, Orientation::Horizontal, &attach)
                         .set_visible_time_point_count(80)
                         .set_tick_label_spacing_px(28)
                         .set_time_format("mm:ss.zzz")
                         .set_color(axis_color)
                         .build();
        }
        else if (case_id_ == "sweep_spectrum" || case_id_ == "constellation") {
            numeric_domain_axis_ = Gallery_Axis::Builder(axes_node_, Orientation::Horizontal, &attach)
                                   .set_coord_range(coordinate_range)
                                   .set_use_wheel(true)
                                   .set_use_drag(true)
                                   .set_color(axis_color)
                                   .build();
        }
        else {
            frequency_domain_axis_ = Gallery_Frequency_Axis::Builder(axes_node_, Orientation::Horizontal, &attach)
                                   .set_coord_range(coordinate_range)
                                   .set_use_wheel(true)
                                   .set_use_drag(true)
                                   .set_color(axis_color)
                                   .build();
        }
        if (case_id_ == "waterfall") {
            time_axis_ = Gallery_Time_Axis::Builder(axes_node_, Orientation::Vertical, &attach)
                         .set_visible_time_point_count(80)
                         .set_tick_label_spacing_px(28)
                         .set_time_format("mm:ss.zzz")
                         .set_color(axis_color)
                         .build();
        }
        else {
            Range value_range{-120.0, -20.0};
            if (case_id_ == "frequency_trace")
                value_range = {-1.0, 1.0};
            else if (case_id_ == "constellation")
                value_range = {-1.25, 1.25};
            value_axis_ = Gallery_Axis::Builder(axes_node_, Orientation::Vertical, &attach)
                          .set_coord_range(value_range)
                          .set_label_precision(case_id_ == "constellation" ? 2 : 0)
                          .set_color(axis_color)
                          .build();
        }
        if (case_id_ == "axis_lab") {
            time_axis_ = Gallery_Time_Axis::Builder(axes_node_, Orientation::Horizontal, &attach)
                         .set_visible_time_point_count(80)
                         .set_tick_label_spacing_px(28)
                         .set_time_format("mm:ss.zzz")
                         .set_color({69, 221, 190, 255})
                         .build();
        }
        const auto style = [this](const renderive_Owner<Abs_Axis>& axis) {
            if (!axis)
                return;
            update_axis_state(axis, [this](Axis_Base_Properties& value) {
                value.tick_length = 8;
                value.sub_tick_length = 4;
                value.unit_text = case_id_ == "sweep_spectrum" ? "MHz"
                                  : case_id_ == "constellation" ? "I / Q"
                                  : case_id_ == "frequency_trace" ? "value" : "Hz";
                value.unit_text_font = {12.0, 500, false};
                value.unit_text_pen = {Color{220, 233, 255, 255}};
                value.unit_text_background_brush = {
                    Color{7, 17, 31, 255}, Brush_Style::Solid};
            });
        };
        style(horizontal_axis());
        style(vertical_axis());
        if (case_id_ == "axis_lab")
            style(time_axis_);
    }
    void build_primary(::Scene_Base::Attach_Builder& attach) {
        if (case_id_ == "axis_lab") {
            primary_ = renderive_static_owner_cast<Renderable>(frequency_domain_axis_);
            return;
        }
        if (case_id_ == "spectrum" || case_id_ == "selection_overlay") {
            Spectrum_Properties properties;
            properties.frequency_range = {88'000'000.0, 108'000'000.0};
            properties.frequency_point_size = 512;
            properties.center_frequency = 98'000'000.0;
            properties.sweep_frequency_range = {94'000'000.0, 102'000'000.0};
            properties.max_hold_visible = true;
            properties.max_marker_visible = true;
            properties.sweep_region_visible = true;
            properties.max_brush = {color_from_hex("#332810", 76), Brush_Style::Solid};
            properties.current_brush = {color_from_hex("#0e3a35", 76), Brush_Style::Solid};
            properties.min_brush = {color_from_hex("#19213a", 76), Brush_Style::Solid};
            properties.max_pen = {color_from_hex("#ffd166"), 1.2};
            properties.current_pen = {color_from_hex("#35e6b2"), 2.0,
                                      Line_Style::Solid, Line_Cap::Round, Line_Join::Round};
            properties.min_pen = {color_from_hex("#7aa2ff"), 1.2};
            properties.selected_marker_pen = {color_from_hex("#ff4d8d"), 2.0};
            properties.marker_pen = {color_from_hex("#ff7a59"), 1.2};
            properties.middle_frequency_pen = {color_from_hex("#6bc8ff"), 1.0, Line_Style::Dash};
            properties.sweep_region_brush = {color_from_hex("#293257", 80), Brush_Style::Solid};
            spectrum_ = Gallery_Spectrum::Builder{properties, &attach}.build(
                data_node_, frequency_domain_axis_, value_axis_);
            primary_ = spectrum_;
            if (case_id_ == "selection_overlay") {
                Selection_Rectangle_Overlay_Properties overlay;
                overlay.label_font = {12.0, 500, false};
                overlay.selection_brush = {color_from_hex("#173b66", 70), Brush_Style::Solid};
                overlay.selection_border_pen = {color_from_hex("#7dd3fc"), 1.0, Line_Style::Dash};
                selection_ = Gallery_Selection_Rectangle_Overlay::Builder{overlay, &attach}.build(
                    overlay_node_, frequency_domain_axis_, value_axis_);
                primary_ = selection_;
            }
            return;
        }
        if (case_id_ == "waterfall") {
            Waterfall_Properties properties;
            properties.frequency_range = {88'000'000.0, 108'000'000.0};
            properties.power_range = {-120.0, -20.0};
            properties.frequency_bin_count = 256;
            waterfall_ = Gallery_Waterfall::Builder{properties, &attach}.build(
                data_node_, frequency_domain_axis_, time_axis_);
            primary_ = waterfall_;
            return;
        }
        if (case_id_ == "afterglow") {
            Afterglow_Properties properties;
            properties.frequency_range = {88'000'000.0, 108'000'000.0};
            properties.power_range = {-120.0, -20.0};
            properties.frequency_point_size = 192;
            properties.power_point_size = 96;
            properties.attenuation_rate = 0.18;
            afterglow_ = Gallery_Afterglow::Builder{properties, &attach}.build(
                data_node_, frequency_domain_axis_, value_axis_);
            primary_ = afterglow_;
            return;
        }
        if (case_id_ == "sweep_spectrum") {
            Sweep_Spectrum_Properties properties;
            properties.frequency_range = {0.0, 300.0};
            properties.bins_per_block = 64;
            properties.block_count = 8;
            properties.pen = {color_from_hex("#ffd166"), 1.8};
            properties.current_frequency_pen = {color_from_hex("#ff5d73"), 2.0};
            sweep_ = Gallery_Sweep_Spectrum::Builder{properties, &attach}.build(
                data_node_, numeric_domain_axis_, value_axis_);
            primary_ = sweep_;
            return;
        }
        if (case_id_ == "frequency_trace") {
            Frequency_Trace_Properties properties;
            properties.pen = {color_from_hex("#35e6b2"), 2.0, Line_Style::Solid,
                              Line_Cap::Round, Line_Join::Round};
            trace_ = Gallery_Frequency_Trace::Builder{properties, &attach}.build(
                data_node_, time_axis_, value_axis_);
            primary_ = trace_;
            return;
        }
        if (case_id_ == "constellation") {
            Constellation_Diagram_Properties properties;
            properties.i_range = {-1.25, 1.25};
            properties.q_range = {-1.25, 1.25};
            properties.point_color = color_from_hex("#49e6c3");
            properties.anchor_color = color_from_hex("#ffd166");
            properties.point_lifetime_ms = 1800;
            constellation_ = Gallery_Constellation_Diagram::Builder{properties, &attach}.build(
                data_node_, numeric_domain_axis_, value_axis_);
            primary_ = constellation_;
        }
    }
    renderive_Owner<Abs_Axis> horizontal_axis() const {
        if (frequency_domain_axis_)
            return frequency_domain_axis_;
        if (numeric_domain_axis_)
            return numeric_domain_axis_;
        return time_axis_;
    }
    renderive_Owner<Abs_Axis> vertical_axis() const {
        if (case_id_ == "waterfall")
            return time_axis_;
        return value_axis_;
    }
    void apply_layout() {
        const Size viewport = plot_.viewport_size();
        const int left = viewport.width < 440 ? 48 : 62;
        const int right = 24;
        const int top = case_id_ == "axis_lab" ? 48 : 18;
        const int bottom = 46;
        const int width = std::max(1, viewport.width - left - right);
        const int height = std::max(1, viewport.height - top - bottom);
        const auto layout_axis = [=](const renderive_Owner<Abs_Axis>& target) {
            if (!target)
                return;
            update_axis_state(target, [=](Axis_Base_Properties& axis) {
                axis.x = left;
                axis.y = axis.orientation == Orientation::Horizontal ? top + height : top;
                axis.pixel_length = static_cast<std::size_t>(
                    axis.orientation == Orientation::Horizontal ? width : height);
            });
        };
        layout_axis(horizontal_axis());
        layout_axis(vertical_axis());
        if (case_id_ == "axis_lab" && time_axis_) {
            time_axis_->update([&](auto& axis) {
                axis.x = left;
                axis.y = axis.orientation == Orientation::Horizontal ? 26 : top;
                axis.pixel_length = static_cast<std::size_t>(
                    axis.orientation == Orientation::Horizontal ? width : height);
            });
        }
    }
    void register_controls() {
        controls_.add(*session_control_);
        if (frequency_domain_axis_)
            controls_.add(*frequency_domain_axis_);
        if (numeric_domain_axis_)
            controls_.add("domain_axis", *numeric_domain_axis_);
        if (value_axis_)
            controls_.add("value_axis", *value_axis_);
        if (time_axis_)
            controls_.add(*time_axis_);
        if (spectrum_)
            controls_.add(*spectrum_);
        if (waterfall_)
            controls_.add(*waterfall_);
        if (afterglow_)
            controls_.add(*afterglow_);
        if (sweep_)
            controls_.add(*sweep_);
        if (trace_)
            controls_.add(*trace_);
        if (selection_)
            controls_.add(*selection_);
        if (constellation_)
            controls_.add(*constellation_);
    }
    std::vector<double> spectrum_values(int count, Range power_range = {-120.0, -20.0}) const {
        count = std::max(count, 2);
        std::vector<double> values(static_cast<std::size_t>(count));
        const double time = static_cast<double>(frame_index_) * 0.09;
        for (int index = 0; index < count; ++index) {
            const double x = static_cast<double>(index) / (count - 1);
            const double noise = std::sin(index * 11.71 + time * 2.9) *
            std::sin(index * 0.19 + time * 0.7) * 4.0;
            const double signal = 58.0 * gaussian(x, 0.32 + std::sin(time) * 0.04, 0.035) +
            45.0 * gaussian(x, 0.57, 0.07) +
            32.0 * gaussian(x, 0.78, 0.018);
            values[static_cast<std::size_t>(index)] =
            std::clamp(-112.0 + noise + signal, std::min(power_range.origin, power_range.target),
                       std::max(power_range.origin, power_range.target));
        }
        return values;
    }
    void push_spectrum_samples() {
        spectrum_->update_samples(spectrum_values(spectrum_->get<&Spectrum::Properties::frequency_point_size>()));
    }
    void push_waterfall_row() {
        waterfall_->append_row(current_time_of_day(),
                               spectrum_values(waterfall_->get<&Waterfall::Properties::frequency_bin_count>(), waterfall_->get<&Waterfall::Properties::power_range>()));
    }
    void push_afterglow_spectrum() {
        afterglow_->append_spectrum(spectrum_values(afterglow_->get<&Afterglow::Properties::frequency_point_size>(),
                                                    afterglow_->get<&Afterglow::Properties::power_range>()));
    }
    void push_sweep_block() {
        const int count = sweep_->get<&Sweep_Spectrum::Properties::bins_per_block>();
        std::vector<double> block(static_cast<std::size_t>(std::max(count, 1)));
        for (int index = 0; index < count; ++index) {
            const double x = static_cast<double>(index) / std::max(1, count - 1);
            block[static_cast<std::size_t>(index)] = -104.0 + 68.0 * gaussian(x, 0.5, 0.16) +
            std::sin(frame_index_ * 0.2 + index) * 4.0;
        }
        sweep_->append_block(block);
    }
    void push_trace_sample() {
        const Range range = value_axis_->get<&Axis_Properties::coordinates>();
        const double lower = range.origin;
        const double upper = range.target;
        const double center = (lower + upper) * 0.5;
        const double amplitude = std::abs(upper - lower) * 0.42;
        trace_->append_sample(current_time_of_day(), center + amplitude * std::sin(frame_index_ * 0.12));
    }
    void push_constellation_points() {
        const int count = static_cast<int>(
            constellation_->get<&Constellation_Diagram::Properties::type>());
        const double phase = constellation_->get<
            &Constellation_Diagram::Properties::phase_offset_radians>();
        for (int index = 0; index < 24; ++index) {
            const int anchor = static_cast<int>((frame_index_ * 7 + index * 5) % count);
            const double angle = phase + 2.0 * std::numbers::pi * anchor / count;
            const double noise = std::sin(frame_index_ * 0.31 + index * 1.73) * 0.055;
            constellation_->append_point({
                std::cos(angle) + noise,
                std::sin(angle) - noise * 0.7
            });
        }
    }
    void update_model() {
        if (spectrum_)
            push_spectrum_samples();
        if (waterfall_)
            push_waterfall_row();
        if (afterglow_)
            push_afterglow_spectrum();
        if (sweep_)
            push_sweep_block();
        if (trace_)
            push_trace_sample();
        if (constellation_)
            push_constellation_points();
        if (case_id_ == "axis_lab" && time_axis_)
            time_axis_->append_time(current_time_of_day());
        ++frame_index_;
    }
    static std::string invalid_argument(bool& recognized) {
        recognized = false;
        return {};
    }
    std::uint64_t session_id_{};
    std::string case_id_;
    Gallery_Frame_Mode frame_mode_ = Gallery_Frame_Mode::Low_Latency;
    bool automatic_low_latency_{};
    Scene_Type plot_;
    Gallery_Feedback_Policy feedback_policy_;
    std::unique_ptr<Gallery_Session_Control<Scene_Type>> session_control_;
    Gallery_Controls controls_;
    std::chrono::steady_clock::time_point performance_started_;
    std::chrono::steady_clock::time_point last_performance_log_;
    renderive_Owner<Renderable> root_;
    renderive_Owner<Renderable> axes_node_;
    renderive_Owner<Renderable> data_node_;
    renderive_Owner<Renderable> overlay_node_;
    renderive_Owner<Gallery_Axis> numeric_domain_axis_;
    renderive_Owner<Gallery_Frequency_Axis> frequency_domain_axis_;
    renderive_Owner<Gallery_Axis> value_axis_;
    renderive_Owner<Gallery_Time_Axis> time_axis_;
    renderive_Owner<Renderable> primary_;
    renderive_Owner<Gallery_Spectrum> spectrum_;
    renderive_Owner<Gallery_Waterfall> waterfall_;
    renderive_Owner<Gallery_Frequency_Trace> trace_;
    renderive_Owner<Gallery_Afterglow> afterglow_;
    renderive_Owner<Gallery_Sweep_Spectrum> sweep_;
    renderive_Owner<Gallery_Selection_Rectangle_Overlay> selection_;
    renderive_Owner<Gallery_Constellation_Diagram> constellation_;
    std::uint64_t frame_index_{};
    std::uint64_t render_attempt_count_{};
    std::uint64_t successful_render_count_{};
    double last_render_ms_{};
    Rolling_Statistics render_duration_statistics_{256};
    std::deque<Performance_Clock::time_point> render_history_;
    std::uint64_t pixel_frame_count_{};
    double last_pixel_snapshot_ms_{};
    double last_pixel_encode_ms_{};
    double last_pixel_request_ms_{};
    Rolling_Statistics pixel_encode_statistics_{256};
    Rolling_Statistics pixel_request_statistics_{256};
    std::size_t last_pixel_bytes_{};
    std::deque<Pixel_Performance_Sample> pixel_history_;
    Gallery_Client_Performance client_performance_;
    std::uint64_t consumer_pixel_interval_ns_{};
    std::uint64_t consumer_presentation_interval_ns_{};
    std::uint64_t consumer_manual_interval_ns_{};
    std::string consumer_feedback_source_{"none"};
    bool rendered_since_last_pixel_{};
    std::string last_action_result_;
};
std::unique_ptr<Gallery_Scene_Interface> make_gallery_scene(std::uint64_t session_id, std::string case_id, Gallery_Frame_Mode mode, bool automatic_low_latency) {
    switch (mode) {
    case Gallery_Frame_Mode::Manual:
        return std::make_unique<Gallery_Scene<Manual_Scene2D>>(session_id, std::move(case_id), mode, automatic_low_latency);
    case Gallery_Frame_Mode::Low_Latency:
        return std::make_unique<Gallery_Scene<Scene2D>>(session_id, std::move(case_id), mode, automatic_low_latency);
    case Gallery_Frame_Mode::Playback:
        return std::make_unique<Gallery_Scene<Playback_Scene2D>>(session_id, std::move(case_id), mode, automatic_low_latency);
    }
    throw std::invalid_argument("unknown gallery frame mode");
}
struct Gallery_Plot_Session::Impl {
    explicit Impl(bool enable_automatic_low_latency)
        : automatic_low_latency(enable_automatic_low_latency),
          session_id(next_session_id()) {}
    ~Impl() {
        render_worker.request_stop();
        scheduler_condition.notify_all();
    }
    static std::uint64_t next_session_id() noexcept {
        static std::atomic<std::uint64_t> next{1};
        return next.fetch_add(1, std::memory_order_relaxed);
    }
    void ensure_render_worker() {
        if (!automatic_low_latency || render_worker.joinable())
            return;
        render_worker = std::jthread(
            [this](std::stop_token stop) {
                run_automatic_renderer(stop);
            });
    }
    bool update_client_metrics(std::string_view message) {
        if (!scene)
            return false;
        const auto root = nlohmann::json::parse(message, nullptr, false);
        if (root.is_discarded() || !root.is_object() || !root.contains("client_metrics") ||
            !root["client_metrics"].is_object())
            return false;
        const auto& metrics = root["client_metrics"];
        const auto finite_metric = [&metrics](std::string_view name) {
            const auto iterator = metrics.find(std::string(name));
            if (iterator == metrics.end() || !iterator->is_number())
                return 0.0;
            const double value = iterator->get<double>();
            return std::isfinite(value) ? value : 0.0;
        };
        std::uint64_t buffered_bytes{};
        if (const auto iterator = metrics.find("websocket_buffered_bytes");
            iterator != metrics.end() && iterator->is_number_unsigned()) {
            buffered_bytes = iterator->get<std::uint64_t>();
        }
        const auto unsigned_metric = [&metrics](std::string_view name) {
            const auto iterator = metrics.find(std::string(name));
            if (iterator == metrics.end() || !iterator->is_number_integer())
                return std::uint64_t{};
            const auto value = iterator->get<std::int64_t>();
            return value > 0 ? static_cast<std::uint64_t>(value) : std::uint64_t{};
        };
        Gallery_Client_Performance performance;
        performance.transport_fps = finite_metric("transport_fps");
        performance.presentation_fps = finite_metric("presentation_fps");
        performance.websocket_buffered_bytes = buffered_bytes;
        performance.changed_pixel_frames = unsigned_metric("changed_pixel_frames");
        performance.duplicate_pixel_frames = unsigned_metric("duplicate_pixel_frames");
        performance.frame_request_timeout_count =
            unsigned_metric("frame_request_timeout_count");
        performance.frame_round_trip_ms = finite_metric("frame_round_trip_ms");
        performance.frame_round_trip_average_ms =
            finite_metric("frame_round_trip_average_ms");
        performance.frame_round_trip_deviation_ms =
            finite_metric("frame_round_trip_deviation_ms");
        performance.frame_round_trip_p95_ms = finite_metric("frame_round_trip_p95_ms");
        performance.frame_round_trip_p99_ms = finite_metric("frame_round_trip_p99_ms");
        performance.display_interval_ms = finite_metric("display_interval_ms");
        performance.display_interval_average_ms =
            finite_metric("display_interval_average_ms");
        performance.display_interval_latest_ms =
            finite_metric("display_interval_latest_ms");
        performance.display_interval_p95_ms = finite_metric("display_interval_p95_ms");
        performance.display_interval_p99_ms = finite_metric("display_interval_p99_ms");
        performance.display_interval_deviation_ms =
            finite_metric("display_interval_deviation_ms");
        performance.overwritten_pixel_frames =
            unsigned_metric("overwritten_pixel_frames");
        performance.last_pixel_receive_age_ms =
            finite_metric("last_pixel_receive_age_ms");
        performance.last_pixel_change_age_ms =
            finite_metric("last_pixel_change_age_ms");
        scene->set_client_metrics(performance);
        return true;
    }
    [[nodiscard]] std::unique_lock<std::mutex> acquire_foreground_lock() {
        foreground_waiters.fetch_add(1, std::memory_order_release);
        scheduler_condition.notify_all();
        std::unique_lock lock(mutex);
        foreground_waiters.fetch_sub(1, std::memory_order_release);
        scheduler_condition.notify_all();
        return lock;
    }
    void run_automatic_renderer(std::stop_token stop) {
        using Clock = std::chrono::steady_clock;
        std::unique_lock lock(mutex);
        std::optional<Clock::time_point> last_render_started;
        std::uint64_t active_generation = std::numeric_limits<std::uint64_t>::max();
        while (!stop.stop_requested()) {
            scheduler_condition.wait(lock, [this, &stop] {
                return stop.stop_requested() || (scene && scene->can_render_automatically());
            });
            if (stop.stop_requested())
                break;
            if (active_generation != scene_generation) {
                active_generation = scene_generation;
                last_render_started.reset();
            }
            if (foreground_waiters.load(std::memory_order_acquire) != 0) {
                scheduler_condition.wait(lock, [this, &stop] {
                    return stop.stop_requested() || foreground_waiters.load(std::memory_order_acquire) == 0;
                });
                continue;
            }
            const auto revision = scheduler_revision;
            const auto interval = std::chrono::nanoseconds(std::max<std::uint64_t>(1, scene->kernel_refresh_interval_ns()));
            const auto now = Clock::now();
            const auto deadline = last_render_started ? *last_render_started + interval : now;
            if (now < deadline) {
                const auto spin_window = std::min(interval / 4, std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::microseconds(250)));
                const auto coarse_deadline = deadline > now + spin_window ? deadline - spin_window : now;
                if (now < coarse_deadline) {
                    scheduler_condition.wait_until(lock, coarse_deadline, [this, &stop, revision, active_generation] {
                        return stop.stop_requested() || scheduler_revision != revision || scene_generation != active_generation ||
                        foreground_waiters.load(std::memory_order_acquire) != 0 || !scene || !scene->can_render_automatically();
                    });
                    continue;
                }
                lock.unlock();
                while (!stop.stop_requested() && Clock::now() < deadline)
                    std::this_thread::yield();
                lock.lock();
                continue;
            }
            const auto started = Clock::now();
            (void)scene->render_latest_frame();
            last_render_started = started;
        }
    }
    static bool affects_render_schedule(const Web_Event& event) {
        return std::visit(
            [](const auto& value) {
                using T = std::decay_t<decltype(value)>;
                if constexpr (std::is_same_v<T, Frame_Request>) {
                    return false;
                }
                else if constexpr (std::is_same_v<T, Gallery_Request>) {
                    return value.kind != Gallery_Request_Kind::Catalog &&
                    value.kind != Gallery_Request_Kind::Observe &&
                    value.kind != Gallery_Request_Kind::Refresh &&
                    value.kind != Gallery_Request_Kind::Reset_Monitoring;
                }
                else {
                    return true;
                }
            },
            event);
    }
    std::unique_ptr<Gallery_Scene_Interface> scene;
    std::mutex mutex;
    std::condition_variable scheduler_condition;
    std::uint64_t scheduler_revision{};
    std::uint64_t scene_generation{};
    bool automatic_low_latency{};
    std::uint64_t session_id{};
    std::atomic<std::uint32_t> foreground_waiters{};
    std::jthread render_worker;
    std::optional<Web_Response> handle_gallery(const Gallery_Request& request) {
        if (request.kind == Gallery_Request_Kind::Catalog)
            return Web_Response{Web_Response_Type::Json, Gallery_Protocol::catalog_json()};
        if (request.kind == Gallery_Request_Kind::Open) {
            const auto open = Gallery_Protocol::open_request(request.message);
            if (!open)
                return Web_Response{
                    Web_Response_Type::Json,
                    Gallery_Protocol::error_json("未知的 gallery case 或 frame_mode", "case")
                };
            scene = make_gallery_scene(session_id, open->case_id, open->frame_mode, automatic_low_latency);
            ++scene_generation;
            if (scene->frame_mode() == Gallery_Frame_Mode::Low_Latency)
                ensure_render_worker();
            return Web_Response{
                Web_Response_Type::Json,
                Gallery_Protocol::case_json_from_controls(scene->case_id(), scene->controls().dump(),
                                            scene->telemetry_json(),
                                            "render_2D/Kernel 独立画布已创建",
                                            scene->frame_mode(), false)
            };
        }
        if (!scene)
            return Web_Response{
                Web_Response_Type::Json,
                Gallery_Protocol::error_json("请先发送 gallery_open")
            };
        if (request.kind == Gallery_Request_Kind::Observe) {
            if (update_client_metrics(request.message)) {
                ++scheduler_revision;
                scheduler_condition.notify_all();
            }
            return Web_Response{
                Web_Response_Type::Json,
                Gallery_Protocol::observer_json(
                    scene->case_id(), scene->frame_mode(), scene->telemetry_json())
            };
        }
        if (request.kind == Gallery_Request_Kind::Refresh) {
            if (update_client_metrics(request.message)) {
                ++scheduler_revision;
                scheduler_condition.notify_all();
            }
            return Web_Response{
                Web_Response_Type::Json,
                Gallery_Protocol::case_json_from_controls(
                    scene->case_id(), scene->controls().dump(),
                    scene->telemetry_json(), "观察数据已手动刷新",
                    scene->frame_mode(), true)
            };
        }
        if (request.kind == Gallery_Request_Kind::Reset_Monitoring) {
            scene->reset_monitoring();
            return Web_Response{
                Web_Response_Type::Json,
                Gallery_Protocol::case_json_from_controls(
                    scene->case_id(), scene->controls().dump(),
                    scene->telemetry_json(), "监测滑动窗口已重置",
                    scene->frame_mode(), true)
            };
        }
        if (request.kind == Gallery_Request_Kind::Patch) {
            const auto patch = Gallery_Protocol::control_patch_request(request.message);
            if (!patch)
                return Web_Response{Web_Response_Type::Json,
                    Gallery_Protocol::error_json("gallery_patch format is invalid")};
            const auto result = scene->apply_patch(
                patch->target, nlohmann::json::parse(patch->patch_json));
            if (!result.success)
                return Web_Response{Web_Response_Type::Json,
                    Gallery_Protocol::error_json(result.message)};
            return Web_Response{
                Web_Response_Type::Json,
                Gallery_Protocol::case_json_from_controls(scene->case_id(), scene->controls().dump(),
                                            scene->telemetry_json(),
                                            "控件 API 已由后端应用",
                                            scene->frame_mode(), false)
            };
        }
        const auto action = Gallery_Protocol::action_request(request.message);
        if (!action)
            return Web_Response{
                Web_Response_Type::Json,
                Gallery_Protocol::error_json("gallery_action 格式无效")
            };
        if (!Gallery_Protocol::action_available(scene->case_id(), scene->frame_mode(),
                                                action->id))
            return Web_Response{
                Web_Response_Type::Json,
                Gallery_Protocol::error_json(
                    "动作不属于当前画布或帧策略", "action")
            };
        if (action->id == "reset") {
            const std::string id = scene->case_id();
            const auto mode = scene->frame_mode();
            scene = make_gallery_scene(session_id, id, mode, automatic_low_latency);
            ++scene_generation;
            return Web_Response{
                Web_Response_Type::Json,
                Gallery_Protocol::case_json_from_controls(id, scene->controls().dump(),
                                            scene->telemetry_json(),
                                            "本图已恢复后端默认值", mode, false)
            };
        }
        bool recognized{};
        const std::string notice = scene->action(*action, recognized);
        if (!recognized)
            return Web_Response{
                Web_Response_Type::Json,
                Gallery_Protocol::error_json("动作不属于当前画布或参数无效",
                                             "action")
            };
        scene->record_action_notice_if_empty(notice);
        return Web_Response{
            Web_Response_Type::Json,
            Gallery_Protocol::case_json_from_controls(scene->case_id(), scene->controls().dump(),
                                        scene->telemetry_json(), notice,
                                        scene->frame_mode(), false)
        };
    }
    std::optional<Web_Response> handle_frame_request() {
        const auto request_started = std::chrono::steady_clock::now();
        std::optional<std::string> pixels;
        {
            auto lock = acquire_foreground_lock();
            if (!scene)
                return std::nullopt;
            const auto encode_started = std::chrono::steady_clock::now();
            pixels = scene->encode_latest_pixels();
            const auto encode_finished = std::chrono::steady_clock::now();
            if (pixels)
                scene->record_pixel_response(request_started, encode_started, encode_finished,
                                             pixels->size());
        }
        if (!pixels)
            return std::nullopt;
        return Web_Response{Web_Response_Type::Pixels, std::move(*pixels)};
    }
    std::optional<Web_Response> handle(const Web_Event& event) {
        if (std::holds_alternative<Frame_Request>(event))
            return handle_frame_request();
        const bool reschedule = affects_render_schedule(event);
        std::optional<Web_Response> response;
        {
            auto lock = acquire_foreground_lock();
            response = std::visit(
                [this](const auto& value) -> std::optional<Web_Response> {
                    using T = std::decay_t<decltype(value)>;
                    if constexpr (std::is_same_v<T, Gallery_Request>) {
                        return handle_gallery(value);
                    }
                    else if constexpr (std::is_same_v<T, Frame_Request>) {
                        return std::nullopt;
                    }
                    else if constexpr (std::is_same_v<T, Viewport_Resize>) {
                        if (scene)
                            scene->resize(value.size);
                    }
                    else if constexpr (std::is_same_v<T, Event>) {
                        if (scene)
                            scene->dispatch(value);
                    }
                    else if constexpr (Event_Object<T>) {
                        if (scene)
                            scene->dispatch(value);
                    }
                    return std::nullopt;
                },
                event);
            if (reschedule)
                ++scheduler_revision;
        }
        if (reschedule)
            scheduler_condition.notify_all();
        return response;
    }
};
Gallery_Plot_Session::Gallery_Plot_Session() : Gallery_Plot_Session(false) {}
Gallery_Plot_Session::Gallery_Plot_Session(bool automatic_low_latency)
    : impl_(std::make_unique<Impl>(automatic_low_latency)) {}
Gallery_Plot_Session::~Gallery_Plot_Session() = default;
std::optional<Web_Response> Gallery_Plot_Session::handle(const Web_Event& event) {
    return impl_->handle(event);
}
} // namespace renderive::web
