#pragma once

#include <array>
#include <string>
#include <vector>

#include <imgui.h>
#ifdef IMGUI_IMPL_VULKAN_USE_VOLK
#include <volk.h>
#else
#include <vulkan/vulkan.h>
#endif

struct VpCapabilities_T;
struct VpProfileProperties;

namespace vkcheck {
namespace internal {
enum class SupportFilter : uint8_t {
    SHOW_ALL,
    SHOW_SUPPORTED,
    SHOW_UNSUPPORTED,
};

struct ApiConformance {
    std::array<std::pair<float, std::string>, 4> required_extensions;
    std::array<std::pair<float, std::string>, 4> optional_extensions;
};
} // namespace internal

namespace {
struct Extension;
}

class Gui {
    VkAllocationCallbacks* allocator = nullptr;
    VkInstance instance = VK_NULL_HANDLE;

    VpCapabilities_T* capabilities;
    std::vector<VpProfileProperties> profiles;

    std::vector<struct PhysicalDevice> physical_devices;
    std::vector<struct ExtensionRow> instance_extensions;
    std::vector<struct ExtensionRow> device_extensions;
    size_t current_device = 0;
    std::string current_search;
    internal::SupportFilter support_filter = internal::SupportFilter::SHOW_ALL;
    std::vector<struct ProfileSupport> profile_support;
    std::string log_current_profile;

    struct {
        std::vector<std::reference_wrapper<struct ExtensionRow>> instance_extension_rows;
        std::vector<std::reference_wrapper<struct ExtensionRow>> device_extension_rows;
        internal::ApiConformance device_conformance;
        std::string device_info;
        std::string profile_support_log;
    } view;

    ImGuiContext* imgui_context;
    bool fullscreen;

    void refresh() noexcept;

    template <typename T>
    std::vector<struct ExtensionRow> build_extension_rows(
        const std::vector<Extension>& all, std::vector<T> implemented) noexcept;
    void update_displayed_extension_rows() noexcept;

    bool render_toolbar() noexcept;
    void render_instance_extensions_tree(ImGuiWindowFlags window_flags, bool force_sort) noexcept;
    void render_profile_support_tree() noexcept;
    void render_profile_support_cell(const char* profile_name, bool supports, const std::string& log) noexcept;
    void render_device_extensions_tree(ImGuiWindowFlags window_flags, bool force_sort) noexcept;

  public:
    Gui(const Gui&) = default;
    Gui(Gui&&) = delete;
    Gui& operator=(const Gui&) = default;
    Gui& operator=(Gui&&) = delete;
    explicit Gui(VkInstance instance, float main_scale = 1.0, bool fullscreen = false) noexcept;
    virtual ~Gui();

    void render() noexcept;
};
} // namespace vkcheck
