#pragma once

#include "foundation/result.h"

#include <string>
#include <string_view>
#include <utility>
#include <vector>

namespace pp::app {

enum class CommandConvertStep {
    apply_renderer_state,
    create_canvas,
    open_project,
    export_equirectangular,
};

struct CommandConvertPlan {
    std::string project_path;
    std::string output_path;
    int canvas_resolution = 0;
    std::vector<CommandConvertStep> steps;
};

class CommandConvertServices {
public:
    virtual ~CommandConvertServices() = default;

    virtual void apply_renderer_state() = 0;
    virtual void create_canvas(int canvas_resolution) = 0;
    virtual void open_project(std::string_view project_path) = 0;
    virtual void export_equirectangular(std::string_view output_path) = 0;
};

[[nodiscard]] inline pp::foundation::Result<CommandConvertPlan> plan_command_convert(
    std::string_view project_path,
    std::string_view output_path,
    int canvas_resolution)
{
    if (project_path.empty()) {
        return pp::foundation::Result<CommandConvertPlan>::failure(
            pp::foundation::Status::invalid_argument("convert project path must not be empty"));
    }

    if (output_path.empty()) {
        return pp::foundation::Result<CommandConvertPlan>::failure(
            pp::foundation::Status::invalid_argument("convert output path must not be empty"));
    }

    if (canvas_resolution < 1) {
        return pp::foundation::Result<CommandConvertPlan>::failure(
            pp::foundation::Status::invalid_argument("convert canvas resolution must be positive"));
    }

    CommandConvertPlan plan;
    plan.project_path = std::string(project_path);
    plan.output_path = std::string(output_path);
    plan.canvas_resolution = canvas_resolution;
    plan.steps = {
        CommandConvertStep::apply_renderer_state,
        CommandConvertStep::create_canvas,
        CommandConvertStep::open_project,
        CommandConvertStep::export_equirectangular,
    };
    return pp::foundation::Result<CommandConvertPlan>::success(std::move(plan));
}

[[nodiscard]] inline pp::foundation::Status execute_command_convert_plan(
    const CommandConvertPlan& plan,
    CommandConvertServices& services)
{
    if (plan.project_path.empty() || plan.output_path.empty() || plan.canvas_resolution < 1) {
        return pp::foundation::Status::invalid_argument("convert plan is malformed");
    }

    for (const auto step : plan.steps) {
        switch (step) {
        case CommandConvertStep::apply_renderer_state:
            services.apply_renderer_state();
            break;
        case CommandConvertStep::create_canvas:
            services.create_canvas(plan.canvas_resolution);
            break;
        case CommandConvertStep::open_project:
            services.open_project(plan.project_path);
            break;
        case CommandConvertStep::export_equirectangular:
            services.export_equirectangular(plan.output_path);
            break;
        }
    }

    return pp::foundation::Status::success();
}

} // namespace pp::app
