#include "pch.h"
#include "app.h"
#include "app_core/app_dialog.h"
#include "app_core/document_export.h"
#include "legacy_brush_package_export_services.h"
#include "legacy_document_export_services.h"
#include "legacy_ui_overlay_services.h"
#include "node_dialog_export_ppbr.h"

#include <codec_api.h>
#define MP4V2_NO_STDINT_DEFS
#include <mp4v2/mp4v2.h>

#include <utility>

namespace pp::panopainter {

namespace {

[[nodiscard]] bool can_start_document_export(App& app, bool requires_license)
{
    const auto decision = pp::app::plan_document_export_start(
        requires_license,
        !requires_license || app.check_license(),
        app.canvas != nullptr);

    switch (decision) {
    case pp::app::DocumentExportStartDecision::start_now:
        return true;
    case pp::app::DocumentExportStartDecision::show_license_disabled:
    {
        const auto plan = pp::app::plan_document_export_license_disabled_dialog();
        app.message_box(plan.title, plan.message, plan.show_cancel);
        return false;
    }
    case pp::app::DocumentExportStartDecision::unavailable_no_canvas:
        return false;
    }

    return false;
}

void start_document_export_collection(
    App& app,
    pp::app::DocumentExportCollectionKind kind)
{
    const auto plan = pp::app::plan_document_export_collection_target(
        kind,
        app.uses_work_directory_document_export_collections());
    const auto success_kind = pp::app::document_export_collection_success_kind(kind);

    if (plan.destination == pp::app::DocumentExportCollectionDestination::work_directory_collection) {
        const auto target = pp::app::make_document_export_collection_target(
            app.work_path,
            app.doc_name,
            plan.suffix);
        if (!target) {
            const auto dialog = pp::app::plan_document_export_failure_dialog(success_kind, target.status().message);
            app.message_box(dialog.title, dialog.message, dialog.show_cancel);
            return;
        }

        const auto status = pp::panopainter::execute_legacy_document_export_collection(
            app,
            plan.kind,
            target.value());
        if (!status.ok())
            LOG(
                "%s: %s",
                pp::app::document_export_execution_log_message(
                    kind == pp::app::DocumentExportCollectionKind::layers
                        ? pp::app::DocumentExportExecutionKind::layers_collection
                        : pp::app::DocumentExportExecutionKind::animation_frames_collection),
                status.message);
        return;
    }

    app.pick_dir([
        &app,
        kind = plan.kind,
        success_kind
    ](std::string path) {
        const auto target = pp::app::make_document_export_stem_target(path, app.doc_name);
        if (!target) {
            const auto dialog = pp::app::plan_document_export_failure_dialog(success_kind, target.status().message);
            app.message_box(dialog.title, dialog.message, dialog.show_cancel);
            return;
        }

        const auto status = pp::panopainter::execute_legacy_document_export_stem(
            app,
            kind,
            target.value());
        if (!status.ok())
            LOG(
                "%s: %s",
                pp::app::document_export_execution_log_message(
                    kind == pp::app::DocumentExportCollectionKind::layers
                        ? pp::app::DocumentExportExecutionKind::layers_stem
                        : pp::app::DocumentExportExecutionKind::animation_frames_stem),
                status.message);
    });
}

void start_document_video_export(
    App& app,
    pp::app::DocumentVideoExportKind kind,
    pp::app::DocumentExportSuccessKind success_kind,
    const char* suffix,
    pp::app::DocumentExportExecutionKind execution_kind)
{
    if (!can_start_document_export(app, false))
        return;

    if (app.uses_prepared_file_writes())
    {
        const auto target = pp::app::make_document_export_suggested_name(app.doc_name, suffix);
        if (!target) {
            const auto dialog = pp::app::plan_document_export_failure_dialog(
                success_kind,
                target.status().message);
            app.message_box(dialog.title, dialog.message, dialog.show_cancel);
            return;
        }

        app.pick_file_save("mp4", target.value().name,
            [&app, kind, execution_kind](std::string path) {
                const auto status = pp::panopainter::execute_legacy_document_video_export(
                    app,
                    kind,
                    path,
                    false);
                if (!status.ok())
                    LOG(
                        "%s: %s",
                        pp::app::document_export_execution_log_message(execution_kind),
                        status.message);
            },
            [](const std::string& path, bool saved) {
                (void)path;
                (void)saved;
            }
        );
        return;
    }

    app.pick_file_save({ "mp4" }, [&app, kind, execution_kind](std::string path) {
        const auto status = pp::panopainter::execute_legacy_document_video_export(
            app,
            kind,
            path,
            true);
        if (!status.ok())
            LOG(
                "%s: %s",
                pp::app::document_export_execution_log_message(execution_kind),
                status.message);
    });
}

} // namespace

void open_document_export_dialog(App& app, std::string ext)
{
    if (!can_start_document_export(app, true))
        return;

    // TODO: use picker
    const auto target = pp::app::make_document_export_file_target(app.work_path, app.doc_name, ext);
    if (!target) {
        const auto dialog = pp::app::plan_document_export_failure_dialog(
            pp::app::DocumentExportSuccessKind::equirectangular,
            target.status().message);
        app.message_box(dialog.title, dialog.message, dialog.show_cancel);
        return;
    }

    const auto status = pp::panopainter::execute_legacy_document_export_file(app, target.value());
    if (!status.ok())
        LOG(
            "%s: %s",
            pp::app::document_export_execution_log_message(
                pp::app::DocumentExportExecutionKind::equirectangular_file),
            status.message);
}

void open_document_export_layers_dialog(App& app)
{
    if (!can_start_document_export(app, true))
        return;

    start_document_export_collection(
        app,
        pp::app::DocumentExportCollectionKind::layers);
}

void open_document_export_anim_frames_dialog(App& app)
{
    if (!can_start_document_export(app, true))
        return;

    start_document_export_collection(
        app,
        pp::app::DocumentExportCollectionKind::animation_frames);
}

void open_document_export_depth_dialog(App& app)
{
    if (!can_start_document_export(app, true))
        return;

    const auto status = pp::panopainter::execute_legacy_document_export_depth(app, app.doc_name);
    if (!status.ok())
        LOG(
            "%s: %s",
            pp::app::document_export_execution_log_message(pp::app::DocumentExportExecutionKind::depth),
            status.message);
}

void open_document_export_cube_faces_dialog(App& app)
{
    if (!can_start_document_export(app, false))
        return;

    const auto status = pp::panopainter::execute_legacy_document_export_cube_faces(app, app.doc_name);
    if (!status.ok())
        LOG(
            "%s: %s",
            pp::app::document_export_execution_log_message(pp::app::DocumentExportExecutionKind::cube_faces),
            status.message);
}

void open_document_timelapse_export_dialog(App& app)
{
    start_document_video_export(
        app,
        pp::app::DocumentVideoExportKind::timelapse,
        pp::app::DocumentExportSuccessKind::timelapse,
        "-timelapse",
        pp::app::DocumentExportExecutionKind::timelapse);
}

void open_document_export_mp4_dialog(App& app)
{
    start_document_video_export(
        app,
        pp::app::DocumentVideoExportKind::animation_mp4,
        pp::app::DocumentExportSuccessKind::animation_mp4,
        "-animation",
        pp::app::DocumentExportExecutionKind::animation_mp4);
}

void open_ppbr_export_dialog(App& app)
{
    auto* overlay_anchor = app.layout[app.main_id];
    if (!overlay_anchor) {
        LOG("PPBR export dialog open failed: main layout anchor is missing");
        return;
    }

    auto dialog = pp::panopainter::make_legacy_overlay_node<NodeDialogExportPPBR>(app);

    const auto overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*overlay_anchor, dialog);
    if (!overlay) {
        LOG("PPBR export dialog open failed: %s", overlay.status().message);
        return;
    }
    const auto overlay_handle = overlay.value();

