#pragma once

#include <algorithm>
#include <string>
#include <vector>

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

class LanguageSelectValue : public ConfigValue
{
public:
    LanguageSelectValue(const int initial, const std::string& n)
        : ConfigValue(n), value_(initial), def_(initial)
    {
    }

    void draw() override
    {
        clamp_value();

        const float sf = menu::get_scale_factor();
        ImGui::PushID(get_imgui_title().c_str());
        const std::string combo_label = i18n::tr(imgui_addons::label_text(get_imgui_title()));
        ImGui::AlignTextToFramePadding();
        ImGui::TextColored(disabled_ ? menu::with_alpha(menu::palette::muted, 0.7f) : menu::palette::txt,
                           "%s", combo_label.c_str());

        const float w = (std::min)(230.f * sf, ImGui::GetContentRegionAvail().x * 0.62f);
        imgui_addons::right_align(w);
        if (disabled_)
            ImGui::BeginDisabled();

        const char* preview = labels_.empty() ? "" : labels_[static_cast<size_t>(value_)].c_str();
        if (ImGui::BeginCombo("##lang", preview))
        {
            for (int i = 0; i < static_cast<int>(labels_.size()); ++i)
            {
                const bool selected = value_ == i;
                if (ImGui::Selectable(labels_[static_cast<size_t>(i)].c_str(), selected))
                    value_ = i;
                if (selected)
                    ImGui::SetItemDefaultFocus();
            }
            ImGui::EndCombo();
        }

        if (disabled_)
            ImGui::EndDisabled();
        ImGui::Dummy(ImVec2(0, 3.f * sf));
        ImGui::PopID();
    }

    void rebuild_labels()
    {
        labels_.clear();
        locale_codes_.clear();
        for (const i18n::language_entry& entry : i18n::available_languages())
        {
            locale_codes_.push_back(entry.code);
            labels_.push_back(i18n::tr(entry.display_name));
        }
        clamp_value();
    }

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

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

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

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

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

    [[nodiscard]] size_t option_count() const
    {
        return labels_.size();
    }

private:
    int value_;
    int def_;
    std::vector<std::string> labels_;
    std::vector<std::string> locale_codes_;

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

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

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