#pragma once

#include "core/asset_helpers/save_projectile_config.h"
#include "core/projectile_config/projectile_config.h"
#include "core/projectile_type/projectile_type.h"
#include "spdlog/spdlog.h"
#include <RmlUi/Core.h>
#include <RmlUi/Core/Elements/ElementFormControlInput.h>
#include <RmlUi/Debugger.h>
#include <RmlUi_Backend.h>
#include <unordered_map>
#include <vector>

using std::string;
using std::unordered_map;
using std::vector;

using Rml::DataModelHandle;
using Rml::Event;
using Rml::VariantList;

namespace UI::ProjectileEditor {

struct ViewModel {
    vector<string> projectile_name;
    string projectile_image;
    int selected_projectile_idx = 0;
    std::string scale = "0";
    std::string speed = "0";
};

class Page {
  public:
    Rml::ElementDocument *document = nullptr;

    vector<ProjectileConfig> ordered_projectile_configs;

    ViewModel vm;

    void initialize(Rml::Context *context, unordered_map<ProjectileType, ProjectileConfig> projectile_configs) {
        // Init view model
        for (size_t i = 0; i < ordered_projectile_types.size(); i++) {
            ordered_projectile_configs.push_back(projectile_configs[ordered_projectile_types[i]]);

            vm.projectile_name.push_back(ordered_projectile_type_names[i]);
        }

        select_projectile(0);

        // Bind view model
        if (Rml::DataModelConstructor constructor = context->CreateDataModel("projectile_editor")) {
            constructor.RegisterArray<vector<string>>();

            if (auto sh = constructor.RegisterStruct<ViewModel>()) {
                sh.RegisterMember("projectile_name", &ViewModel::projectile_name);
                sh.RegisterMember("projectile_image", &ViewModel::projectile_image);
                sh.RegisterMember("selected_projectile_idx", &ViewModel::selected_projectile_idx);
                sh.RegisterMember("scale", &ViewModel::scale);
                sh.RegisterMember("speed", &ViewModel::speed);
            }

            constructor.BindEventCallback(
                "on_scale_change",
                [this](DataModelHandle handle, Event &event, const VariantList &) {
                    auto value_str = event.GetParameter<Rml::String>("value", "");
                    vm.scale = value_str;
                    handle.DirtyVariable("vm");
                });

            constructor.BindEventCallback(
                "on_speed_change",
                [this](DataModelHandle handle, Event &event, const VariantList &) {
                    auto value_str = event.GetParameter<Rml::String>("value", "");
                    vm.speed = value_str;
                    handle.DirtyVariable("vm");
                });

            constructor.BindEventCallback(
                "on_select_projectile",
                [this](DataModelHandle handle, Event &, const VariantList &args) {
                    int idx = args[0].Get<int>();
                    select_projectile(idx);
                    handle.DirtyVariable("vm");
                });

            constructor.BindEventCallback(
                "on_save_projectile",
                [this](DataModelHandle handle, Event &, const VariantList &) {
                    save_projectile();
                    handle.DirtyVariable("vm");
                });

            constructor.Bind("vm", &vm);

            document = context->LoadDocument("build/assets/ui/pages/projectile_editor/projectile_editor.rml");

            data_model_handle = constructor.GetModelHandle();
        }
    }

    void show() {
        document->Show();
    }

    void hide() {
        document->Hide();
    }

  private:
    Rml::DataModelHandle data_model_handle;

    void select_projectile(int idx) {
        auto &projectile_config = ordered_projectile_configs[idx];

        vm.projectile_image = "../../../../" + projectile_config.image_path;

        vm.selected_projectile_idx = idx;

        vm.scale = std::to_string(projectile_config.scale);
        vm.speed = std::to_string(projectile_config.speed);
    }

    void save_projectile() {
        auto &projectile_config = ordered_projectile_configs[vm.selected_projectile_idx];

        projectile_config.scale = stof(vm.scale);
        projectile_config.speed = stof(vm.speed);

        save_projectile_config(projectile_config);
    }
};

} // namespace UI::ProjectileEditor
