#include "pch.h"

#include "legacy_document_session_services.h"

#include "app.h"
#include "legacy_history_services.h"
#include "node_dialog_open.h"

#include <utility>

namespace pp::panopainter {
namespace {

void create_legacy_new_document(
    App& app,
    const pp::app::NewDocumentPlan& plan,
    const std::shared_ptr<NodeDialogNewDoc>& dialog)
{
    app.doc_name = plan.target.name;
    app.doc_path = plan.target.path;
    app.doc_filename = plan.target.name + ".ppi";
    app.doc_dir = plan.target.directory;

    app.layers->clear();
    app.canvas->m_canvas->m_layers.clear();
    app.canvas->m_canvas->resize(plan.resolution, plan.resolution);
    app.canvas->reset_camera();
    pp::panopainter::clear_legacy_history();

    app.layers->add_layer("Default", false, true);

    app.canvas->m_canvas->m_unsaved = true;
    app.canvas->m_canvas->m_newdoc = false;
    app.title_update();

    dialog->destroy();
    App::I->hideKeyboard();
}

class LegacyNewDocumentServices final : public pp::app::NewDocumentServices {
public:
    LegacyNewDocumentServices(App& app, std::shared_ptr<NodeDialogNewDoc> dialog) noexcept
        : app_(app)
        , dialog_(std::move(dialog))
    {
    }

    void create_new_document(const pp::app::NewDocumentPlan& plan) override
    {
        create_legacy_new_document(app_, plan, dialog_);
    }

    void prompt_overwrite_new_document(const pp::app::NewDocumentPlan& plan) override
    {
        auto msgbox = new NodeMessageBox();
        msgbox->set_manager(&app_.layout);
        msgbox->init();
        msgbox->m_title->set_text("Warning");
        msgbox->m_message->set_text("A document with this name already exists, continue?");
        auto* app = &app_;
        auto dialog = dialog_;
        msgbox->btn_ok->on_click = [app, msgbox, dialog, plan](Node*) {
            create_legacy_new_document(*app, plan, dialog);
            msgbox->destroy();
        };
        app_.layout[app_.main_id]->add_child(msgbox);
    }

private:
    App& app_;
    std::shared_ptr<NodeDialogNewDoc> dialog_;
};

void save_legacy_document_file(
    App& app,
    const pp::app::DocumentFileSavePlan& plan,
    const std::shared_ptr<NodeDialogSave>& dialog)
{
    app.canvas->m_canvas->project_save(plan.target.path);
    app.doc_name = plan.target.name;
    app.doc_path = plan.target.path;
    app.doc_dir = plan.target.directory;
    app.title_update();
    dialog->destroy();
    App::I->hideKeyboard();
}

class LegacyDocumentFileSaveServices final : public pp::app::DocumentFileSaveServices {
public:
    LegacyDocumentFileSaveServices(App& app, std::shared_ptr<NodeDialogSave> dialog) noexcept
        : app_(app)
        , dialog_(std::move(dialog))
    {
    }

    void save_document_file(const pp::app::DocumentFileSavePlan& plan) override
    {
        save_legacy_document_file(app_, plan, dialog_);
    }

    void prompt_overwrite_document_file(const pp::app::DocumentFileSavePlan& plan) override
    {
        auto msgbox = new NodeMessageBox();
        msgbox->set_manager(&app_.layout);
        msgbox->init();
        msgbox->m_title->set_text("Warning");
        msgbox->m_message->set_text(("Are you sure you want to overwrite " + plan.target.name + "?").c_str());
        auto* app = &app_;
        auto dialog = dialog_;
        msgbox->btn_ok->on_click = [app, msgbox, dialog, plan](Node*) {
            save_legacy_document_file(*app, plan, dialog);
            msgbox->destroy();
        };
        app_.layout[app_.main_id]->add_child(msgbox);
    }

private:
    App& app_;
    std::shared_ptr<NodeDialogSave> dialog_;
};

class LegacyDocumentVersionSaveServices final : public pp::app::DocumentVersionSaveServices {
public:
    explicit LegacyDocumentVersionSaveServices(App& app) noexcept
        : app_(app)
    {
    }

    void save_document_version(const pp::app::DocumentVersionTarget& target) override
    {
        app_.doc_name = target.name;
        app_.doc_path = target.path;
        app_.canvas->m_canvas->m_unsaved = true;
        app_.title_update();
        app_.canvas->m_canvas->project_save(app_.doc_path);
    }

private:
    App& app_;
};

class LegacyCloseRequestServices final : public pp::app::CloseRequestServices {
public:
    LegacyCloseRequestServices(App& app, bool& dialog_already_opened) noexcept
        : app_(app)
        , dialog_already_opened_(dialog_already_opened)
    {
    }

