using System.Data; using Dapper; using PlotLine.Models; namespace PlotLine.Data; public interface ICoreImportBasicLocationReviewRepository { Task GetByPreviewAsync(int userId, Guid previewId); Task ResetByPreviewAsync(int userId, Guid previewId); Task CreateAsync(int userId, Guid previewId, int projectId, int bookId, int? buildId); Task SaveCandidateAsync(int reviewId, CoreImportBasicLocationCandidate candidate); Task DeleteEvidenceAsync(int candidateId); Task SaveEvidenceAsync(int candidateId, CoreImportBasicLocationEvidence evidence); Task CompletePreparationAsync(int reviewId, int rawObservationCount, int candidateCount); Task<(IReadOnlyList Candidates, IReadOnlyList Evidence)> ListCandidatesAsync(int reviewId); Task SaveDecisionAsync(int reviewId, CoreImportBasicLocationDecision decision); Task SetResultAsync(int reviewId, string stableKey, int resultLocationId); Task MarkCompleteAsync(int reviewId); Task MarkSkippedAsync(int reviewId); } public sealed class CoreImportBasicLocationReviewRepository(ISqlConnectionFactory connectionFactory) : ICoreImportBasicLocationReviewRepository { public async Task GetByPreviewAsync(int userId, Guid previewId) { using var connection = connectionFactory.CreateConnection(); return await connection.QuerySingleOrDefaultAsync( "dbo.CoreImportBasicLocationReview_GetByPreview", new { UserID = userId, PreviewID = previewId }, commandType: CommandType.StoredProcedure); } public async Task ResetByPreviewAsync(int userId, Guid previewId) { using var connection = connectionFactory.CreateConnection(); await connection.ExecuteAsync( "dbo.CoreImportBasicLocationReview_ResetByPreview", new { UserID = userId, PreviewID = previewId }, commandType: CommandType.StoredProcedure); } public async Task CreateAsync(int userId, Guid previewId, int projectId, int bookId, int? buildId) { using var connection = connectionFactory.CreateConnection(); return await connection.QuerySingleAsync( "dbo.CoreImportBasicLocationReview_Create", new { UserID = userId, PreviewID = previewId, ProjectID = projectId, BookID = bookId, BuildID = buildId }, commandType: CommandType.StoredProcedure); } public async Task SaveCandidateAsync(int reviewId, CoreImportBasicLocationCandidate candidate) { using var connection = connectionFactory.CreateConnection(); return await connection.QuerySingleAsync( "dbo.CoreImportBasicLocationReview_SaveCandidate", new { CoreImportBasicLocationReviewID = reviewId, candidate.StableKey, candidate.ProposedName, candidate.PreferredName, candidate.KnownNamesJson, candidate.ParentLocationID, candidate.ParentCandidateKey, candidate.ExistingLocationID, candidate.FirstChapterNumber, candidate.FirstSceneNumber, candidate.FirstOccurrenceIndex, candidate.ObservationCount, candidate.SortOrder }, commandType: CommandType.StoredProcedure); } public async Task DeleteEvidenceAsync(int candidateId) { using var connection = connectionFactory.CreateConnection(); await connection.ExecuteAsync( "dbo.CoreImportBasicLocationReview_DeleteEvidence", new { CoreImportBasicLocationCandidateID = candidateId }, commandType: CommandType.StoredProcedure); } public async Task SaveEvidenceAsync(int candidateId, CoreImportBasicLocationEvidence evidence) { using var connection = connectionFactory.CreateConnection(); await connection.ExecuteAsync( "dbo.CoreImportBasicLocationReview_SaveEvidence", new { CoreImportBasicLocationCandidateID = candidateId, evidence.SceneID, evidence.ChapterID, evidence.ChapterNumber, evidence.SceneNumber, evidence.OccurrenceIndex, evidence.EvidenceText, evidence.SortOrder }, commandType: CommandType.StoredProcedure); } public async Task CompletePreparationAsync(int reviewId, int rawObservationCount, int candidateCount) { using var connection = connectionFactory.CreateConnection(); await connection.ExecuteAsync( "dbo.CoreImportBasicLocationReview_CompletePreparation", new { CoreImportBasicLocationReviewID = reviewId, RawObservationCount = rawObservationCount, CandidateCount = candidateCount }, commandType: CommandType.StoredProcedure); } public async Task<(IReadOnlyList Candidates, IReadOnlyList Evidence)> ListCandidatesAsync(int reviewId) { using var connection = connectionFactory.CreateConnection(); using var rows = await connection.QueryMultipleAsync( "dbo.CoreImportBasicLocationReview_ListCandidates", new { CoreImportBasicLocationReviewID = reviewId }, commandType: CommandType.StoredProcedure); var candidates = (await rows.ReadAsync()).ToList(); var evidence = (await rows.ReadAsync()).ToList(); return (candidates, evidence); } public async Task SaveDecisionAsync(int reviewId, CoreImportBasicLocationDecision decision) { using var connection = connectionFactory.CreateConnection(); await connection.ExecuteAsync( "dbo.CoreImportBasicLocationReview_SaveDecision", new { CoreImportBasicLocationReviewID = reviewId, decision.StableKey, decision.PreferredName, decision.Action, decision.ParentLocationID, decision.ParentCandidateKey, decision.SameAsLocationID, decision.SameAsCandidateKey }, commandType: CommandType.StoredProcedure); } public async Task SetResultAsync(int reviewId, string stableKey, int resultLocationId) { using var connection = connectionFactory.CreateConnection(); await connection.ExecuteAsync( "dbo.CoreImportBasicLocationReview_SetResult", new { CoreImportBasicLocationReviewID = reviewId, StableKey = stableKey, ResultLocationID = resultLocationId }, commandType: CommandType.StoredProcedure); } public async Task MarkCompleteAsync(int reviewId) { using var connection = connectionFactory.CreateConnection(); await connection.ExecuteAsync( "dbo.CoreImportBasicLocationReview_MarkComplete", new { CoreImportBasicLocationReviewID = reviewId }, commandType: CommandType.StoredProcedure); } public async Task MarkSkippedAsync(int reviewId) { using var connection = connectionFactory.CreateConnection(); await connection.ExecuteAsync( "dbo.CoreImportBasicLocationReview_MarkSkipped", new { CoreImportBasicLocationReviewID = reviewId }, commandType: CommandType.StoredProcedure); } }