#pragma once

#include "app_core/app_dialog.h"
#include "app_core/document_canvas.h"
#include "app_core/history_ui.h"
#include "foundation/result.h"

#include <string>

namespace pp::app {

enum class MainToolbarCommand {
    open_document,
    save_document,
    undo,
    redo,
    clear_history,
    clear_canvas,
    show_message_box,
    show_settings,
};

enum class MainToolbarAction {
    show_open_dialog,
    show_save_dialog,
    invoke_undo,
    invoke_redo,
    clear_history,
    clear_canvas,
    show_message_box,
    show_settings_dialog,
    no_op_unavailable,
};

struct MainToolbarPlan {
    MainToolbarCommand command = MainToolbarCommand::open_document;
    MainToolbarAction action = MainToolbarAction::show_open_dialog;
    std::string label;
    bool requires_canvas = false;
    bool updates_memory_label = false;
    bool updates_title = false;
    bool records_undo = false;
    bool marks_unsaved = false;
    bool no_op = false;
    HistoryUiPlan history;
    DocumentCanvasClearPlan canvas_clear;
};

class MainToolbarServices {
public:
    virtual ~MainToolbarServices() = default;

    virtual void show_open_dialog() = 0;
    virtual void show_save_dialog() = 0;
    virtual void invoke_undo(const HistoryUiPlan& plan) = 0;
    virtual void invoke_redo(const HistoryUiPlan& plan) = 0;
    virtual void clear_history(const HistoryUiPlan& plan) = 0;
    virtual void clear_canvas(const DocumentCanvasClearPlan& plan) = 0;
    virtual void show_message_box() = 0;
    virtual void show_settings_dialog() = 0;
};

[[nodiscard]] inline AppMessageDialogPlan plan_main_toolbar_message_dialog()
{
    return plan_app_message_dialog(
        "Just a test message",
        "Longer description for the error or the message.",
        true);
}

[[nodiscard]] inline pp::foundation::Result<MainToolbarPlan> plan_main_toolbar_command(
    MainToolbarCommand command,
    int undo_count = 0,
    int redo_count = 0,
    int memory_bytes = 0,
    bool has_canvas = true)
{
    MainToolbarPlan plan;
    plan.command = command;

    switch (command) {
    case MainToolbarCommand::open_document:
        plan.action = MainToolbarAction::show_open_dialog;
        plan.label = "Open";
        return pp::foundation::Result<MainToolbarPlan>::success(plan);

    case MainToolbarCommand::save_document:
        plan.action = MainToolbarAction::show_save_dialog;
        plan.label = "Save";
        return pp::foundation::Result<MainToolbarPlan>::success(plan);

    case MainToolbarCommand::undo:
    {
        const auto history = plan_history_undo(undo_count);
        if (!history) {
            return pp::foundation::Result<MainToolbarPlan>::failure(history.status());
        }
        plan.action = history.value().invokes_undo
            ? MainToolbarAction::invoke_undo
            : MainToolbarAction::no_op_unavailable;
        plan.label = history.value().invokes_undo ? "Undo" : "Undo (No history)";
        plan.updates_memory_label = history.value().updates_memory_label;
        plan.updates_title = history.value().updates_title;
        plan.no_op = history.value().no_op;
        plan.history = history.value();
        return pp::foundation::Result<MainToolbarPlan>::success(plan);
    }

    case MainToolbarCommand::redo:
    {
        const auto history = plan_history_redo(redo_count);
        if (!history) {
            return pp::foundation::Result<MainToolbarPlan>::failure(history.status());
        }
        plan.action = history.value().invokes_redo
            ? MainToolbarAction::invoke_redo
            : MainToolbarAction::no_op_unavailable;
        plan.label = history.value().invokes_redo ? "Redo" : "Redo (No history)";
        plan.updates_memory_label = history.value().updates_memory_label;
        plan.updates_title = history.value().updates_title;
        plan.no_op = history.value().no_op;
        plan.history = history.value();
        return pp::foundation::Result<MainToolbarPlan>::success(plan);
    }

    case MainToolbarCommand::clear_history:
    {
        const auto history = plan_history_clear(undo_count, redo_count, memory_bytes);
        if (!history) {
            return pp::foundation::Result<MainToolbarPlan>::failure(history.status());
        }
        plan.action = history.value().clears_history
            ? MainToolbarAction::clear_history
            : MainToolbarAction::no_op_unavailable;
        plan.label = history.value().clears_history ? "Clear History" : "Clear History (Empty)";
        plan.updates_memory_label = history.value().updates_memory_label;
        plan.no_op = history.value().no_op;
        plan.history = history.value();
        return pp::foundation::Result<MainToolbarPlan>::success(plan);
    }

    case MainToolbarCommand::clear_canvas:
    {
        const auto clear = plan_document_canvas_clear(has_canvas);
        if (!clear) {
            return pp::foundation::Result<MainToolbarPlan>::failure(clear.status());
        }
        plan.action = clear.value().clears_canvas
            ? MainToolbarAction::clear_canvas
            : MainToolbarAction::no_op_unavailable;
        plan.label = clear.value().clears_canvas ? "Clear Canvas" : "Clear Canvas (No canvas)";
        plan.requires_canvas = true;
        plan.records_undo = clear.value().records_undo;
        plan.marks_unsaved = clear.value().marks_unsaved;
        plan.no_op = clear.value().no_op;
        plan.canvas_clear = clear.value();
        return pp::foundation::Result<MainToolbarPlan>::success(plan);
    }

    case MainToolbarCommand::show_message_box:
        plan.action = MainToolbarAction::show_message_box;
        plan.label = "Show Message Box";
        return pp::foundation::Result<MainToolbarPlan>::success(plan);

    case MainToolbarCommand::show_settings:
        plan.action = MainToolbarAction::show_settings_dialog;
        plan.label = "Settings";
        return pp::foundation::Result<MainToolbarPlan>::success(plan);
    }

    return pp::foundation::Result<MainToolbarPlan>::failure(
        pp::foundation::Status::invalid_argument("unknown main toolbar command"));
}

[[nodiscard]] inline pp::foundation::Status execute_main_toolbar_plan(
    const MainToolbarPlan& plan,
    MainToolbarServices& services)
{
    switch (plan.action) {
    case MainToolbarAction::show_open_dialog:
        services.show_open_dialog();
        return pp::foundation::Status::success();
    case MainToolbarAction::show_save_dialog:
        services.show_save_dialog();
        return pp::foundation::Status::success();
    case MainToolbarAction::invoke_undo:
        services.invoke_undo(plan.history);
        return pp::foundation::Status::success();
    case MainToolbarAction::invoke_redo:
        services.invoke_redo(plan.history);
        return pp::foundation::Status::success();
    case MainToolbarAction::clear_history:
        services.clear_history(plan.history);
        return pp::foundation::Status::success();
    case MainToolbarAction::clear_canvas:
        services.clear_canvas(plan.canvas_clear);
        return pp::foundation::Status::success();
    case MainToolbarAction::show_message_box:
        services.show_message_box();
        return pp::foundation::Status::success();
    case MainToolbarAction::show_settings_dialog:
        services.show_settings_dialog();
        return pp::foundation::Status::success();
    case MainToolbarAction::no_op_unavailable:
        return pp::foundation::Status::success();
    }

    return pp::foundation::Status::invalid_argument("unknown main toolbar action");
}

} // namespace pp::app
