#include "pch.h"
#include "app.h"
#include "app_core/app_preferences.h"
#include "app_core/brush_ui.h"
#include "app_core/tools_menu.h"
#include "legacy_brush_ui_services.h"
#include "legacy_app_preference_services.h"
#include "legacy_app_shell_services.h"
#include "legacy_preference_storage.h"
#include "legacy_ui_overlay_services.h"
#include "node_button_custom.h"
#include "node_checkbox.h"
#include "node_combobox.h"
#include "node_dialog_picker.h"
#include "node_panel_animation.h"
#include "node_panel_brush.h"
#include "node_panel_color.h"
#include "node_panel_floating.h"
#include "node_panel_grid.h"
#include "node_panel_layer.h"
#include "node_panel_stroke.h"
#include "node_popup_menu.h"

#include <vector>

namespace {

[[nodiscard]] bool should_open_tools_panel(const pp::app::ToolsPanelPlan& plan) noexcept
{
    return plan.action == pp::app::ToolsPanelAction::open_floating_panel;
}

void apply_tools_panel_chrome(NodePanelFloating& panel, const pp::app::ToolsPanelPlan& plan)
{
    if (plan.width > 0 && plan.height > 0) {
        panel.SetSize(static_cast<float>(plan.width), static_cast<float>(plan.height));
    } else {
        if (plan.width > 0)
            panel.SetWidth(static_cast<float>(plan.width));
        if (plan.height > 0)
            panel.SetHeight(static_cast<float>(plan.height));
    }
    if (plan.min_width > 0)
        panel.SetMinWidth(static_cast<float>(plan.min_width));
    if (plan.min_height > 0)
        panel.SetMinHeight(static_cast<float>(plan.min_height));
    panel.m_title->set_text(plan.title.data());
    panel.m_droppable = plan.droppable;
}

std::shared_ptr<NodePopupMenu> add_menu_popup(
    App& app,
    const char* template_id,
    glm::vec2 position,
    float rtl_anchor_width)
{
    const auto popup = pp::panopainter::add_legacy_popup_menu(
        app,
        template_id,
        position.x,
        position.y,
        rtl_anchor_width);
    if (!popup) {
        LOG("Popup menu '%s' failed: %s", template_id ? template_id : "<null>", popup.status().message);
        return nullptr;
    }
    return popup.value();
}

} // namespace

