// import_bank.cpp — see import_bank.h for the contract. The REAPER-facing half of the
// import: the project directory, the minted bank id, the birth records, and the one
// undo-batched persist. Every decision it makes is in import_landing / import_plan.
//
// main.cpp owns the API pointers; this TU gets them extern. DAW-verified, not unit tested.

#include "shell/package/import_bank.h"

#include <cstdint>
#include <ctime>
#include <string>
#include <vector>

#include "core/capture/capture_paths.h"  // projectDirOfRpp
#include "shell/bank_ops/bank_ops.h"     // persistBankOp — one bank op is one Ctrl-Z
#include "shell/persist/session.h"

#define REAPERAPI_MINIMAL
#define REAPERAPI_WANT_EnumProjects
#define REAPERAPI_WANT_genGuid
#define REAPERAPI_WANT_guidToString
#include "reaper_plugin_functions.h"

namespace reasampler {

namespace {

std::string activeProjectDir() {
    std::vector<char> buf(4096, '\0');
    EnumProjects(-1, buf.data(), static_cast<int>(buf.size()));
    return capture::projectDirOfRpp(std::string(buf.data()));
}

// The model mints no ids (it stays pure and deterministic), so the shell does — the
// same GUID pair bankOpCreate uses.
std::string mintBankId() {
    GUID g{};
    genGuid(&g);
    char buf[64] = {0};  // guidToString needs >=64 chars (SDK contract)
    guidToString(&g, buf);
    return std::string(buf);
}

void fillPlanCounts(ImportBankResult& out, const package::ImportPlan& plan) {
    out.bankDisplayName = plan.bankDisplayName;
    out.seedBankName = plan.seedBankName;
    out.bankNameAdjusted = plan.bankNameAdjusted;
    out.landedCount = plan.landCount;
    out.collisionRenameCount = plan.collisionRenameCount;
    out.sanitizeRenameCount = plan.sanitizeRenameCount;
    out.collapsedCount = plan.collapseCount;
}

}  // namespace

ImportBankResult importBankPackage(ReaSamplerSession& session,
                                   const std::string& packageAbsPath) {
    ImportBankResult out;

    // A per-import disambiguator, the same shape capture and ingest file under.
    const std::string uniqueTag =
        std::to_string(static_cast<std::int64_t>(std::time(nullptr)));

    LandedFileJournal journal;
    const ImportLanding landing = landPackage(packageAbsPath, activeProjectDir(),
                                              session.book(), uniqueTag, journal);
    out.outcome = landing.outcome;
    out.header = landing.header;
    out.failedEntryName = landing.failedEntryName;
    out.rollback = landing.rollback;
    fillPlanCounts(out, landing.plan);
    if (landing.outcome != ImportOutcome::Landed) return out;

    const std::string bankId = mintBankId();
    const bool applied = applyImportedBank(
        session.book(), bankId, landing.plan,
        [&session](const model::Sample& s) {
            session.recordCreated(s, tracking::OriginKind::PackageImport);
        });
    if (!applied) {
        out.outcome = ImportOutcome::IndexRejected;
        out.rollback = journal.rollback();
        return out;
    }
    out.bankId = bankId;

    // Generation bump + persist ride inside one undo block, so a Ctrl-Z takes the whole
    // import back out of the index. It does NOT un-write the files — the summary says so.
    persistBankOp(session, "ReaSampler: import bank package", /*bumpGeneration=*/true);
    // Only now: the files are referenced, so prune's self-cleanup carve-out no longer
    // covers them (see package_rollback.h).
    journal.markIndexCommitted();

    return out;
}

}  // namespace reasampler
