namespace SVSim.Database.Repositories.Card; /// /// Mutating operations on a viewer's card inventory (destruct, create, protect…). /// Read-only catalog queries live on . /// public interface ICardInventoryRepository { /// /// Validate-then-mutate destruct of owned cards. Atomic: all validation runs before any /// mutation, and the mutation phase is wrapped in an explicit DB transaction so a mid-flight /// EF failure rolls back currency + inventory + deck-strip together. /// /// Authenticated viewer. /// cardId → num_to_destruct. Empty dict is rejected by the caller. /// /// with post-state totals on success, or a /// when validation fails. On error nothing is written. /// Task DestructCards(long viewerId, IReadOnlyDictionary destructCounts); /// /// Validate-then-mutate craft of cards from RedEther. Atomic in a transaction; on validation /// failure nothing is written. Routes Card grants through /// so the CardCosmeticReward cascade fires for first-time owners. /// /// cardId → num_to_create. Empty dict is rejected by the caller. Task CreateCards(long viewerId, IReadOnlyDictionary createCounts); } /// /// Either a success payload or an error code. Discriminated by which field is set. /// public sealed record DestructOutcome(DestructResult? Result, DestructError? Error) { public bool IsSuccess => Result is not null; public static DestructOutcome Ok(DestructResult r) => new(r, null); public static DestructOutcome Fail(DestructError e) => new(null, e); } public sealed record DestructResult( ulong NewRedEtherTotal, IReadOnlyDictionary NewOwnedCounts); // cardId → post-destruct Count public enum DestructError { UnknownCard, NotDestructible, CardProtected, InsufficientCards, } public sealed record CreateOutcome(CreateResult? Result, CreateError? Error) { public bool IsSuccess => Result is not null; public static CreateOutcome Ok(CreateResult r) => new(r, null); public static CreateOutcome Fail(CreateError e) => new(null, e); } /// /// Outcome of a successful create. is the flattened /// list returned by /// — one Card entry per crafted cardId plus any cosmetic-cascade entries. /// public sealed record CreateResult( ulong NewRedEtherTotal, IReadOnlyList Grants); public enum CreateError { UnknownCard, NotCraftable, WouldExceedMaxCopies, InsufficientVials, }