    const auto close_dialog = [overlay_anchor, overlay_handle]() {
        const auto close_status = pp::panopainter::close_legacy_overlay_node(*overlay_anchor, overlay_handle);
        (void)close_status;
    };

    dialog->btn_ok->on_click = [&app, dialog] (Node*) {
        const auto request = pp::panopainter::make_legacy_brush_package_export_request(*dialog);

        if (app.uses_prepared_file_writes())
        {
            app.pick_file_save("ppbr", "exported-brushes",
                [&app, dialog, request] (std::string path) {
                    const auto status = pp::panopainter::execute_legacy_brush_package_export(
                        app,
                        *dialog,
                        request,
                        path,
                        pp::panopainter::LegacyBrushPackageExportMode::inline_export_only);
                    if (!status.ok())
                        LOG("PPBR export failed: %s", status.message);
                },
                [dialog] (const std::string& path, bool saved) {
                    (void)path;
                    pp::panopainter::complete_legacy_brush_package_export(*dialog, saved);
                }
            );
            return;
        }

        app.pick_file_save({ "ppbr" }, [&app, dialog, request] (std::string path) {
            const auto status = pp::panopainter::execute_legacy_brush_package_export(
                app,
                *dialog,
                request,
                path,
                pp::panopainter::LegacyBrushPackageExportMode::desktop_async_close_and_message);
            if (!status.ok())
                LOG("PPBR export failed: %s", status.message);
        });
    };
    dialog->btn_cancel->on_click = [close_dialog](Node*)
    {
        close_dialog();
    };
}

} // namespace pp::panopainter
