#pragma once
#include <vector>

#include "ConfigValue.h"
#include "../gui/menu/imgui_addons.h"

class SelectValue : public ConfigValue
{
public:
    SelectValue(int initial, const std::vector<const char*>& options, const std::string& n,
                const bool translate_options = true)
        : ConfigValue(n), translate_options_(translate_options)
    {
        this->value_ = initial;
        this->def_ = initial;
        this->options = options;
        clamp_value();
    }

    SelectValue(int initial, const char* const* options, const size_t count, const std::string& n,
                const bool translate_options = true)
        : ConfigValue(n), translate_options_(translate_options)
    {
        this->value_ = initial;
        this->def_ = initial;
        this->options.assign(options, options + count);
        clamp_value();
    }

    void draw() override
    {
        clamp_value();
        imgui_addons::select(this->get_imgui_title(), &this->value_, this->options, disabled_,
                             translate_options_);
    }

    void set(const std::string& string) override
    {
        this->value_ = from_string(string);
        clamp_value();
    }

    std::string get() override
    {
        return to_string(this->value_);
    }

    std::string get_default() override
    {
        return to_string(this->def_);
    }

    [[nodiscard]] int get_value() const
    {
        return this->value_;
    }

    void set_value(const int v)
    {
        this->value_ = v;
        clamp_value();
    }

    std::string get_selected() const
    {
        return {this->options[this->value_]};
    }

    std::vector<const char*> get_options()
    {
        return this->options;
    }

    void set_options(const std::vector<const char*>& opts)
    {
        option_storage_.clear();
        options.clear();
        option_storage_.reserve(opts.size());
        options.reserve(opts.size());
        for (const char* opt : opts)
        {
            option_storage_.emplace_back(opt ? opt : "");
            options.push_back(option_storage_.back().c_str());
        }
        clamp_value();
    }

private:
    int value_;
    int def_;
    std::vector<std::string> option_storage_;
    std::vector<const char*> options;
    bool translate_options_ = true;

    void clamp_value()
    {
        if (options.empty())
        {
            value_ = 0;
            return;
        }
        if (value_ < 0)
            value_ = 0;
        else if (static_cast<size_t>(value_) >= options.size())
            value_ = static_cast<int>(options.size()) - 1;
    }

    static std::string to_string(int v)
    {
        return std::to_string(v);
    }

    static int from_string(const std::string& string)
    {
        return std::stoi(string);
    }
};
