// shell/package/export_bank — the promptless bank-export verb: survey, digest,
// stream, commit. No prompts and no message boxes (shell/actions/
// package_export_action is the skin). The session arrives CONST, which is how "an
// export writes no ext state, opens no undo point and never bumps the bank
// generation" is enforced rather than remembered — those three acts
// (saveToActiveProject, bumpBankGeneration, writeAssignmentRequest) are exactly the
// session members that are non-const (session.h:113,108,147). Constness does not
// block every mutation, though: pruneReclaim (session.h:140-141) is const and is
// the system's sole file-deletion path — irrelevant to export, but not something a
// const session forbids in general. Blocking I/O: UI-thread actions only.

#pragma once

#include <cstddef>
#include <cstdint>
#include <string>
#include <vector>

#include "core/package/bank_package.h"
#include "core/package/export_plan.h"

namespace reasampler {

class ReaSamplerSession;

struct ExportRequest {
    std::string projectDir;       // absolute; the root the index's relative paths hang off
    std::string bankId;
    std::string destAbsPath;      // the .rsbank to write
    std::int64_t exportTimestamp = 0;  // manifest envelope; the caller's clock read
    // Both default false and are set ONLY after the skin's explicit confirm: one
    // lists what is absent, the other names the destination being replaced.
    bool allowIncomplete = false;
    bool allowOverwrite = false;
};

enum class ExportStatus {
    Written,
    NoSuchBank,
    NoProjectDir,
    RefusedIncomplete,
    RefusedUnrepresentable,
    RefusedDestinationExists,
    SourceReadFailed,  // a file the plan classified Present would not read, or is empty
    SourceChanged,     // a payload's bytes moved between the digest pass and the stream pass
    EncodeFailed,
    WriteFailed,
};

struct ExportOutcome {
    ExportStatus status = ExportStatus::WriteFailed;
    std::size_t entriesWritten = 0;
    std::uint64_t bytesWritten = 0;
    std::string bankDisplayName;
    std::vector<package::ExcludedEntry> excluded;
    std::string offendingName;  // the entry a SourceReadFailed / SourceChanged names
};

struct ExportSurvey {
    bool bankFound = false;
    package::ExportPlan plan;
};

// Report-before-acting: the same plan exportBank recomputes, with nothing written.
// Read-only against both the project and the filesystem.
ExportSurvey surveyBankExport(const ReaSamplerSession& session,
                              const std::string& projectDir,
                              const std::string& bankId);

// Fills each manifest entry's byteLength and byteHash from its source file — the
// digest pass, one payload in memory at a time. False with `outFailedName` set when a
// source will not read or is empty; a zero-length entry cannot round-trip the
// format's own seam, so it is a failure here rather than an entry.
bool digestSources(package::PackageManifest& manifest,
                   const std::vector<std::string>& sourceAbsPaths,
                   std::string& outFailedName);

// Streams one package to `destAbsPath`: the encoded prefix, then each payload re-read
// from `sourceAbsPaths` (parallel to `manifest.entries`) and re-checked against the
// length and digest recorded for it before it is appended — so the digest the
// manifest claims describes the bytes actually written, not the bytes a concurrent
// edit replaced. Any failure abandons the writer, leaving the destination absent or
// holding its prior contents.
//
// Public because that atomicity is this function's property: proving it needs a
// failure injected mid-stream, which is a call to this seam, not to exportBank.
ExportOutcome writePackageFile(const package::EncodedPackage& encoded,
                               const package::PackageManifest& manifest,
                               const std::vector<std::string>& sourceAbsPaths,
                               const std::string& destAbsPath);

// The verb: plan, gate on the verdict and the destination, digest, encode, stream.
ExportOutcome exportBank(const ReaSamplerSession& session, const ExportRequest& req);

}  // namespace reasampler