    void request_close_now() override
    {
    }

    void show_unsaved_close_prompt() override
    {
        auto* app = &app_;
        auto* dialog_already_opened = &dialog_already_opened_;
        auto* m = app_.layout[app_.main_id]->add_child<NodeMessageBox>();
        m->m_title->set_text("Unsaved document");
        m->m_message->set_text("Do you want to close without saving?");
        m->btn_ok->m_text->set_text("Yes");
        m->btn_ok->on_click = [app](Node*) {
            app->request_app_close();
            Canvas::I->m_unsaved = false;
        };
        m->btn_cancel->m_text->set_text("No");
        m->btn_cancel->on_click = [dialog_already_opened, m](Node*) {
            m->destroy();
            *dialog_already_opened = false;
        };
        dialog_already_opened_ = true;
    }

private:
    App& app_;
    bool& dialog_already_opened_;
};

class LegacyDocumentSaveServices final : public pp::app::DocumentSaveServices {
public:
    explicit LegacyDocumentSaveServices(App& app) noexcept
        : app_(app)
    {
    }

    void show_save_dialog() override
    {
        app_.dialog_save();
    }

    void save_existing_document() override
    {
        Canvas::I->project_save();
    }

    void save_document_version() override
    {
        app_.dialog_save_ver();
    }

private:
    App& app_;
};

class LegacyDocumentWorkflowServices final : public pp::app::DocumentWorkflowServices {
public:
    LegacyDocumentWorkflowServices(App& app, std::function<void()> action) noexcept
        : app_(app)
        , action_(std::move(action))
    {
    }

    void continue_workflow_now() override
    {
        action_();
    }

    void prompt_save_before_continue() override
    {
        auto m = app_.layout[app_.main_id]->add_child<NodeMessageBox>();
        m->m_title->set_text("Unsaved document");
        m->m_message->set_text("Would you like to save this document before closing?");
        m->btn_ok->m_text->set_text("Yes");
        m->btn_cancel->m_text->set_text("No");
        auto* app = &app_;
        auto action = action_;
        m->btn_ok->on_click = [app, m, action](Node*) {
            Canvas::I->project_save([app, m, action](bool success) {
                if (success)
                    action();
                else
                    app->message_box("Saving Error", "There was a problem saving the document");
            });
            m->destroy();
        };
        m->btn_cancel->on_click = [m, action](Node*) {
            action();
            m->destroy();
        };
    }

private:
    App& app_;
    std::function<void()> action_;
};

} // namespace

pp::foundation::Status execute_legacy_close_request_decision(
    App& app,
    pp::app::CloseRequestDecision decision,
    bool& dialog_already_opened)
{
    LegacyCloseRequestServices services(app, dialog_already_opened);
    return pp::app::execute_close_request_decision(decision, services);
}

pp::foundation::Status execute_legacy_document_save_decision(
    App& app,
    pp::app::DocumentSaveDecision decision)
{
    LegacyDocumentSaveServices services(app);
    return pp::app::execute_document_save_decision(decision, services);
}

pp::foundation::Status execute_legacy_document_workflow_decision(
    App& app,
    pp::app::DocumentWorkflowDecision decision,
    std::function<void()> action)
{
    LegacyDocumentWorkflowServices services(app, std::move(action));
    return pp::app::execute_document_workflow_decision(decision, services);
}

pp::foundation::Status execute_legacy_new_document_plan(
    App& app,
    const pp::app::NewDocumentPlan& plan,
    std::shared_ptr<NodeDialogNewDoc> dialog)
{
    LegacyNewDocumentServices services(app, std::move(dialog));
    return pp::app::execute_new_document_plan(plan, services);
}

pp::foundation::Status execute_legacy_document_file_save_plan(
    App& app,
    const pp::app::DocumentFileSavePlan& plan,
    std::shared_ptr<NodeDialogSave> dialog)
{
    LegacyDocumentFileSaveServices services(app, std::move(dialog));
    return pp::app::execute_document_file_save_plan(plan, services);
}

pp::foundation::Status execute_legacy_document_version_save(
    App& app,
    const pp::app::DocumentVersionTarget& target)
{
    LegacyDocumentVersionSaveServices services(app);
    return pp::app::execute_document_version_save(target, services);
}

} // namespace pp::panopainter