namespace pp::panopainter {

void bind_legacy_tools_menu(App& app)
{
    auto main = app.layout[app.main_id];

    if (auto menu_exp = main->find<NodeButtonCustom>("menu-tools"))
    {
        menu_exp->on_click = [&app, menu_exp, main](Node*) {
            glm::vec2 pos = menu_exp->m_pos + glm::vec2(0, menu_exp->m_size.y);
            auto popup_exp = add_menu_popup(app, "tools-menu", pos, menu_exp->m_size.x);
            if (!popup_exp)
                return;

            if (auto tick = popup_exp->find<NodeButtonCustom>("tools-panels")) tick->on_click = [&app, popup_exp, main](Node* b)
            {
                const auto menu_plan = pp::app::plan_tools_menu_command(pp::app::ToolsMenuCommand::panels);
                if (menu_plan.action != pp::app::ToolsMenuAction::show_panels_submenu)
                    return;

                pp::panopainter::detach_legacy_node_from_parent(*popup_exp);
                const auto popup_exp_overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*main, popup_exp);
                if (!popup_exp_overlay)
                    return;
                const auto popup_exp_handle = popup_exp_overlay.value();

                glm::vec2 pos = b->m_pos + glm::vec2(b->m_size.x, 0);
                auto popup_time = add_menu_popup(app, "panels-menu", pos, b->m_size.x);
                if (!popup_time)
                {
                    close_legacy_overlay_handle_ignoring_status(*main, popup_exp_handle);
                    return;
                }
                pp::panopainter::detach_legacy_node_from_parent(*popup_time);
                const auto popup_time_overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*main, popup_time);
                if (!popup_time_overlay)
                {
                    close_legacy_overlay_handle_ignoring_status(*main, popup_exp_handle);
                    return;
                }
                const auto popup_time_handle = popup_time_overlay.value();

                const auto close_panel_popups = [main, popup_exp_handle, popup_time_handle]()
                {
                    close_legacy_overlay_handle_ignoring_status(*main, popup_exp_handle);
                    close_legacy_overlay_handle_ignoring_status(*main, popup_time_handle);
                };

                auto visible = [&app](Node* panel) {
                    if (!panel)
                        return false;
                    for (auto& c : app.floatings_container->m_children)
                    {
                        if (auto fp = std::static_pointer_cast<NodePanelFloating>(c))
                        {
                            if (fp->m_container->is_child(panel))
                                return true;
                        }
                    }
                    return false;
                };

                popup_time->find<NodeButtonCustom>("panel-presets")->on_click = [&app, close_panel_popups, visible](Node*) {
                    const auto plan = pp::app::plan_tools_panel(
                        pp::app::ToolsPanel::presets,
                        visible(app.floating_presets.get()));
                    if (!should_open_tools_panel(plan))
                        return;
                    auto fpanel = app.floatings_container->add_child<NodePanelFloating>();
                    fpanel->m_class = NodePanelFloating::kClass::Presets;
                    apply_tools_panel_chrome(*fpanel, plan);
                    if (!app.floating_presets)
                    {
                        app.floating_presets = fpanel->m_container->add_child_ref<NodePanelBrushPreset>();
                        app.floating_presets->SetHeightP(100);
                        app.floating_presets->on_brush_changed = [&app](Node*, std::shared_ptr<Brush>& b) {
                            (void)pp::panopainter::apply_legacy_brush_preset_plan(app, b);
                        };
                    }
                    else
                    {
                        fpanel->m_container->add_child(app.floating_presets);
                    }
                    close_panel_popups();
                };

                popup_time->find<NodeButtonCustom>("panel-color")->on_click = [&app, close_panel_popups, visible](Node*) {
                    const auto plan = pp::app::plan_tools_panel(
                        pp::app::ToolsPanel::color,
                        visible(app.floating_color.get()));
                    if (!should_open_tools_panel(plan))
                        return;
                    auto fpanel = app.floatings_container->add_child<NodePanelFloating>();
                    fpanel->m_class = NodePanelFloating::kClass::Color;
                    apply_tools_panel_chrome(*fpanel, plan);
                    if (!app.floating_color)
                    {
                        app.floating_color = fpanel->m_container->add_child_ref<NodePanelColor>();
                        app.floating_color->SetHeightP(100);
                        if (plan.hides_embedded_title)
                            app.floating_color->find("title")->SetVisibility(false);
                        app.floating_color->on_color_changed = [&app](Node*, glm::vec4 color) {
                            (void)pp::panopainter::apply_legacy_brush_color_plan(app, color, false, false);
                        };
                    }
                    else
                    {
                        fpanel->m_container->add_child(app.floating_color);
                    }
                    close_panel_popups();
                };
                popup_time->find<NodeButtonCustom>("panel-color-adv")->on_click = [&app, close_panel_popups, visible](Node*) {
                    const auto plan = pp::app::plan_tools_panel(
                        pp::app::ToolsPanel::color_advanced,
                        visible(app.floating_picker.get()));
                    if (!should_open_tools_panel(plan))
                        return;
                    auto fpanel = app.floatings_container->add_child<NodePanelFloating>();
                    fpanel->m_class = NodePanelFloating::kClass::ColorAdv;
                    apply_tools_panel_chrome(*fpanel, plan);
                    if (!app.floating_picker)
                    {
                        app.floating_picker = fpanel->m_container->add_child_ref<NodeColorPicker>();
                        app.floating_picker->m_autohide = false;
                        app.floating_picker->on_color_change = [&app](Node*, glm::vec3 color) {
                            (void)pp::panopainter::apply_legacy_brush_color_plan(app, glm::vec4(color, 1.f), false, false);
                        };
                    }
                    else
                    {
                        fpanel->m_container->add_child(app.floating_picker);
                    }
                    close_panel_popups();
                };
                popup_time->find<NodeButtonCustom>("panel-layers")->on_click = [&app, close_panel_popups, visible](Node*) {
                    const auto plan = pp::app::plan_tools_panel(
                        pp::app::ToolsPanel::layers,
                        visible(app.layers.get()));
                    if (!should_open_tools_panel(plan))
                        return;
                    auto fpanel = app.floatings_container->add_child<NodePanelFloating>();
                    fpanel->m_class = NodePanelFloating::kClass::Layers;
                    apply_tools_panel_chrome(*fpanel, plan);
                    fpanel->m_container->add_child(app.layers);
                    app.layers->SetPositioning(YGPositionTypeRelative);
                    app.layers->SetPosition(0, 0);
                    app.layers->SetWidthP(100);
                    app.layers->SetHeightP(100);
                    app.layers->SetFlexShrink(0);
                    if (plan.hides_embedded_title)
                        app.layers->find("title")->SetVisibility(false);

                    close_panel_popups();
                };
                popup_time->find<NodeButtonCustom>("panel-brush")->on_click = [&app, close_panel_popups, visible](Node*) {
                    const auto plan = pp::app::plan_tools_panel(
                        pp::app::ToolsPanel::brush,
                        visible(app.stroke.get()));
                    if (!should_open_tools_panel(plan))
                        return;
                    auto fpanel = app.floatings_container->add_child<NodePanelFloating>();
                    fpanel->m_class = NodePanelFloating::kClass::Brush;
                    fpanel->m_container->add_child(app.stroke);
                    apply_tools_panel_chrome(*fpanel, plan);
                    app.stroke->SetPositioning(YGPositionTypeRelative);
                    app.stroke->SetPosition(0, 0);
                    app.stroke->SetWidthP(100);
                    app.stroke->SetHeightP(100);
                    if (plan.hides_embedded_title)
                        app.stroke->find("title")->SetVisibility(false);

                    close_panel_popups();
                };
                popup_time->find<NodeButtonCustom>("panel-grids")->on_click = [&app, close_panel_popups, visible](Node*) {
                    const auto plan = pp::app::plan_tools_panel(
                        pp::app::ToolsPanel::grids,
                        visible(app.grid.get()));
                    if (!should_open_tools_panel(plan))
                        return;
                    auto fpanel = app.floatings_container->add_child<NodePanelFloating>();
                    fpanel->m_class = NodePanelFloating::kClass::Grids;
                    fpanel->m_container->add_child(app.grid);
                    apply_tools_panel_chrome(*fpanel, plan);
                    app.grid->SetPositioning(YGPositionTypeRelative);
                    app.grid->SetPosition(0, 0);
                    app.grid->SetWidthP(100);
                    app.grid->SetHeightP(100);
                    if (plan.hides_embedded_title)
                        app.grid->find("title")->SetVisibility(false);

                    close_panel_popups();
                };
                popup_time->find<NodeButtonCustom>("panel-animation")->on_click = [&app, close_panel_popups, visible](Node*) {
                    const auto plan = pp::app::plan_tools_panel(
                        pp::app::ToolsPanel::animation,
                        visible(app.animation.get()));
                    if (!should_open_tools_panel(plan))
                        return;
                    auto fpanel = app.floatings_container->add_child<NodePanelFloating>();
                    fpanel->m_class = NodePanelFloating::kClass::Animation;
                    fpanel->m_container->add_child(app.animation);
                    apply_tools_panel_chrome(*fpanel, plan);
                    app.animation->SetPositioning(YGPositionTypeRelative);
                    app.animation->SetPosition(0, 0);
                    app.animation->SetWidthP(100);
                    app.animation->SetHeightP(100);

                    close_panel_popups();
                };
            };

            if (auto options = popup_exp->find<NodeButtonCustom>("tools-options")) options->on_click = [&app, options, main](Node* b)
            {
                const auto menu_plan = pp::app::plan_tools_menu_command(pp::app::ToolsMenuCommand::options);
                if (menu_plan.action != pp::app::ToolsMenuAction::show_options_submenu)
                    return;

                glm::vec2 pos = b->m_pos + glm::vec2(b->m_size.x, 0);
                auto popup_time = add_menu_popup(app, "options-menu", pos, b->m_size.x);
                if (!popup_time)
                    return;

                if (auto ui_scale = popup_time->find<NodeComboBox>("tools-ui-scale"))
                {
                    std::vector<float> scale_options;
                    scale_options.reserve(ui_scale->m_data.size());
                    for (int i = 0; i < ui_scale->m_data.size(); i++)
                        scale_options.push_back(ui_scale->get_float(i));

                    const auto selection = pp::app::plan_scale_option_selection(App::I->zoom, scale_options);
                    if (selection.has_selection)
                        ui_scale->set_index(static_cast<int>(selection.index));

                    ui_scale->on_select = [ui_scale](Node*, int index)
                    {
                        const auto status = pp::panopainter::execute_legacy_ui_scale_preference(
                            *App::I,
                            ui_scale->get_float(index));
                        if (!status.ok())
                            LOG("UI scale preference failed: %s", status.message);
                    };
                }

                if (auto vp_scale = popup_time->find<NodeComboBox>("tools-vp-scale"))
                {
                    std::vector<float> scale_options;
                    scale_options.reserve(vp_scale->m_data.size());
                    for (int i = 0; i < vp_scale->m_data.size(); i++)
                        scale_options.push_back(vp_scale->get_float(i));

                    const auto selection = pp::app::plan_scale_option_selection(App::I->canvas->m_density, scale_options);
                    if (selection.has_selection)
                        vp_scale->set_index(static_cast<int>(selection.index));

                    vp_scale->on_select = [vp_scale](Node*, int index)
                    {
                        const auto status = pp::panopainter::execute_legacy_viewport_scale_preference(
                            *App::I,
                            vp_scale->get_float(index));
                        if (!status.ok())
                            LOG("Viewport scale preference failed: %s", status.message);
                    };
                }

                if (auto rtl_btn = popup_time->find<NodeButtonCustom>("tools-rtl"))
                {
                    NodeCheckBox* cb = rtl_btn->find<NodeCheckBox>("tools-rtl-check");
                    cb->set_value(app.ui_rtl, false);

                    rtl_btn->on_click = [rtl_btn](Node*)
                    {
                        NodeCheckBox* cb = rtl_btn->find<NodeCheckBox>("tools-rtl-check");
                        cb->set_value(!cb->checked, true);
                    };
                
                    rtl_btn->find<NodeCheckBox>("tools-rtl-check")->on_value_changed = [&app](Node*, bool checked)
                    {
                        const auto status = pp::panopainter::execute_legacy_interface_direction_preference(
                            app,
                            checked);
                        if (!status.ok())
                            LOG("Interface direction preference failed: %s", status.message);
                    };
                }

                if (auto vr_btn = popup_time->find<NodeButtonCustom>("tools-vr"))
                {
                    NodeCheckBox* cb = vr_btn->find<NodeCheckBox>("tools-vr-check");
                    cb->set_value(app.vr_session_snapshot().has_vr);

                    vr_btn->on_click = [vr_btn](Node*)
                    {
                        NodeCheckBox* cb = vr_btn->find<NodeCheckBox>("tools-vr-check");
                        cb->set_value(!cb->checked, true);
                    };

                    vr_btn->find<NodeCheckBox>("tools-vr-check")->on_value_changed = [&app](Node* target, bool checked)
                    {
                        const auto status = pp::panopainter::execute_legacy_vr_mode_preference(
                            app,
                            checked);
                        if (!status.ok()) {
                            auto cb = static_cast<NodeCheckBox*>(target);
                            cb->set_value(false);
                            app.message_box("VR Failed", "Couldn't start Virtual Reality mode");
                        }
                    };
                }

                if (auto vr_btn = popup_time->find<NodeButtonCustom>("tools-vr-controllers"))
                {
                    NodeCheckBox* cb = vr_btn->find<NodeCheckBox>("tools-vr-controllers-check");
                    cb->set_value(app.vr_controllers_enabled);

                    vr_btn->on_click = [vr_btn](Node*)
                    {
                        NodeCheckBox* cb = vr_btn->find<NodeCheckBox>("tools-vr-controllers-check");
                        cb->set_value(!cb->checked, true);
                    };

                    vr_btn->find<NodeCheckBox>("tools-vr-controllers-check")->on_value_changed = [&app](Node*, bool checked)
                    {
                        const auto status = pp::panopainter::execute_legacy_vr_controllers_preference(
                            app,
                            checked);
                        if (!status.ok())
                            LOG("VR controllers preference failed: %s", status.message);
                    };
                }

                if (auto btn = popup_time->find<NodeButtonCustom>("tools-timelapse"))
                {
                    NodeCheckBox* cb = btn->find<NodeCheckBox>("tools-timelapse-check");
                    cb->set_value(
                        pp::panopainter::read_legacy_startup_preferences(app.vr_controllers_enabled).auto_timelapse,
                        false);

                    btn->on_click = [btn](Node*)
                    {
                        NodeCheckBox* cb = btn->find<NodeCheckBox>("tools-timelapse-check");
                        cb->set_value(!cb->checked, true);
                    };

                    btn->find<NodeCheckBox>("tools-timelapse-check")->on_value_changed = [&app](Node*, bool checked)
                    {
                        const auto status = pp::panopainter::execute_legacy_timelapse_preference(
                            app,
                            checked);
                        if (!status.ok())
                            LOG("Timelapse preference failed: %s", status.message);
                    };
                }

                if (auto mode = popup_time->find<NodeComboBox>("tools-show-cursor"))
                {
                    mode->set_index(pp::panopainter::read_legacy_canvas_preferences().cursor_mode);

                    mode->on_select = [](Node*, int index)
                    {
                        const auto status = pp::panopainter::execute_legacy_canvas_cursor_mode_preference(
                            *App::I,
                            index);
                        if (!status.ok())
                            LOG("Cursor mode preference failed: %s", status.message);
                    };
                }
            };

            popup_exp->find<NodeButtonCustom>("clear-grids")->on_click = [&app, popup_exp](Node*) {
                auto popup_exp_overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*popup_exp->root(), popup_exp);
                if (!popup_exp_overlay)
                    return;
                const auto popup_exp_handle = popup_exp_overlay.value();
                const auto plan = pp::app::plan_tools_menu_command(pp::app::ToolsMenuCommand::clear_grids);
                pp::panopainter::execute_legacy_tools_menu_plan(app, plan);
                if (plan.closes_root_popup)
                {
                    close_legacy_overlay_handle_ignoring_status(*popup_exp->root(), popup_exp_handle);
                }
            };

