#include "application/config/ConfigSnapshotBuilder.h"

#include <string_view>

#include "application/config/ConfigOwner.h"
#include "application/config/values/BasicValues.h"
#include "application/config/values/ColorValues.h"
#include "application/config/values/KeybindValue.h"
#include "application/config/values/NumberValues.h"
#include "application/config/values/TextValues.h"

namespace ta::application::config
{
namespace
{
    ta::ui::ConfigControlKind to_ui_kind(const ConfigValueKind kind)
    {
        switch (kind)
        {
        case ConfigValueKind::Checkbox: return ta::ui::ConfigControlKind::Checkbox;
        case ConfigValueKind::Colorpicker: return ta::ui::ConfigControlKind::Colorpicker;
        case ConfigValueKind::FloatSlider: return ta::ui::ConfigControlKind::FloatSlider;
        case ConfigValueKind::IntSlider: return ta::ui::ConfigControlKind::IntSlider;
        case ConfigValueKind::IntTextbox: return ta::ui::ConfigControlKind::IntTextbox;
        case ConfigValueKind::Keybind: return ta::ui::ConfigControlKind::Keybind;
        case ConfigValueKind::Select: return ta::ui::ConfigControlKind::Select;
        case ConfigValueKind::Textbox:
        default: return ta::ui::ConfigControlKind::Textbox;
        }
    }

    ta::ui::ConfigValueSnapshot snapshot_value(ConfigValue* value)
    {
        ta::ui::ConfigValueSnapshot snapshot{};
        if (!value)
            return snapshot;

        snapshot.id = value->value_id();
        snapshot.key = value->get_config_key();
        snapshot.label_key = value->display_name();
        snapshot.kind = to_ui_kind(value->kind());

        switch (value->kind())
        {
        case ConfigValueKind::Checkbox:
            snapshot.bool_value = static_cast<CheckboxValue*>(value)->get_value();
            break;
        case ConfigValueKind::Colorpicker:
        {
            const ConfigColor color = static_cast<ColorpickerValue*>(value)->get_value();
            snapshot.color_value = {color.x, color.y, color.z, color.w};
            break;
        }
        case ConfigValueKind::FloatSlider:
        {
            auto* slider = static_cast<FloatSliderValue*>(value);
            snapshot.float_value = slider->get_value();
            snapshot.float_min = slider->min_value();
            snapshot.float_max = slider->max_value();
            snapshot.float_step = slider->step_value();
            break;
        }
        case ConfigValueKind::IntSlider:
        {
            auto* slider = static_cast<IntSliderValue*>(value);
            snapshot.int_value = slider->get_value();
            snapshot.int_min = slider->min_value();
            snapshot.int_max = slider->max_value();
            break;
        }
        case ConfigValueKind::IntTextbox:
            snapshot.int_value = static_cast<IntTextboxValue*>(value)->get_value();
            break;
        case ConfigValueKind::Keybind:
        {
            auto* keybind = static_cast<KeybindValue*>(value);
            snapshot.int_value = keybind->get_value();
            snapshot.allow_none = keybind->allow_none();
            break;
        }
        case ConfigValueKind::Select:
        {
            auto* select = static_cast<SelectValue*>(value);
            snapshot.int_value = select->get_value();
            const auto& options = select->options_ref();
            snapshot.options.reserve(options.size());
            for (const std::string& option : options)
                snapshot.options.push_back(option);
            break;
        }
        case ConfigValueKind::Textbox:
            snapshot.text_value = static_cast<TextboxValue*>(value)->get();
            break;
        default:
            break;
        }

        return snapshot;
    }

    ta::ui::ConfigValueSnapshot snapshot_action(const ta::application::UiAction* action)
    {
        ta::ui::ConfigValueSnapshot snapshot{};
        if (!action)
            return snapshot;

        snapshot.id = action->value_id();
        snapshot.key = action->key();
        snapshot.label_key = action->display_name();
        snapshot.kind = ta::ui::ConfigControlKind::ActionRow;
        return snapshot;
    }

    ta::ui::ConfigPanelSnapshot snapshot_owner(const ConfigOwner& owner)
    {
        ta::ui::ConfigPanelSnapshot snapshot{};
        snapshot.id = owner.config_owner_id();
        snapshot.label_key = owner.name;
        snapshot.category = owner.category;
        snapshot.values.reserve(owner.config_values().size() + owner.ui_actions().size());
        for (ConfigValue* value : owner.config_values())
            snapshot.values.push_back(snapshot_value(value));
        for (const ta::application::UiAction* action : owner.ui_actions())
            snapshot.values.push_back(snapshot_action(action));
        return snapshot;
    }

}
}

namespace ta::application::config::snapshot_builder
{
    ta::ui::ConfigUiSnapshot build_snapshot(const ConfigOwner& global_config,
                                        const std::vector<ConfigOwner*>& owners)
    {
        ta::ui::ConfigUiSnapshot snapshot{};
        snapshot.global_config = snapshot_owner(global_config);
        snapshot.panels.reserve(owners.size());
        for (ConfigOwner* owner : owners)
        {
            if (owner)
                snapshot.panels.push_back(snapshot_owner(*owner));
        }
        return snapshot;
    }

}
