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

#include <cstddef>

namespace {

void dispatch_plan_is_consistent_under_stress(pp::tests::Harness& harness)
{
    constexpr std::size_t queued_sizes[] = { 0U, 1U, 4U, 8U, 16U };

    for (const auto queued_task_count : queued_sizes) {
        const auto plan = pp::app::plan_app_task_dispatch(
            false,
            true,
            queued_task_count,
            true,
            true,
            true);

        PP_EXPECT(harness, !plan.execute_immediately);
        PP_EXPECT(harness, plan.queue_task);
        PP_EXPECT(harness, plan.remove_matching_unique_task == (queued_task_count > 0U));
        PP_EXPECT(harness, plan.notify_worker);
        PP_EXPECT(harness, plan.wait_for_completion);
        PP_EXPECT(harness, plan.request_redraw);
        PP_EXPECT(harness, !plan.reject_unsafe_cross_thread_dispatch);
    }
}

void dispatch_plan_handles_target_thread_with_rejection_flag(pp::tests::Harness& harness)
{
    constexpr std::size_t queued_sizes[] = { 0U, 5U };
    for (const auto queued_task_count : queued_sizes) {
        const auto plan = pp::app::plan_app_task_dispatch(
            true,
            true,
            queued_task_count,
            false,
            true,
            true,
            true);

        PP_EXPECT(harness, plan.execute_immediately);
        PP_EXPECT(harness, !plan.queue_task);
        PP_EXPECT(harness, !plan.remove_matching_unique_task);
        PP_EXPECT(harness, !plan.notify_worker);
        PP_EXPECT(harness, !plan.wait_for_completion);
        PP_EXPECT(harness, plan.request_redraw);
        PP_EXPECT(harness, !plan.reject_unsafe_cross_thread_dispatch);
    }
}

void dispatch_plan_rejects_cross_thread_mutations_under_pressure(pp::tests::Harness& harness)
{
    constexpr std::size_t queued_sizes[] = { 0U, 4U, 8U };

    for (const auto queued_task_count : queued_sizes) {
        const auto plan = pp::app::plan_app_task_dispatch(
            false,
            true,
            queued_task_count,
            false,
            true,
            true,
            true);

        PP_EXPECT(harness, !plan.execute_immediately);
        PP_EXPECT(harness, !plan.queue_task);
        PP_EXPECT(harness, !plan.remove_matching_unique_task);
        PP_EXPECT(harness, !plan.notify_worker);
        PP_EXPECT(harness, !plan.wait_for_completion);
        PP_EXPECT(harness, !plan.request_redraw);
        PP_EXPECT(harness, plan.reject_unsafe_cross_thread_dispatch);
    }
}

} // namespace

int main()
{
    pp::tests::Harness harness;
    harness.run("dispatch plan is consistent across queue sizes", dispatch_plan_is_consistent_under_stress);
    harness.run("dispatch plan ignores reject flag when already on target thread", dispatch_plan_handles_target_thread_with_rejection_flag);
    harness.run("dispatch plan rejects unsafe cross-thread work under load", dispatch_plan_rejects_cross_thread_mutations_under_pressure);
    return harness.finish();
}