            popup_exp->find<NodeButtonCustom>("camera-reset")->on_click = [&app, popup_exp](Node*) {
                auto popup_exp_overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*popup_exp->root(), popup_exp);
                if (!popup_exp_overlay)
                    return;
                const auto popup_exp_handle = popup_exp_overlay.value();
                const auto plan = pp::app::plan_tools_menu_command(pp::app::ToolsMenuCommand::reset_camera);
                pp::panopainter::execute_legacy_tools_menu_plan(app, plan);
                if (plan.closes_root_popup)
                {
                    close_legacy_overlay_handle_ignoring_status(*popup_exp->root(), popup_exp_handle);
                }
            };

            popup_exp->find<NodeButtonCustom>("shortcuts")->on_click = [&app, popup_exp](Node*) {
                auto popup_exp_overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*popup_exp->root(), popup_exp);
                if (!popup_exp_overlay)
                    return;
                const auto popup_exp_handle = popup_exp_overlay.value();
                const auto plan = pp::app::plan_tools_menu_command(pp::app::ToolsMenuCommand::shortcuts);
                pp::panopainter::execute_legacy_tools_menu_plan(app, plan);
                if (plan.closes_root_popup)
                {
                    close_legacy_overlay_handle_ignoring_status(*popup_exp->root(), popup_exp_handle);
                }
            };

/*
            popup_exp->find<NodeButtonCustom>("mp4test")->on_click = [this, popup_exp](Node*) {
                dialog_export_mp4();
                pp::panopainter::close_legacy_popup_overlay(*popup_exp);
            };
*/

            if (app.platform_supports_sonarpen())
            {
                popup_exp->find<NodeButtonCustom>("sonarpen")->on_click = [&app, popup_exp](Node*) {
                    auto popup_exp_overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*popup_exp->root(), popup_exp);
                    if (!popup_exp_overlay)
                        return;
                    const auto popup_exp_handle = popup_exp_overlay.value();
                    const auto plan = pp::app::plan_tools_menu_command(
                        pp::app::ToolsMenuCommand::sonarpen,
                        app.platform_supports_sonarpen());
                    pp::panopainter::execute_legacy_tools_menu_plan(app, plan);
                    if (plan.closes_root_popup)
                    {
                        close_legacy_overlay_handle_ignoring_status(*popup_exp->root(), popup_exp_handle);
                    }
                };
            }
        };
    }
}

} // namespace pp::panopainter
