using SVSim.Database.Enums; using SVSim.Database.Models; namespace SVSim.Database.Services; /// /// The single read/ownership authority for what a viewer is *treated as* owning. Knows the /// Freeplay flag; all freeplay read-side behavior lives here. See /// docs/superpowers/specs/2026-05-29-freeplay-mode-design.md. /// /// /// Include precondition: methods that inspect the viewer's collections require the /// viewer to have been loaded with .Include(v => v.Cards).ThenInclude(c => c.Card) /// and the cosmetic collections /// (Sleeves, Emblems, Degrees, LeaderSkins, MyPageBackgrounds) /// included. Without those includes the EF owned-collection nav refs are null or zero-filled /// (see the EF owned-collection nav-include pitfall in MEMORY.md). /// public interface IViewerEntitlements { /// True when the global Freeplay config section is enabled. bool IsFreeplay { get; } /// /// The balance the viewer is treated as having: the configured freeplay amount for /// Crystal/Rupee/RedEther when freeplay is on, otherwise (and always for SpotPoint) the real /// viewer.Currency field. /// long EffectiveBalance(Viewer viewer, SpendCurrency currency); bool OwnsCard(Viewer viewer, long cardId); /// uses (Skin == leader skin). bool OwnsCosmetic(Viewer viewer, CosmeticType type, int id); /// The full owned-card projection for /load/index's user_card_list. Task> EffectiveOwnedCardsAsync(Viewer viewer, CancellationToken ct = default); /// The cosmetic id-lists + leader-skin catalog/owned-set for /load/index. Task EffectiveCosmeticsAsync(Viewer viewer, CancellationToken ct = default); } /// /// Cosmetic projection bundle for /load/index. The four id-lists are "what the viewer owns" /// (all of them in freeplay). Leader skins are always the full catalog with a per-skin owned flag; /// is every skin id in freeplay. /// public sealed record EffectiveCosmetics( IReadOnlyList SleeveIds, IReadOnlyList EmblemIds, IReadOnlyList DegreeIds, IReadOnlyList MyPageBackgroundIds, IReadOnlyList AllLeaderSkins, IReadOnlySet OwnedLeaderSkinIds);