#pragma once
// assignment_request — pure core of the ingest assignment-request seam. No
// REAPER/SWELL/VST3/vendor includes; unit-tested outside the DAW.
//
// When the extension ingests a sample it writes an assignment request to its
// own ext-state namespace: "the active sampler instance should now play THIS
// sample." Owns only the wire format — the persist shell writes it, the
// instrument reads it, both must agree on the byte layout. The extension
// writing its own namespace does not violate the instrument's
// read-only-over-the-bank rule.
//
// `generation` exists because re-assigning the SAME (bankId, sampleId) would
// be indistinguishable from a stale value without a changing field; the
// writer supplies a unix-epoch stamp so the reader can tell "assigned again
// just now" from "already saw this."

#include <cstdint>
#include <optional>
#include <string>

namespace reasampler::wire {

// One assignment request: the ingested sample's identity + a monotonic disambiguator.
// generation is an opaque "did this change?" token (writer supplies unix-epoch
// seconds); the reader never interprets it as a wall-clock.
struct AssignmentRequest {
    std::string  bankId;
    std::string  sampleId;
    std::int64_t generation = 0;

    bool operator==(const AssignmentRequest& o) const {
        return bankId == o.bankId && sampleId == o.sampleId &&
               generation == o.generation;
    }
    bool operator!=(const AssignmentRequest& o) const { return !(*this == o); }
};

// Length-prefixed fields behind a magic+version tag, so arbitrary bytes in an
// id round-trip whole with no escaping ambiguity. Deterministic.
//   "rsassign1" <len>':'<bankId> <len>':'<sampleId> <len>':'<generation-decimal>
std::string encodeAssignmentRequest(const AssignmentRequest& req);

// std::nullopt on any malformed/truncated/trailing-garbage input (never UB,
// never a partial value); the reader treats that as "no pending request."
// Round-trips: decodeAssignmentRequest(encodeAssignmentRequest(x)) == x.
//
// Reader requirement: an undo can roll back the `banks` key without atomically
// clearing `assign_request`, so after decoding, the reader must verify
// (bankId, sampleId) still resolves to an existing sample and silently drop it
// otherwise — never crash or select a nonexistent entry.
std::optional<AssignmentRequest> decodeAssignmentRequest(const std::string& wire);

} // namespace reasampler::wire
