| | | 1 | | using Chronicis.Api.Data; |
| | | 2 | | using Chronicis.Shared.DTOs; |
| | | 3 | | using Chronicis.Shared.Enums; |
| | | 4 | | using Microsoft.EntityFrameworkCore; |
| | | 5 | | |
| | | 6 | | namespace Chronicis.Api.Services; |
| | | 7 | | |
| | | 8 | | public sealed class DashboardReadService : IDashboardReadService |
| | | 9 | | { |
| | | 10 | | private readonly ChronicisDbContext _context; |
| | | 11 | | private readonly IPromptService _promptService; |
| | | 12 | | |
| | | 13 | | public DashboardReadService(ChronicisDbContext context, IPromptService promptService) |
| | | 14 | | { |
| | 2 | 15 | | _context = context; |
| | 2 | 16 | | _promptService = promptService; |
| | 2 | 17 | | } |
| | | 18 | | |
| | | 19 | | public async Task<DashboardDto> GetDashboardAsync(Guid userId, string userDisplayName) |
| | | 20 | | { |
| | | 21 | | var worldIds = await _context.WorldMembers |
| | | 22 | | .Where(wm => wm.UserId == userId) |
| | | 23 | | .Select(wm => wm.WorldId) |
| | | 24 | | .ToListAsync(); |
| | | 25 | | |
| | | 26 | | var worlds = await _context.Worlds |
| | | 27 | | .Where(w => worldIds.Contains(w.Id)) |
| | | 28 | | .Include(w => w.Campaigns) |
| | | 29 | | .ThenInclude(c => c.Arcs) |
| | | 30 | | .Include(w => w.Articles) |
| | | 31 | | .OrderBy(w => w.Name) |
| | | 32 | | .ToListAsync(); |
| | | 33 | | |
| | | 34 | | var claimedCharacters = await _context.Articles |
| | | 35 | | .Where(a => a.PlayerId == userId && a.Type == ArticleType.Character) |
| | | 36 | | .Where(a => a.WorldId.HasValue && worldIds.Contains(a.WorldId.Value)) |
| | | 37 | | .Select(a => new ClaimedCharacterDto |
| | | 38 | | { |
| | | 39 | | Id = a.Id, |
| | | 40 | | Title = a.Title ?? "Unnamed Character", |
| | | 41 | | IconEmoji = a.IconEmoji, |
| | | 42 | | WorldId = a.WorldId!.Value, |
| | | 43 | | WorldName = a.World != null ? a.World.Name : "Unknown World", |
| | | 44 | | ModifiedAt = a.ModifiedAt, |
| | | 45 | | CreatedAt = a.CreatedAt |
| | | 46 | | }) |
| | | 47 | | .ToListAsync(); |
| | | 48 | | |
| | | 49 | | var dashboardWorlds = new List<DashboardWorldDto>(); |
| | | 50 | | foreach (var world in worlds) |
| | | 51 | | { |
| | | 52 | | var dashboardWorld = new DashboardWorldDto |
| | | 53 | | { |
| | | 54 | | Id = world.Id, |
| | | 55 | | Name = world.Name, |
| | | 56 | | Slug = world.Slug, |
| | | 57 | | Description = world.Description, |
| | | 58 | | CreatedAt = world.CreatedAt, |
| | | 59 | | ArticleCount = world.Articles?.Count ?? 0, |
| | | 60 | | Campaigns = new List<DashboardCampaignDto>(), |
| | | 61 | | MyCharacters = new List<DashboardCharacterDto>() |
| | | 62 | | }; |
| | | 63 | | |
| | | 64 | | var worldRoot = world.Articles?.FirstOrDefault(a => a.ParentId == null && a.Type == ArticleType.WikiArticle) |
| | | 65 | | dashboardWorld.WorldRootArticleId = worldRoot?.Id; |
| | | 66 | | |
| | | 67 | | if (world.Campaigns != null) |
| | | 68 | | { |
| | | 69 | | foreach (var campaign in world.Campaigns.OrderByDescending(c => c.IsActive).ThenBy(c => c.Name)) |
| | | 70 | | { |
| | | 71 | | var sessionCount = await _context.Sessions |
| | | 72 | | .AsNoTracking() |
| | | 73 | | .CountAsync(s => s.Arc.CampaignId == campaign.Id); |
| | | 74 | | |
| | | 75 | | var dashboardCampaign = new DashboardCampaignDto |
| | | 76 | | { |
| | | 77 | | Id = campaign.Id, |
| | | 78 | | Name = campaign.Name, |
| | | 79 | | Description = campaign.Description, |
| | | 80 | | CreatedAt = campaign.CreatedAt, |
| | | 81 | | StartedAt = campaign.StartedAt, |
| | | 82 | | IsActive = campaign.IsActive, |
| | | 83 | | SessionCount = sessionCount, |
| | | 84 | | ArcCount = campaign.Arcs?.Count ?? 0 |
| | | 85 | | }; |
| | | 86 | | |
| | | 87 | | var activeArc = campaign.Arcs? |
| | | 88 | | .Where(a => a.IsActive) |
| | | 89 | | .OrderByDescending(a => a.SortOrder) |
| | | 90 | | .FirstOrDefault(); |
| | | 91 | | |
| | | 92 | | if (activeArc != null) |
| | | 93 | | { |
| | | 94 | | var arcSessionCount = await _context.Sessions |
| | | 95 | | .AsNoTracking() |
| | | 96 | | .CountAsync(s => s.ArcId == activeArc.Id); |
| | | 97 | | |
| | | 98 | | var latestSession = await _context.Sessions |
| | | 99 | | .AsNoTracking() |
| | | 100 | | .Where(s => s.ArcId == activeArc.Id) |
| | | 101 | | .OrderByDescending(s => s.SessionDate ?? s.CreatedAt) |
| | | 102 | | .FirstOrDefaultAsync(); |
| | | 103 | | |
| | | 104 | | dashboardCampaign.CurrentArc = new DashboardArcDto |
| | | 105 | | { |
| | | 106 | | Id = activeArc.Id, |
| | | 107 | | Name = activeArc.Name, |
| | | 108 | | Description = activeArc.Description, |
| | | 109 | | SessionCount = arcSessionCount, |
| | | 110 | | LatestSessionDate = latestSession?.SessionDate ?? latestSession?.CreatedAt |
| | | 111 | | }; |
| | | 112 | | } |
| | | 113 | | |
| | | 114 | | dashboardWorld.Campaigns.Add(dashboardCampaign); |
| | | 115 | | } |
| | | 116 | | } |
| | | 117 | | |
| | | 118 | | dashboardWorld.MyCharacters = claimedCharacters |
| | | 119 | | .Where(c => c.WorldId == world.Id) |
| | | 120 | | .Select(c => new DashboardCharacterDto |
| | | 121 | | { |
| | | 122 | | Id = c.Id, |
| | | 123 | | Title = c.Title, |
| | | 124 | | IconEmoji = c.IconEmoji, |
| | | 125 | | ModifiedAt = c.ModifiedAt, |
| | | 126 | | CreatedAt = c.CreatedAt |
| | | 127 | | }) |
| | | 128 | | .ToList(); |
| | | 129 | | |
| | | 130 | | dashboardWorlds.Add(dashboardWorld); |
| | | 131 | | } |
| | | 132 | | |
| | | 133 | | var dashboard = new DashboardDto |
| | | 134 | | { |
| | | 135 | | UserDisplayName = userDisplayName, |
| | | 136 | | Worlds = dashboardWorlds, |
| | | 137 | | ClaimedCharacters = claimedCharacters, |
| | | 138 | | Prompts = new List<PromptDto>() |
| | | 139 | | }; |
| | | 140 | | |
| | | 141 | | dashboard.Prompts = _promptService.GeneratePrompts(dashboard); |
| | | 142 | | return dashboard; |
| | | 143 | | } |
| | | 144 | | } |
| | | 145 | | |