using Microsoft.EntityFrameworkCore; using RadicadeServer.DB; using RadicadeServer.Extensions; using RadicadeServer.RecNet.Config; namespace RadicadeServer.Clubs; public sealed class PlayerSubscriptionRecord { public long subscriberAccountId { get; set; } public long creatorAccountId { get; set; } public DateTime createdAt { get; set; } = DateTime.UtcNow; } public static class PlayerSubscriptions { private const string ConfigKey = "PlayerSubscriptions"; private const long PersonalClubIdBase = 1_000_000_000_000L; public static long PersonalClubId(long accountId) => accountId > 0 ? PersonalClubIdBase + accountId : 0; public static bool IsPersonalClubId(long clubId) => clubId >= PersonalClubIdBase; public static long? AccountIdForPersonalClub(long clubId) => IsPersonalClubId(clubId) ? clubId - PersonalClubIdBase : null; public static async Task> LoadAsync(RecDBContext db) { var config = await db.ServerConfig.AsNoTracking().FirstOrDefaultAsync(x => x.Key == ConfigKey); if (config == null || string.IsNullOrWhiteSpace(config.Value)) return new List(); try { return config.Value.FromJson>() ?? new List(); } catch { return new List(); } } private static async Task SaveAsync(RecDBContext db, List subscriptions) { var config = await db.ServerConfig.FirstOrDefaultAsync(x => x.Key == ConfigKey); if (config == null) { config = new ServerConfigVal(ConfigKey, "[]"); await db.ServerConfig.AddAsync(config); } config.Value = subscriptions.ToJson(); await db.SaveChangesAsync(); } public static async Task SubscribeAsync(RecDBContext db, long subscriberId, long creatorId) { if (subscriberId <= 0 || creatorId <= 0 || subscriberId == creatorId) return false; var subscriptions = await LoadAsync(db); if (subscriptions.Any(x => x.subscriberAccountId == subscriberId && x.creatorAccountId == creatorId)) return true; subscriptions.Add(new PlayerSubscriptionRecord { subscriberAccountId = subscriberId, creatorAccountId = creatorId }); await SaveAsync(db, subscriptions); return true; } public static async Task UnsubscribeAsync(RecDBContext db, long subscriberId, long creatorId) { var subscriptions = await LoadAsync(db); if (subscriptions.RemoveAll(x => x.subscriberAccountId == subscriberId && x.creatorAccountId == creatorId) == 0) return false; await SaveAsync(db, subscriptions); return true; } public static async Task> SubscriptionIdsAsync(RecDBContext db, long accountId) => (await LoadAsync(db)) .Where(x => x.subscriberAccountId == accountId) .Select(x => x.creatorAccountId) .Distinct() .ToList(); public static async Task> SubscriberIdsAsync(RecDBContext db, long accountId) => (await LoadAsync(db)) .Where(x => x.creatorAccountId == accountId) .Select(x => x.subscriberAccountId) .Distinct() .ToList(); public static async Task SubscriberCountAsync(RecDBContext db, long accountId) => (await SubscriberIdsAsync(db, accountId)).Count; public static async Task> TopCreatorsAsync(RecDBContext db, int limit) { var creators = (await LoadAsync(db)) .GroupBy(x => x.creatorAccountId) .Select(group => new { clubId = PersonalClubId(group.Key), accountId = group.Key, subscriberCount = group.Select(x => x.subscriberAccountId).Distinct().Count() }) .OrderByDescending(creator => creator.subscriberCount) .ThenBy(creator => creator.accountId) .Take(limit) .ToList(); return creators.Cast().ToList(); } }