using SVSim.Database.Enums; namespace SVSim.Database.Repositories.Viewer; /// /// Lightweight profile shape used by chat surfaces (guild_chat, gathering_chat). /// Fields match the ChatUserDto wire shape. /// public record ChatUserProfile( string Name, long EmblemId, string CountryCode, int Rank, int DegreeId); /// /// Richer profile shape used by guild management surfaces (invite list, join-request list). /// Extends with IsOfficialMarkDisplayed. /// public record GuildMemberProfile( string Name, long EmblemId, string CountryCode, int Rank, int DegreeId, bool IsOfficialMarkDisplayed); public interface IViewerRepository { Task GetViewerBySocialConnection(SocialAccountType accountType, ulong socialId); Task GetViewerWithSocials(long id); Task GetViewerByShortUdid(long shortUdid); Task GetViewerByUdid(Guid udid); Task RegisterViewer(string displayName, SocialAccountType socialType, ulong socialAccountIdentifier, ulong? shortUdid = null); Task RegisterAnonymousViewer(Guid udid); Task LinkSteamToViewer(long viewerId, ulong steamId); /// /// Merges an anonymous viewer (just created by /tool/signup on a fresh UDID) /// into a target viewer that the Steam ticket resolved to. Transfers the anonymous /// viewer's UDID to the target, then deletes the anonymous viewer. /// Task MergeAnonymousViewerInto(long anonymousViewerId, long targetViewerId); /// /// Focused load for building a battle-node MatchContext: viewer + Info + Info's /// equipped Emblem/Degree nav refs. Read-only (AsNoTracking). Returns null if the viewer /// doesn't exist. /// Task LoadForMatchContextAsync(long viewerId); /// /// Focused load for class-XP grants: viewer with owned Classes collection and /// each ViewerClassData.Class nav ref included. Tracked (not AsNoTracking) so /// the caller can mutate Exp/Level and SaveChangesAsync. Returns /// null if the viewer does not exist. /// Task LoadForBattleXpGrantAsync(long viewerId, CancellationToken ct = default); /// /// Load a viewer with the joins 's Finish /// needs: Classes (for the class-XP grant) + RankProgress (for the rank grant). Split-query /// per project_ef_split_query to avoid the cartesian explosion when both nav /// collections are populated on the same viewer. /// Task LoadForRankProgressAsync(long viewerId, CancellationToken ct = default); /// Sets Viewer.GuildId to . No-op if the viewer does not exist. Task SetGuildIdAsync(long viewerId, int guildId, CancellationToken ct = default); /// Clears Viewer.GuildId to null. No-op if the viewer does not exist. Task ClearGuildIdAsync(long viewerId, CancellationToken ct = default); /// /// Batch-loads DisplayName for a set of viewer ids. Returns a dictionary keyed by viewer id; /// ids with no matching row are absent from the result. Read-only (AsNoTracking). /// Task> LoadDisplayNamesAsync(IReadOnlyCollection viewerIds, CancellationToken ct = default); /// /// Batch-loads the fields for a set of viewer ids. Used by chat /// surfaces (guild_chat, gathering_chat) to populate users[] without a direct DB context /// in the controller. Ids with no matching row are absent from the result. Read-only (AsNoTracking). /// Task> LoadChatProfilesAsync(IReadOnlyCollection viewerIds, CancellationToken ct = default); /// /// Batch-loads the fields (emblem, degree, /// IsOfficialMarkDisplayed) for a set of viewer ids. Used by guild management surfaces /// (invite_user_list, join_request_list). Ids with no matching row are absent. Read-only. /// Task> LoadGuildProfileBatchAsync(IReadOnlyCollection viewerIds, CancellationToken ct = default); /// /// Loads a viewer's currently-equipped emblem id, or 100_000_000 (default) if none. /// Used by to seed the guild's initial emblem. /// Returns 100_000_000 if the viewer doesn't exist. /// Task GetEquippedEmblemIdAsync(long viewerId, CancellationToken ct = default); /// /// Batch-loads owned guild-emblem ids for a viewer. Used by /guild/emblem_list. /// Task> GetEmblemListAsync(long viewerId, CancellationToken ct = default); }