#include "app_core/file_menu.h"
#include "test_harness.h"

namespace {

class FakeFileMenuServices final : public pp::app::FileMenuServices {
public:
    void show_new_document_dialog() override { new_document_dialogs += 1; }
    void pick_image_for_import() override { image_picks += 1; }
    void pick_project_file() override { project_picks += 1; }
    void show_cloud_browser_dialog() override { cloud_browser_dialogs += 1; }
    void save_document(pp::app::DocumentSaveIntent intent) override
    {
        save_calls += 1;
        last_save_intent = intent;
    }
    void show_export_jpeg_dialog(pp::app::DocumentExportMenuKind kind) override
    {
        export_jpeg_dialogs += 1;
        last_export_kind = kind;
    }
    void show_export_submenu() override { export_submenus += 1; }
    void share_document() override { share_calls += 1; }
    void show_resize_dialog() override { resize_dialogs += 1; }
    void upload_to_cloud() override { cloud_uploads += 1; }
    void browse_cloud_documents() override { cloud_browses += 1; }

    int new_document_dialogs = 0;
    int image_picks = 0;
    int project_picks = 0;
    int cloud_browser_dialogs = 0;
    int save_calls = 0;
    int export_jpeg_dialogs = 0;
    int export_submenus = 0;
    int share_calls = 0;
    int resize_dialogs = 0;
    int cloud_uploads = 0;
    int cloud_browses = 0;
    pp::app::DocumentSaveIntent last_save_intent = pp::app::DocumentSaveIntent::save;
    pp::app::DocumentExportMenuKind last_export_kind = pp::app::DocumentExportMenuKind::jpeg;
};

void file_menu_routes_document_creation_and_opening(pp::tests::Harness& harness)
{
    const auto new_doc = pp::app::plan_file_menu_command(pp::app::FileMenuCommand::new_document);
    const auto open = pp::app::plan_file_menu_command(pp::app::FileMenuCommand::open_project);
    const auto import = pp::app::plan_file_menu_command(pp::app::FileMenuCommand::import_image);

    PP_EXPECT(harness, new_doc.action == pp::app::FileMenuAction::show_new_document_dialog);
    PP_EXPECT(harness, open.action == pp::app::FileMenuAction::pick_project_file);
    PP_EXPECT(harness, import.action == pp::app::FileMenuAction::pick_image_for_import);
}

void file_menu_preserves_save_intents(pp::tests::Harness& harness)
{
    const auto save = pp::app::plan_file_menu_command(pp::app::FileMenuCommand::save);
    const auto save_as = pp::app::plan_file_menu_command(pp::app::FileMenuCommand::save_as);
    const auto save_version = pp::app::plan_file_menu_command(pp::app::FileMenuCommand::save_version);

    PP_EXPECT(harness, save.action == pp::app::FileMenuAction::save_document);
    PP_EXPECT(harness, save.save_intent == pp::app::DocumentSaveIntent::save);
    PP_EXPECT(harness, save_as.save_intent == pp::app::DocumentSaveIntent::save_as);
    PP_EXPECT(harness, save_version.save_intent == pp::app::DocumentSaveIntent::save_version);
}

void file_menu_routes_export_and_cloud_actions(pp::tests::Harness& harness)
{
    const auto jpeg = pp::app::plan_file_menu_command(pp::app::FileMenuCommand::export_jpeg);
    const auto submenu = pp::app::plan_file_menu_command(pp::app::FileMenuCommand::export_submenu);
    const auto upload = pp::app::plan_file_menu_command(pp::app::FileMenuCommand::cloud_upload);
    const auto browse = pp::app::plan_file_menu_command(pp::app::FileMenuCommand::cloud_browse);

    PP_EXPECT(harness, jpeg.action == pp::app::FileMenuAction::show_export_jpeg_dialog);
    PP_EXPECT(harness, jpeg.export_kind == pp::app::DocumentExportMenuKind::jpeg);
    PP_EXPECT(harness, submenu.action == pp::app::FileMenuAction::show_export_submenu);
    PP_EXPECT(harness, upload.action == pp::app::FileMenuAction::upload_to_cloud);
    PP_EXPECT(harness, browse.action == pp::app::FileMenuAction::browse_cloud_documents);
}

void file_menu_parser_accepts_legacy_button_names(pp::tests::Harness& harness)
{
    const auto export_jpeg = pp::app::parse_file_menu_command("export");
    const auto cloud_upload = pp::app::parse_file_menu_command("cloud-upload");
    const auto invalid = pp::app::parse_file_menu_command("not-a-command");

    PP_EXPECT(harness, export_jpeg);
    if (export_jpeg) {
        PP_EXPECT(harness, export_jpeg.value() == pp::app::FileMenuCommand::export_jpeg);
    }
    PP_EXPECT(harness, cloud_upload);
    if (cloud_upload) {
        PP_EXPECT(harness, cloud_upload.value() == pp::app::FileMenuCommand::cloud_upload);
    }
    PP_EXPECT(harness, !invalid);
}

void file_menu_executor_dispatches_dialog_picker_and_document_actions(pp::tests::Harness& harness)
{
    FakeFileMenuServices services;

    PP_EXPECT(
        harness,
        pp::app::execute_file_menu_plan(
            pp::app::plan_file_menu_command(pp::app::FileMenuCommand::new_document),
            services).ok());
    PP_EXPECT(harness, services.new_document_dialogs == 1);

    PP_EXPECT(
        harness,
        pp::app::execute_file_menu_plan(
            pp::app::plan_file_menu_command(pp::app::FileMenuCommand::import_image),
            services).ok());
    PP_EXPECT(harness, services.image_picks == 1);

    PP_EXPECT(
        harness,
        pp::app::execute_file_menu_plan(
            pp::app::plan_file_menu_command(pp::app::FileMenuCommand::open_project),
            services).ok());
    PP_EXPECT(harness, services.project_picks == 1);

    PP_EXPECT(
        harness,
        pp::app::execute_file_menu_plan(
            pp::app::plan_file_menu_command(pp::app::FileMenuCommand::save_as),
            services).ok());
    PP_EXPECT(harness, services.save_calls == 1);
    PP_EXPECT(harness, services.last_save_intent == pp::app::DocumentSaveIntent::save_as);

    PP_EXPECT(
        harness,
        pp::app::execute_file_menu_plan(
            pp::app::plan_file_menu_command(pp::app::FileMenuCommand::share),
            services).ok());
    PP_EXPECT(harness, services.share_calls == 1);

    PP_EXPECT(
        harness,
        pp::app::execute_file_menu_plan(
            pp::app::plan_file_menu_command(pp::app::FileMenuCommand::resize),
            services).ok());
    PP_EXPECT(harness, services.resize_dialogs == 1);
}

void file_menu_executor_dispatches_export_and_cloud_actions(pp::tests::Harness& harness)
{
    FakeFileMenuServices services;

    PP_EXPECT(
        harness,
        pp::app::execute_file_menu_plan(
            pp::app::plan_file_menu_command(pp::app::FileMenuCommand::export_jpeg),
            services).ok());
    PP_EXPECT(harness, services.export_jpeg_dialogs == 1);
    PP_EXPECT(harness, services.last_export_kind == pp::app::DocumentExportMenuKind::jpeg);

    PP_EXPECT(
        harness,
        pp::app::execute_file_menu_plan(
            pp::app::plan_file_menu_command(pp::app::FileMenuCommand::export_submenu),
            services).ok());
    PP_EXPECT(harness, services.export_submenus == 1);

    PP_EXPECT(
        harness,
        pp::app::execute_file_menu_plan(
            pp::app::plan_file_menu_command(pp::app::FileMenuCommand::browse_cloud),
            services).ok());
    PP_EXPECT(harness, services.cloud_browser_dialogs == 1);

    PP_EXPECT(
        harness,
        pp::app::execute_file_menu_plan(
            pp::app::plan_file_menu_command(pp::app::FileMenuCommand::cloud_upload),
            services).ok());
    PP_EXPECT(harness, services.cloud_uploads == 1);

    PP_EXPECT(
        harness,
        pp::app::execute_file_menu_plan(
            pp::app::plan_file_menu_command(pp::app::FileMenuCommand::cloud_browse),
            services).ok());
    PP_EXPECT(harness, services.cloud_browses == 1);
}

}

int main()
{
    pp::tests::Harness harness;
    harness.run("file menu routes document creation and opening", file_menu_routes_document_creation_and_opening);
    harness.run("file menu preserves save intents", file_menu_preserves_save_intents);
    harness.run("file menu routes export and cloud actions", file_menu_routes_export_and_cloud_actions);
    harness.run("file menu parser accepts legacy button names", file_menu_parser_accepts_legacy_button_names);
    harness.run(
        "file menu executor dispatches dialog picker and document actions",
        file_menu_executor_dispatches_dialog_picker_and_document_actions);
    harness.run(
        "file menu executor dispatches export and cloud actions",
        file_menu_executor_dispatches_export_and_cloud_actions);
    return harness.finish();
}
