#include "ui_toggle.h"

#include <cassert>

namespace recompui {

    Toggle::Toggle(Element *parent) : Element(parent, Events(EventType::Click, EventType::Hover, EventType::Enable), "button") {
        set_width(162.0f);
        set_height(72.0f);
        set_border_radius(36.0f);
        set_opacity(0.9f);
        set_cursor(Cursor::Pointer);
        set_border_width(2.0f);
        set_border_color(Color{ 177, 76, 34, 255 });
        set_background_color(Color{ 0, 0, 0, 0 });
        checked_style.set_border_color(Color{ 34, 177, 76, 255 });
        hover_style.set_border_color(Color{ 177, 76, 34, 255 });
        hover_style.set_background_color(Color{ 206, 120, 68, 76 });
        checked_hover_style.set_border_color(Color{ 34, 177, 76, 255 });
        checked_hover_style.set_background_color(Color{ 68, 206, 120, 76 });
        disabled_style.set_border_color(Color{ 177, 76, 34, 128 });
        checked_disabled_style.set_border_color(Color{ 34, 177, 76, 128 });
        add_style(&checked_style, checked_state);
        add_style(&hover_style, hover_state);
        add_style(&checked_hover_style, { checked_state, hover_state });
        add_style(&disabled_style, disabled_state);
        add_style(&checked_disabled_style, { checked_state, disabled_state });

        ContextId context = get_current_context();

        floater = context.create_element<Element>(this);
        floater->set_position(Position::Relative);
        floater->set_top(2.0f);
        floater->set_width(80.0f);
        floater->set_height(64.0f);
        floater->set_border_radius(32.0f);
        floater->set_background_color(Color{ 177, 76, 34, 255 });
        floater_checked_style.set_background_color(Color{ 34, 177, 76, 255 });
        floater_disabled_style.set_background_color(Color{ 177, 76, 34, 128 });
        floater_disabled_checked_style.set_background_color(Color{ 34, 177, 76, 128 });
        floater->add_style(&floater_checked_style, checked_state);
        floater->add_style(&floater_disabled_style, disabled_state);
        floater->add_style(&floater_disabled_checked_style, { checked_state, disabled_state });

        set_checked_internal(false, false, true, false);
    }

    void Toggle::set_checked_internal(bool checked, bool animate, bool setup, bool trigger_callbacks) {
        if (this->checked != checked || setup) {
            this->checked = checked;

            floater->set_left(floater_left_target(), Unit::Dp, animate ? Animation::tween(0.1f) : Animation::set());

            if (trigger_callbacks) {
                for (const auto &function : checked_callbacks) {
                    function(checked);
                }
            }

            set_style_enabled(checked_state, checked);
            floater->set_style_enabled(checked_state, checked);
        }
    }

    float Toggle::floater_left_target() const {
        return checked ? 4.0f : 78.0f;
    }

    void Toggle::process_event(const Event &e) {
        switch (e.type) {
        case EventType::Click:
            if (is_enabled()) {
                set_checked_internal(!checked, true, false, true);
            }

            break;
        case EventType::Hover: {
            bool hover_active = std::get<EventHover>(e.variant).active;
            set_style_enabled(hover_state, hover_active);
            floater->set_style_enabled(hover_state, hover_active);
            break;
        }
        case EventType::Enable: {
            bool enable_active = std::get<EventEnable>(e.variant).active;
            set_style_enabled(disabled_state, !enable_active);
            floater->set_style_enabled(disabled_state, !enable_active);
            break;
        }
        default:
            assert(false && "Unknown event type.");
            break;
        }
    }

    void Toggle::set_checked(bool checked) {
        set_checked_internal(checked, false, false, false);
    }

    bool Toggle::is_checked() const {
        return checked;
    }

    void Toggle::add_checked_callback(std::function<void(bool)> callback) {
        checked_callbacks.emplace_back(callback);
    }
};