using System.Data; using Dapper; using PlotLine.Models; namespace PlotLine.Data; public interface IStoryIntelligenceRepository { Task CreateWithConsentAsync(int userId, int onboardingStateId, int projectId, int bookId, string consentText); Task GetAsync(int userId, Guid jobId); Task GetLatestForUserAsync(int userId); Task ClaimNextPendingAsync(); Task UpdateProgressAsync(Guid jobId, string status, int progressPercent, string currentStage, string currentMessage, string? estimatedRemaining); Task CompleteAsync(Guid jobId); Task CancelAsync(int userId, Guid jobId); Task FailAsync(Guid jobId, string errorMessage); } public sealed class StoryIntelligenceRepository(ISqlConnectionFactory connectionFactory) : IStoryIntelligenceRepository { public async Task CreateWithConsentAsync(int userId, int onboardingStateId, int projectId, int bookId, string consentText) { using var connection = connectionFactory.CreateConnection(); return await connection.QuerySingleOrDefaultAsync( "dbo.StoryIntelligenceJob_CreateWithConsent", new { UserID = userId, UserOnboardingStateID = onboardingStateId, ProjectID = projectId, BookID = bookId, ConsentText = consentText }, commandType: CommandType.StoredProcedure); } public async Task GetAsync(int userId, Guid jobId) { using var connection = connectionFactory.CreateConnection(); return await connection.QuerySingleOrDefaultAsync( "dbo.StoryIntelligenceJob_Get", new { UserID = userId, JobID = jobId }, commandType: CommandType.StoredProcedure); } public async Task GetLatestForUserAsync(int userId) { using var connection = connectionFactory.CreateConnection(); return await connection.QuerySingleOrDefaultAsync( "dbo.StoryIntelligenceJob_GetLatestForUser", new { UserID = userId }, commandType: CommandType.StoredProcedure); } public async Task ClaimNextPendingAsync() { using var connection = connectionFactory.CreateConnection(); return await connection.QuerySingleOrDefaultAsync( "dbo.StoryIntelligenceJob_ClaimNextPending", commandType: CommandType.StoredProcedure); } public async Task UpdateProgressAsync(Guid jobId, string status, int progressPercent, string currentStage, string currentMessage, string? estimatedRemaining) { using var connection = connectionFactory.CreateConnection(); return await connection.QuerySingleOrDefaultAsync( "dbo.StoryIntelligenceJob_UpdateProgress", new { JobID = jobId, Status = status, ProgressPercent = progressPercent, CurrentStage = currentStage, CurrentMessage = currentMessage, EstimatedRemaining = estimatedRemaining }, commandType: CommandType.StoredProcedure); } public async Task CompleteAsync(Guid jobId) { using var connection = connectionFactory.CreateConnection(); return await connection.QuerySingleOrDefaultAsync( "dbo.StoryIntelligenceJob_Complete", new { JobID = jobId }, commandType: CommandType.StoredProcedure); } public async Task CancelAsync(int userId, Guid jobId) { using var connection = connectionFactory.CreateConnection(); return await connection.QuerySingleOrDefaultAsync( "dbo.StoryIntelligenceJob_Cancel", new { UserID = userId, JobID = jobId }, commandType: CommandType.StoredProcedure); } public async Task FailAsync(Guid jobId, string errorMessage) { using var connection = connectionFactory.CreateConnection(); return await connection.QuerySingleOrDefaultAsync( "dbo.StoryIntelligenceJob_Fail", new { JobID = jobId, ErrorMessage = errorMessage }, commandType: CommandType.StoredProcedure); } }