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

#include <string>

namespace {

class FakeDocumentResizeServices final : public pp::app::DocumentResizeServices {
public:
    void resize_document(int width, int height) override
    {
        resize_calls += 1;
        last_width = width;
        last_height = height;
        call_order += "resize;";
    }

    void update_title() override
    {
        title_updates += 1;
        call_order += "title;";
    }

    void clear_history() override
    {
        history_clears += 1;
        call_order += "history;";
    }

    int resize_calls = 0;
    int title_updates = 0;
    int history_clears = 0;
    int last_width = 0;
    int last_height = 0;
    std::string call_order;
};

void dialog_state_labels_current_resolution(pp::tests::Harness& harness)
{
    const auto state = pp::app::make_document_resize_dialog_state(2048);
    PP_EXPECT(harness, state.current_resolution == 2048);
    PP_EXPECT(harness, state.current_resolution_text == "Current: 8K");
    PP_EXPECT(harness, state.current_resolution_index == 3);
}

void dialog_state_survives_unknown_resolution(pp::tests::Harness& harness)
{
    const auto state = pp::app::make_document_resize_dialog_state(1234);
    PP_EXPECT(harness, state.current_resolution == 1234);
    PP_EXPECT(harness, state.current_resolution_text == "Current: unknown");
    PP_EXPECT(harness, state.current_resolution_index == 6);
}

void resize_plan_maps_selection_to_square_canvas(pp::tests::Harness& harness)
{
    const auto plan = pp::app::plan_document_resize(4);
    PP_EXPECT(harness, plan);
    if (plan) {
        PP_EXPECT(harness, plan.value().resolution == 4096);
        PP_EXPECT(harness, plan.value().width == 4096);
        PP_EXPECT(harness, plan.value().height == 4096);
        PP_EXPECT(harness, plan.value().clears_history);
    }
}

void resize_plan_rejects_invalid_selection(pp::tests::Harness& harness)
{
    PP_EXPECT(harness, !pp::app::plan_document_resize(-1));
    PP_EXPECT(harness, !pp::app::plan_document_resize(6));
}

void resize_executor_dispatches_canvas_title_and_history(pp::tests::Harness& harness)
{
    FakeDocumentResizeServices services;
    const auto plan = pp::app::plan_document_resize(4);
    PP_EXPECT(harness, plan);
    if (plan) {
        PP_EXPECT(harness, pp::app::execute_document_resize_plan(plan.value(), services).ok());
    }

    PP_EXPECT(harness, services.resize_calls == 1);
    PP_EXPECT(harness, services.last_width == 4096);
    PP_EXPECT(harness, services.last_height == 4096);
    PP_EXPECT(harness, services.title_updates == 1);
    PP_EXPECT(harness, services.history_clears == 1);
    PP_EXPECT(harness, services.call_order == "resize;title;history;");
}

void resize_executor_preserves_optional_history_clear(pp::tests::Harness& harness)
{
    FakeDocumentResizeServices services;
    const pp::app::DocumentResizePlan plan {
        1024,
        1024,
        1024,
        false,
    };

    PP_EXPECT(harness, pp::app::execute_document_resize_plan(plan, services).ok());
    PP_EXPECT(harness, services.resize_calls == 1);
    PP_EXPECT(harness, services.title_updates == 1);
    PP_EXPECT(harness, services.history_clears == 0);
    PP_EXPECT(harness, services.call_order == "resize;title;");
}

void resize_executor_rejects_invalid_dimensions(pp::tests::Harness& harness)
{
    FakeDocumentResizeServices services;
    const pp::app::DocumentResizePlan plan {
        0,
        0,
        1024,
        true,
    };

    const auto status = pp::app::execute_document_resize_plan(plan, services);
    PP_EXPECT(harness, !status.ok());
    PP_EXPECT(harness, status.code == pp::foundation::StatusCode::out_of_range);
    PP_EXPECT(harness, services.resize_calls == 0);
    PP_EXPECT(harness, services.title_updates == 0);
    PP_EXPECT(harness, services.history_clears == 0);
}

}

int main()
{
    pp::tests::Harness harness;
    harness.run("dialog state labels current resolution", dialog_state_labels_current_resolution);
    harness.run("dialog state survives unknown resolution", dialog_state_survives_unknown_resolution);
    harness.run("resize plan maps selection to square canvas", resize_plan_maps_selection_to_square_canvas);
    harness.run("resize plan rejects invalid selection", resize_plan_rejects_invalid_selection);
    harness.run("resize executor dispatches canvas title and history", resize_executor_dispatches_canvas_title_and_history);
    harness.run("resize executor preserves optional history clear", resize_executor_preserves_optional_history_clear);
    harness.run("resize executor rejects invalid dimensions", resize_executor_rejects_invalid_dimensions);
    return harness.finish();
}
