#pragma once

#include "renderive/scene/Scene2D_Context.hpp"
#include <structive/property/property.hpp>

#include <cstdint>
#include <algorithm>
#include <string>
#include <string_view>
#include <vector>

namespace renderive::web {

enum class Gallery_Frame_Mode : std::uint8_t {
    Manual,
    Low_Latency,
    Playback
};

struct Gallery_Action_Category {};

struct Gallery_Action_Attribute {
    using attribute_category = Gallery_Action_Category;
    static constexpr bool single_valued = false;
    static constexpr bool inheritable = false;

    std::string_view id;
    std::string_view label;
    std::string_view api;
    std::string_view group;
    std::string_view description;
    std::string_view argument_input;
    std::string_view argument_label;
    double argument_default{};
    bool request_frame{};
};

constexpr Gallery_Action_Attribute gallery_action(
    std::string_view id, std::string_view label, std::string_view api,
    std::string_view group, std::string_view description = {},
    std::string_view argument_input = {}, std::string_view argument_label = {},
    double argument_default = 0.0, bool request_frame = false) {
    return {id, label, api, group, description, argument_input, argument_label,
            argument_default, request_frame};
}

struct Gallery_Action_Model {
    std::string id;
    std::string label;
    std::string api;
    std::string description;
    std::string group;
    std::string argument_input;
    std::string argument_label;
    double argument_default{};
    bool request_frame{};
};

inline Gallery_Action_Model gallery_action_model(
    const Gallery_Action_Attribute& action) {
    return {std::string(action.id), std::string(action.label), std::string(action.api),
            std::string(action.description), std::string(action.group),
            std::string(action.argument_input), std::string(action.argument_label),
            action.argument_default, action.request_frame};
}

template <structive::Property_Described_Object Object>
void append_gallery_actions(std::vector<Gallery_Action_Model>& target) {
    structive::type_descriptor<Object>()
        .template for_each_type_attribute<Gallery_Action_Category>(
            [&target](const auto& action) {
                const auto found = std::find_if(
                    target.begin(), target.end(),
                    [&action](const auto& existing) { return existing.id == action.id; });
                if (found == target.end())
                    target.push_back(gallery_action_model(action));
            });
}

} // namespace renderive::web

namespace structive {

template <class Scene_Frame, Mutex_Type Mutex, class Observer>
struct Type_Descriptor<Manual_Refresh_Strategy<Scene_Frame, Mutex, Observer>> {
    using T = Manual_Refresh_Strategy<Scene_Frame, Mutex, Observer>;
    static auto get() {
        using renderive::web::gallery_action;
        return object<T>(type_metadata(
            gallery_action("mode_prepare", "准备帧",
                           "Manual_Refresh_Strategy::acquire_painter / Basic_Scene2D::prepare_frame",
                           "Manual_Refresh_Strategy"),
            gallery_action("mode_refresh", "提交手动刷新",
                           "Manual_Refresh_Strategy::refresh / Basic_Scene2D::refresh_manual_frame",
                           "Manual_Refresh_Strategy"),
            gallery_action("mode_render", "渲染已刷新帧",
                           "Manual_Refresh_Strategy::acquire_renderer / Basic_Scene2D::render_prepared_frame",
                           "Manual_Refresh_Strategy", {}, {}, {}, 0.0, true),
            gallery_action("mode_discard", "丢弃待刷新帧",
                           "Basic_Scene2D::discard_pending_frame",
                           "Manual_Refresh_Strategy"),
            gallery_action("mode_cycle", "执行完整手动帧周期",
                           "Basic_Scene2D::render_frame", "Manual_Refresh_Strategy",
                           {}, {}, {}, 0.0, true)));
    }
};

template <class Scene_Frame, Mutex_Type Mutex, class Observer>
struct Type_Descriptor<Low_Latency_Strategy<Scene_Frame, Mutex, Observer>> {
    using T = Low_Latency_Strategy<Scene_Frame, Mutex, Observer>;
    static auto get() {
        using renderive::web::gallery_action;
        return object<T>(type_metadata(
            gallery_action("mode_prepare", "发布低延迟帧",
                           "Low_Latency_Strategy::acquire_painter / Basic_Scene2D::prepare_frame",
                           "Low_Latency_Strategy"),
            gallery_action("mode_render", "消费最新帧",
                           "Low_Latency_Strategy::acquire_renderer / Basic_Scene2D::render_prepared_frame",
                           "Low_Latency_Strategy", {}, {}, {}, 0.0, true),
            gallery_action("mode_discard", "丢弃陈旧帧",
                           "Basic_Scene2D::discard_pending_frame", "Low_Latency_Strategy"),
            gallery_action("mode_cycle", "执行低延迟帧周期",
                           "Basic_Scene2D::render_frame", "Low_Latency_Strategy",
                           {}, {}, {}, 0.0, true)));
    }
};

template <class Scene_Frame, Mutex_Type Mutex, class Observer>
struct Type_Descriptor<Flow_Refresh_Strategy<Scene_Frame, Mutex, Observer>> {
    using T = Flow_Refresh_Strategy<Scene_Frame, Mutex, Observer>;
    static auto get() {
        using renderive::web::gallery_action;
        return object<T>(type_metadata(
            gallery_action("mode_enqueue", "压入一帧",
                           "Flow_Refresh_Strategy::acquire_painter / Basic_Scene2D::prepare_frame",
                           "Flow_Refresh_Strategy"),
            gallery_action("mode_enqueue_burst", "批量压入回放队列",
                           "Flow_Refresh_Strategy::acquire_painter / Basic_Scene2D::prepare_frame x N",
                           "Flow_Refresh_Strategy", {}, "number", "帧数", 8.0),
            gallery_action("mode_dequeue", "消费队首帧",
                           "Flow_Refresh_Strategy::acquire_renderer / Basic_Scene2D::render_prepared_frame",
                           "Flow_Refresh_Strategy", {}, {}, {}, 0.0, true),
            gallery_action("mode_cycle", "执行回放帧周期",
                           "Basic_Scene2D::render_frame", "Flow_Refresh_Strategy",
                           {}, {}, {}, 0.0, true)));
    }
};

} // namespace structive

namespace renderive::web {

inline std::vector<Gallery_Action_Model> gallery_frame_actions(Gallery_Frame_Mode mode) {
    std::vector<Gallery_Action_Model> result;
    switch (mode) {
    case Gallery_Frame_Mode::Manual:
        append_gallery_actions<Manual_Refresh_Strategy<Scene2D_Frame_Data, std::mutex,
                                                       Observer_State<>>>(result);
        break;
    case Gallery_Frame_Mode::Low_Latency:
        append_gallery_actions<Low_Latency_Strategy<Scene2D_Frame_Data, std::mutex,
                                                    Observer_State<>>>(result);
        break;
    case Gallery_Frame_Mode::Playback:
        append_gallery_actions<Flow_Refresh_Strategy<Scene2D_Frame_Data, std::mutex,
                                                     Observer_State<>>>(result);
        break;
    }
    return result;
}

} // namespace renderive::web
