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

namespace {

class FakeDocumentExportMenuServices final : public pp::app::DocumentExportMenuServices {
public:
    void show_jpeg_dialog() override { jpeg_dialogs += 1; }
    void show_png_dialog() override { png_dialogs += 1; }
    void show_layers_dialog() override { layer_dialogs += 1; }
    void show_cube_faces_dialog() override { cube_dialogs += 1; }
    void show_depth_dialog() override { depth_dialogs += 1; }
    void show_animation_frames_dialog() override { animation_frame_dialogs += 1; }
    void show_animation_mp4_dialog() override { animation_mp4_dialogs += 1; }
    void show_timelapse_dialog() override { timelapse_dialogs += 1; }
    void show_license_disabled() override { license_messages += 1; }

    [[nodiscard]] int total_calls() const noexcept
    {
        return jpeg_dialogs + png_dialogs + layer_dialogs + cube_dialogs + depth_dialogs
            + animation_frame_dialogs + animation_mp4_dialogs + timelapse_dialogs
            + license_messages;
    }

    int jpeg_dialogs = 0;
    int png_dialogs = 0;
    int layer_dialogs = 0;
    int cube_dialogs = 0;
    int depth_dialogs = 0;
    int animation_frame_dialogs = 0;
    int animation_mp4_dialogs = 0;
    int timelapse_dialogs = 0;
    int license_messages = 0;
};

void equirectangular_export_builds_file_target(pp::tests::Harness& harness)
{
    const auto target = pp::app::make_document_export_file_target("D:/Paint", "demo", ".png");
    PP_EXPECT(harness, target);
    PP_EXPECT(harness, target.value().path == "D:/Paint/demo.png");
    PP_EXPECT(harness, target.value().suggested_name == "demo.png");
}

void export_file_target_rejects_invalid_input(pp::tests::Harness& harness)
{
    const auto missing_name = pp::app::make_document_export_file_target("D:/Paint", "", ".jpg");
    const auto missing_extension = pp::app::make_document_export_file_target("D:/Paint", "demo", "");
    PP_EXPECT(harness, !missing_name);
    PP_EXPECT(harness, missing_name.status().code == pp::foundation::StatusCode::invalid_argument);
    PP_EXPECT(harness, !missing_extension);
    PP_EXPECT(harness, missing_extension.status().code == pp::foundation::StatusCode::invalid_argument);
}

void collection_export_builds_directory_and_stem(pp::tests::Harness& harness)
{
    const auto target = pp::app::make_document_export_collection_target("D:/Paint", "demo", "_layers");
    PP_EXPECT(harness, target);
    PP_EXPECT(harness, target.value().directory == "D:/Paint/demo_layers");
    PP_EXPECT(harness, target.value().stem_path == "D:/Paint/demo_layers/demo");
}

void picked_directory_export_builds_stem(pp::tests::Harness& harness)
{
    const auto target = pp::app::make_document_export_stem_target("D:/Exports", "demo");
    PP_EXPECT(harness, target);
    PP_EXPECT(harness, target.value().stem_path == "D:/Exports/demo");
}

void video_export_builds_suggested_name(pp::tests::Harness& harness)
{
    const auto timelapse = pp::app::make_document_export_suggested_name("demo", "-timelapse");
    const auto animation = pp::app::make_document_export_suggested_name("demo", "-animation");
    PP_EXPECT(harness, timelapse);
    PP_EXPECT(harness, animation);
    PP_EXPECT(harness, timelapse.value().name == "demo-timelapse");
    PP_EXPECT(harness, animation.value().name == "demo-animation");
}

void export_start_allows_valid_canvas_state(pp::tests::Harness& harness)
{
    PP_EXPECT(
        harness,
        pp::app::plan_document_export_start(true, true, true)
            == pp::app::DocumentExportStartDecision::start_now);
    PP_EXPECT(
        harness,
        pp::app::plan_document_export_start(false, false, true)
            == pp::app::DocumentExportStartDecision::start_now);
}

void export_start_blocks_demo_only_when_license_required(pp::tests::Harness& harness)
{
    PP_EXPECT(
        harness,
        pp::app::plan_document_export_start(true, false, true)
            == pp::app::DocumentExportStartDecision::show_license_disabled);
}

void export_start_reports_missing_canvas_after_license_gate(pp::tests::Harness& harness)
{
    PP_EXPECT(
        harness,
        pp::app::plan_document_export_start(false, true, false)
            == pp::app::DocumentExportStartDecision::unavailable_no_canvas);
    PP_EXPECT(
        harness,
        pp::app::plan_document_export_start(true, false, false)
            == pp::app::DocumentExportStartDecision::show_license_disabled);
}

void export_menu_routes_image_dialogs_without_license(pp::tests::Harness& harness)
{
    const auto jpeg = pp::app::plan_document_export_menu_action(
        pp::app::DocumentExportMenuKind::jpeg,
        true,
        false);
    const auto png = pp::app::plan_document_export_menu_action(
        pp::app::DocumentExportMenuKind::png,
        true,
        false);

    PP_EXPECT(harness, jpeg.action == pp::app::DocumentExportMenuAction::show_jpeg_dialog);
    PP_EXPECT(harness, jpeg.opens_dialog);
    PP_EXPECT(harness, png.action == pp::app::DocumentExportMenuAction::show_png_dialog);
    PP_EXPECT(harness, png.opens_dialog);
}

void export_menu_blocks_video_when_license_is_missing(pp::tests::Harness& harness)
{
    const auto mp4 = pp::app::plan_document_export_menu_action(
        pp::app::DocumentExportMenuKind::animation_mp4,
        true,
        false);
    const auto timelapse = pp::app::plan_document_export_menu_action(
        pp::app::DocumentExportMenuKind::timelapse,
        true,
        false);

    PP_EXPECT(harness, mp4.action == pp::app::DocumentExportMenuAction::show_license_disabled);
    PP_EXPECT(harness, !mp4.opens_dialog);
    PP_EXPECT(harness, timelapse.action == pp::app::DocumentExportMenuAction::show_license_disabled);
    PP_EXPECT(harness, !timelapse.opens_dialog);
}

void export_menu_reports_missing_canvas_for_unlicensed_image_exports(pp::tests::Harness& harness)
{
    const auto plan = pp::app::plan_document_export_menu_action(
        pp::app::DocumentExportMenuKind::layers,
        false,
        true);

    PP_EXPECT(harness, plan.action == pp::app::DocumentExportMenuAction::unavailable_no_canvas);
    PP_EXPECT(harness, !plan.opens_dialog);
}

void export_menu_executor_dispatches_all_dialog_actions(pp::tests::Harness& harness)
{
    FakeDocumentExportMenuServices services;

    PP_EXPECT(
        harness,
        pp::app::execute_document_export_menu_plan(
            pp::app::plan_document_export_menu_action(
                pp::app::DocumentExportMenuKind::jpeg,
                true,
                true),
            services).ok());
    PP_EXPECT(
        harness,
        pp::app::execute_document_export_menu_plan(
            pp::app::plan_document_export_menu_action(
                pp::app::DocumentExportMenuKind::png,
                true,
                true),
            services).ok());
    PP_EXPECT(
        harness,
        pp::app::execute_document_export_menu_plan(
            pp::app::plan_document_export_menu_action(
                pp::app::DocumentExportMenuKind::layers,
                true,
                true),
            services).ok());
    PP_EXPECT(
        harness,
        pp::app::execute_document_export_menu_plan(
            pp::app::plan_document_export_menu_action(
                pp::app::DocumentExportMenuKind::cube_faces,
                true,
                true),
            services).ok());
    PP_EXPECT(
        harness,
        pp::app::execute_document_export_menu_plan(
            pp::app::plan_document_export_menu_action(
                pp::app::DocumentExportMenuKind::depth,
                true,
                true),
            services).ok());
    PP_EXPECT(
        harness,
        pp::app::execute_document_export_menu_plan(
            pp::app::plan_document_export_menu_action(
                pp::app::DocumentExportMenuKind::animation_frames,
                true,
                true),
            services).ok());
    PP_EXPECT(
        harness,
        pp::app::execute_document_export_menu_plan(
            pp::app::plan_document_export_menu_action(
                pp::app::DocumentExportMenuKind::animation_mp4,
                true,
                true),
            services).ok());
    PP_EXPECT(
        harness,
        pp::app::execute_document_export_menu_plan(
            pp::app::plan_document_export_menu_action(
                pp::app::DocumentExportMenuKind::timelapse,
                true,
                true),
            services).ok());

    PP_EXPECT(harness, services.jpeg_dialogs == 1);
    PP_EXPECT(harness, services.png_dialogs == 1);
    PP_EXPECT(harness, services.layer_dialogs == 1);
    PP_EXPECT(harness, services.cube_dialogs == 1);
    PP_EXPECT(harness, services.depth_dialogs == 1);
    PP_EXPECT(harness, services.animation_frame_dialogs == 1);
    PP_EXPECT(harness, services.animation_mp4_dialogs == 1);
    PP_EXPECT(harness, services.timelapse_dialogs == 1);
}

void export_menu_executor_preserves_blocked_and_unavailable_actions(pp::tests::Harness& harness)
{
    FakeDocumentExportMenuServices services;

    const auto blocked = pp::app::plan_document_export_menu_action(
        pp::app::DocumentExportMenuKind::animation_mp4,
        true,
        false);
    PP_EXPECT(harness, blocked.action == pp::app::DocumentExportMenuAction::show_license_disabled);
    PP_EXPECT(harness, pp::app::execute_document_export_menu_plan(blocked, services).ok());
    PP_EXPECT(harness, services.license_messages == 1);

    const auto unavailable = pp::app::plan_document_export_menu_action(
        pp::app::DocumentExportMenuKind::png,
        false,
        true);
    PP_EXPECT(harness, unavailable.action == pp::app::DocumentExportMenuAction::unavailable_no_canvas);
    PP_EXPECT(harness, pp::app::execute_document_export_menu_plan(unavailable, services).ok());
    PP_EXPECT(harness, services.total_calls() == 1);
}

}

