using PlotLine.Data; using PlotLine.Models; using PlotLine.ViewModels; namespace PlotLine.Services; public interface IStoryIntelligenceGlobalProgressService { Task GetForCurrentUserAsync(); Task GetForUserAsync(int userId); } public sealed class StoryIntelligenceGlobalProgressService( ICurrentUserService currentUser, IStoryIntelligenceResultRepository runs) : IStoryIntelligenceGlobalProgressService { public async Task GetForCurrentUserAsync() { if (currentUser.UserId is not int userId) { return new StoryIntelligenceGlobalProgressViewModel(); } return await GetForUserAsync(userId); } public async Task GetForUserAsync(int userId) { var summaries = await runs.ListActiveBookRunSummariesForUserAsync(userId); var books = new List(); foreach (var summary in summaries) { var bookRuns = summary.BookID.HasValue ? await runs.ListRunsByBookForUserAsync(summary.BookID.Value, userId) : []; var relevantRuns = bookRuns .Where(run => run.CreatedUtc >= summary.FirstCreatedUtc && run.Status is StoryIntelligenceRunStatuses.Pending or StoryIntelligenceRunStatuses.Running or StoryIntelligenceRunStatuses.Completed or StoryIntelligenceRunStatuses.CompletedWithWarnings or StoryIntelligenceRunStatuses.Failed or StoryIntelligenceRunStatuses.Cancelled) .Select(run => new StoryIntelligenceGlobalProgressRunViewModel { RunID = run.StoryIntelligenceRunID, ProjectID = run.ProjectID, BookID = run.BookID, BookTitle = string.IsNullOrWhiteSpace(summary.BookDisplayTitle) ? "Book" : summary.BookDisplayTitle, Status = string.IsNullOrWhiteSpace(run.Status) ? StoryIntelligenceRunStatuses.Pending : run.Status, TotalDetectedScenes = run.TotalDetectedScenes ?? 0, CompletedScenes = run.CompletedScenes ?? 0, FailedScenes = run.FailedScenes ?? 0, TotalDurationMs = run.TotalDurationMs ?? 0, UpdatedUtc = run.UpdatedUtc }) .ToList(); books.Add(new StoryIntelligenceGlobalProgressBookViewModel { ProjectID = summary.ProjectID, BookID = summary.BookID, BookTitle = string.IsNullOrWhiteSpace(summary.BookDisplayTitle) ? "Book" : summary.BookDisplayTitle, RunCount = summary.RunCount, PendingRunCount = summary.PendingRunCount, RunningRunCount = summary.RunningRunCount, CompletedRunCount = summary.CompletedRunCount, FailedRunCount = summary.FailedRunCount, TotalExpectedScenes = summary.TotalExpectedScenes, CompletedScenes = summary.CompletedScenes, FailedScenes = summary.FailedScenes, ActiveScenes = summary.ActiveScenes, Status = summary.Status, TotalDurationMs = summary.TotalDurationMs, UpdatedUtc = summary.UpdatedUtc, Runs = relevantRuns }); } return new StoryIntelligenceGlobalProgressViewModel { Books = books }; } }