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

namespace {

class TestProgressDialog final : public pp::app::AppProgressDialog {
public:
    [[nodiscard]] pp::app::AppDialogKind kind() const noexcept override
    {
        return pp::app::AppDialogKind::progress;
    }
};

class TestMessageDialog final : public pp::app::AppMessageDialog {
public:
    [[nodiscard]] pp::app::AppDialogKind kind() const noexcept override
    {
        return pp::app::AppDialogKind::message;
    }
};

class TestInputDialog final : public pp::app::AppInputDialog {
public:
    [[nodiscard]] pp::app::AppDialogKind kind() const noexcept override
    {
        return pp::app::AppDialogKind::input;
    }
};

class TestDialogFactory final : public pp::app::AppDialogFactory {
public:
    std::shared_ptr<pp::app::AppProgressDialog> show_progress_dialog(
        const pp::app::AppProgressDialogPlan&) override
    {
        return std::make_shared<TestProgressDialog>();
    }

    std::shared_ptr<pp::app::AppMessageDialog> show_message_dialog(
        const pp::app::AppMessageDialogPlan&) override
    {
        return std::make_shared<TestMessageDialog>();
    }

    std::shared_ptr<pp::app::AppInputDialog> show_input_dialog(
        const pp::app::AppInputDialogPlan&) override
    {
        return std::make_shared<TestInputDialog>();
    }
};

void progress_dialog_initializes_progress_state(pp::tests::Harness& harness)
{
    const auto plan = pp::app::plan_app_progress_dialog("Saving", 12);
    PP_EXPECT(harness, plan.title == "Saving");
    PP_EXPECT(harness, plan.total == 12);
    PP_EXPECT(harness, plan.count == 0);
    PP_EXPECT(harness, plan.progress_fraction == 0.0F);
}

void progress_dialog_clamps_negative_total(pp::tests::Harness& harness)
{
    const auto plan = pp::app::plan_app_progress_dialog("Broken", -4);
    PP_EXPECT(harness, plan.total == 0);
    PP_EXPECT(harness, plan.count == 0);
    PP_EXPECT(harness, plan.progress_fraction == 0.0F);
}

void message_dialog_preserves_cancel_policy(pp::tests::Harness& harness)
{
    const auto plan = pp::app::plan_app_message_dialog("Import", "Import brushes?", true);
    PP_EXPECT(harness, plan.title == "Import");
    PP_EXPECT(harness, plan.message == "Import brushes?");
    PP_EXPECT(harness, plan.ok_caption == "Ok");
    PP_EXPECT(harness, plan.cancel_caption == "Cancel");
    PP_EXPECT(harness, plan.show_cancel);
}

void message_dialog_defaults_to_no_cancel(pp::tests::Harness& harness)
{
    const auto plan = pp::app::plan_app_message_dialog("License", "Disabled", false);
    PP_EXPECT(harness, plan.title == "License");
    PP_EXPECT(harness, plan.message == "Disabled");
    PP_EXPECT(harness, !plan.show_cancel);
}

void message_dialog_allows_custom_button_captions(pp::tests::Harness& harness)
{
    const auto plan = pp::app::plan_app_message_dialog("Unsaved", "Save first?", true, "Yes", "No");
    PP_EXPECT(harness, plan.ok_caption == "Yes");
    PP_EXPECT(harness, plan.cancel_caption == "No");
    PP_EXPECT(harness, plan.show_cancel);
}

void input_dialog_preserves_ok_caption(pp::tests::Harness& harness)
{
    const auto plan = pp::app::plan_app_input_dialog("Rename", "Layer", "Save");
    PP_EXPECT(harness, plan);
    PP_EXPECT(harness, plan.value().title == "Rename");
    PP_EXPECT(harness, plan.value().field_name == "Layer");
    PP_EXPECT(harness, plan.value().ok_caption == "Save");
}

void input_dialog_rejects_empty_ok_caption(pp::tests::Harness& harness)
{
    const auto plan = pp::app::plan_app_input_dialog("Rename", "Layer", "");
    PP_EXPECT(harness, !plan);
    PP_EXPECT(harness, plan.status().code == pp::foundation::StatusCode::invalid_argument);
}

void dialog_factory_uses_pure_app_core_dialog_types(pp::tests::Harness& harness)
{
    TestDialogFactory factory;
    PP_EXPECT(harness, factory.show_progress_dialog({})->kind() == pp::app::AppDialogKind::progress);
    PP_EXPECT(harness, factory.show_message_dialog({})->kind() == pp::app::AppDialogKind::message);
    PP_EXPECT(harness, factory.show_input_dialog({})->kind() == pp::app::AppDialogKind::input);
}

}

int main()
{
    pp::tests::Harness harness;
    harness.run("progress dialog initializes progress state", progress_dialog_initializes_progress_state);
    harness.run("progress dialog clamps negative total", progress_dialog_clamps_negative_total);
    harness.run("message dialog preserves cancel policy", message_dialog_preserves_cancel_policy);
    harness.run("message dialog defaults to no cancel", message_dialog_defaults_to_no_cancel);
    harness.run("message dialog allows custom button captions", message_dialog_allows_custom_button_captions);
    harness.run("input dialog preserves ok caption", input_dialog_preserves_ok_caption);
    harness.run("input dialog rejects empty ok caption", input_dialog_rejects_empty_ok_caption);
    harness.run("dialog factory uses pure app-core dialog types", dialog_factory_uses_pure_app_core_dialog_types);
    return harness.finish();
}