int main()
{
    pp::tests::Harness harness;
    harness.run("equirectangular export builds file target", equirectangular_export_builds_file_target);
    harness.run("export file target rejects invalid input", export_file_target_rejects_invalid_input);
    harness.run("collection export builds directory and stem", collection_export_builds_directory_and_stem);
    harness.run("picked directory export builds stem", picked_directory_export_builds_stem);
    harness.run("video export builds suggested name", video_export_builds_suggested_name);
    harness.run("export start allows valid canvas state", export_start_allows_valid_canvas_state);
    harness.run("export start blocks demo only when license required", export_start_blocks_demo_only_when_license_required);
    harness.run("export start reports missing canvas after license gate", export_start_reports_missing_canvas_after_license_gate);
    harness.run("export menu routes image dialogs without license", export_menu_routes_image_dialogs_without_license);
    harness.run("export menu blocks video when license is missing", export_menu_blocks_video_when_license_is_missing);
    harness.run("export menu reports missing canvas for unlicensed image exports", export_menu_reports_missing_canvas_for_unlicensed_image_exports);
    harness.run("export menu executor dispatches all dialog actions", export_menu_executor_dispatches_all_dialog_actions);
    harness.run("export menu executor preserves blocked and unavailable actions", export_menu_executor_preserves_blocked_and_unavailable_actions);
    return harness.finish();
}
