#ifndef ICON_TOGGLE_HPP_
#define ICON_TOGGLE_HPP_

#include <Sound/Sound.hpp>
#include <ToolTip/ToolTip.hpp>
#include <Utilities/StandardLerping.hpp>
#include <functional>

#include <Widget/Widget.hpp>
#include <Material/Material.hpp>
#include <Color/Color.hpp>

/**
 * @brief A widget which shows an icon and sets a variable to a value.
 * 
 * A set of these is typically used on the same variable, with different values,
 * and the user can click one to make a choice. The currently-selected choice
 * is indicated to the user.
 */
template<typename TOption>
class IconToggle : public Widget
{
private:
    static constexpr int margin = 2;

    TOption &currentValue;
    TOption valueToSet;
    Material &icon;

    StandardLerping<glm::vec4> backgroundLerp;
    StandardLerping<glm::vec4> borderLerp;

    std::function<void()> onChanged;
    std::string tooltip;

public:
    IconToggle(
        TOption &currentValue,
        TOption valueToSet,
        Material &icon
    ) :
        currentValue(currentValue),
        valueToSet(valueToSet),
        icon(icon),
        onChanged([](){})
    {}

    IconToggle<TOption>* withChangedCallback(std::function<void()> callback)
    {
        onChanged = callback;
        return this;
    }

    virtual glm::ivec2 getMinSize() override
    {
        return glm::ivec2(icon.width() + 2 * margin, icon.height() + 2 * margin);
    }

    virtual void draw(GraphicsContext &context) override
    {
        glm::vec4 targetBackground = (currentValue == valueToSet) ? Color::selection : Color::widgetBackground;
        context.color = backgroundLerp.sample(targetBackground);
        context.drawRect(0, 0, m_size.x, m_size.y);
        
        context.color = glm::vec4(1.0f);
        context.drawMaterial(icon, margin, margin);

        glm::vec4 borderColor = isMouseInside() ? Color::focused : glm::vec4(0.0f);
        context.color = borderLerp.sample(borderColor);
        context.drawRect(0, 0, 1, m_size.y);
        context.drawRect(m_size.x-1, 0, 1, m_size.y);
        context.drawRect(1, 0, m_size.x-2, 1);
        context.drawRect(1, m_size.y-1, m_size.x-2, 1);

        if (isMouseInside() && !tooltip.empty())
        {
            ToolTip &tip = context.createToolTip();
            tip.addLine(glm::vec4(1.0f), tooltip);
        }
    }

    virtual void onMouseUp(Uint8 button) override
    {
        Widget::onMouseDown(button);

        if (button == SDL_BUTTON_LEFT && isMouseInside())
        {
            Sound::select.play();
            currentValue = valueToSet;
            onChanged();
        }
    }

    /**
     * @brief Set the tool tip text and return this widget.
     */
    IconToggle<TOption>* withToolTip(const std::string &tip)
    {
        tooltip = tip;
        return this;
    }
};

#endif