#include "pch.h"

#include "legacy_document_open_services.h"

#include "action.h"
#include "app.h"
#include "legacy_brush_package_import_services.h"
#include "legacy_canvas_view_services.h"
#include "legacy_history_services.h"
#include "legacy_ui_overlay_services.h"
#include "log.h"
#include "node_panel_brush.h"
#include "node_panel_layer.h"

namespace pp::panopainter {
namespace {

void apply_open_legacy_project_history(const pp::app::DocumentOpenRoute& route)
{
    const auto history_status = pp::panopainter::execute_legacy_history_plan(
        pp::app::plan_document_open_history(route));
    if (!history_status.ok()) {
        LOG("Project open history effect failed: %s", history_status.message);
    }
}

void refresh_opened_legacy_project_layers(App& app)
{
    app.title_update();
    for (std::size_t layer_index = 0; layer_index < app.canvas->m_canvas->m_layers.size(); ++layer_index)
    {
        auto layer = app.layers->add_layer(app.canvas->m_canvas->m_layers[layer_index]->m_name.c_str(), false);
        layer->m_visibility->set_value(app.canvas->m_canvas->m_layers[layer_index]->m_visible);
    }
}

void show_open_legacy_project_error(App& app)
{
    app.message_box(
        "Open Document Error",
        "There was an error opening the document.\n"
        "It may be inaccessible or corrupted.");
}

void handle_open_legacy_project_result(App& app, bool success)
{
    if (success)
    {
        refresh_opened_legacy_project_layers(app);
        return;
    }

    show_open_legacy_project_error(app);
}

void open_legacy_project(App& app, const pp::app::DocumentOpenRoute& route)
{
    app.doc_name = route.name;
    app.doc_dir = route.directory;
    app.doc_path = route.path;
    const auto reset_status = execute_legacy_canvas_camera_reset(app);
    if (!reset_status.ok())
        LOG("Project open camera reset failed: %s", reset_status.message);
    app.layers->clear();
    app.canvas->m_canvas->project_open(route.path, [&app](bool success) {
        handle_open_legacy_project_result(app, success);
    });
    apply_open_legacy_project_history(route);
}

void reconcile_downloaded_project_open(App& app)
{
    for (auto& layer : app.canvas->m_canvas->m_layers)
        app.layers->add_layer(layer->m_name.c_str(), false);
    ActionManager::clear();
}

void prepare_downloaded_project_open(App& app)
{
    const auto reset_status = execute_legacy_canvas_camera_reset(app);
    if (!reset_status.ok())
        LOG("Cloud download camera reset failed: %s", reset_status.message);
    app.layers->clear();
}

void prompt_import_brush_package(
    App& app,
    const char* title,
    const char* log_prefix,
    pp::app::BrushPackageImportKind kind,
    const pp::app::DocumentOpenRoute& route)
{
    auto mb = app.message_box(title, "Would you like to import the brushes?", true);
    mb->on_submit = [&app, path = route.path, kind, log_prefix](Node* target) {
        const auto status = pp::panopainter::execute_legacy_brush_package_import(app, kind, path);
        if (!status.ok())
            LOG("%s import failed: %s", log_prefix, status.message);
        pp::panopainter::close_legacy_dialog_node(*target);
    };
}

void prompt_discard_unsaved_project(App& app, const pp::app::DocumentOpenRoute& route)
{
    auto mb = app.message_box(
        "Unsaved document",
        "Do you want to close the unsaved document before opening the file?",
        true);
    mb->on_submit = [&app, route](Node* target) {
        open_legacy_project(app, route);
        pp::panopainter::close_legacy_dialog_node(*target);
    };
}

class LegacyDocumentOpenServices final : public pp::app::DocumentOpenServices {
public:
    explicit LegacyDocumentOpenServices(App& app) noexcept
        : app_(app)
    {
    }

    void prompt_import_abr(const pp::app::DocumentOpenRoute& route) override
    {
        prompt_import_brush_package(
            app_,
            "Import ABR",
            "ABR",
            pp::app::BrushPackageImportKind::abr,
            route);
    }

    void prompt_import_ppbr(const pp::app::DocumentOpenRoute& route) override
    {
        prompt_import_brush_package(
            app_,
            "Import PPBR",
            "PPBR",
            pp::app::BrushPackageImportKind::ppbr,
            route);
    }

    void open_project_now(const pp::app::DocumentOpenRoute& route) override
    {
        open_legacy_project(app_, route);
    }

    void prompt_discard_unsaved_project(const pp::app::DocumentOpenRoute& route) override
    {
        pp::panopainter::prompt_discard_unsaved_project(app_, route);
    }

private:
    App& app_;
};

} // namespace

pp::foundation::Status execute_legacy_document_open_plan(
    App& app,
    pp::app::DocumentOpenPlanAction action,
    const pp::app::DocumentOpenRoute& route)
{
    LegacyDocumentOpenServices services(app);
    return pp::app::execute_document_open_plan(action, route, services);
}

pp::foundation::Status execute_legacy_document_open(App& app, std::string path)
{
    const auto route = pp::app::classify_document_open_path(path);
    if (!route)
        return route.status();

    const bool has_unsaved_project =
        route.value().kind == pp::app::DocumentOpenKind::open_project && Canvas::I->m_unsaved;
    const auto open_plan = pp::app::plan_document_open(route.value().kind, has_unsaved_project);
    const auto status = execute_legacy_document_open_plan(app, open_plan, route.value());
    if (!status.ok())
        LOG("Document open action failed: %s", status.message);

    return status;
}

void execute_legacy_downloaded_project_open(
    App& app,
    std::string_view path,
    std::string_view name)
{
    prepare_downloaded_project_open(app);
    app.canvas->m_canvas->project_open_thread(std::string(path));

    app.doc_name = std::string(name);
    app.title_update();
    reconcile_downloaded_project_open(app);
}

} // namespace pp::panopainter
