using JSMR.Application.Common.Caching; using JSMR.Application.Scanning.Contracts; using JSMR.Application.Scanning.Ports; namespace JSMR.Application.Scanning; public sealed class ScanVoiceWorksHandler( IVoiceWorkScannerRepository scannerRepository, IVoiceWorkUpdaterRepository updaterRepository, ISpamCircleCache spamCircleCache, IVoiceWorkIngestBuilder ingestBuilder, IVoiceWorkSearchUpdater searchUpdater) { public async Task HandleAsync(ScanVoiceWorksRequest request, CancellationToken cancellationToken) { IVoiceWorksScanner? scanner = scannerRepository.GetScanner(request.Locale); IVoiceWorkUpdater? updater = updaterRepository.GetUpdater(request.Locale); if (scanner is null) throw new InvalidOperationException($"No scanner registered for locale {request.Locale}."); if (updater is null) throw new InvalidOperationException($"No updater registered for locale {request.Locale}."); VoiceWorkScanOptions options = new( PageNumber: request.PageNumber, PageSize: request.PageSize, ExcludedMakerIds: await spamCircleCache.GetAsync(cancellationToken), ExcludePartiallyAIGeneratedWorks: true, ExcludeAIGeneratedWorks: true ); VoiceWorkScanResult scanResult = await scanner.ScanPageAsync(options, cancellationToken); if (scanResult.EndOfResults) { return new ScanVoiceWorksResponse( Results: [], EndOfResults: true ); } VoiceWorkIngest[] ingests = await ingestBuilder.BuildAsync(scanResult, cancellationToken); VoiceWorkUpsertResult[] upsertResults = await updater.UpsertAsync(ingests, cancellationToken); int[] voiceWorkIds = [.. upsertResults.Where(x => x.VoiceWorkId.HasValue).Select(x => x.VoiceWorkId!.Value)]; await searchUpdater.UpdateAsync(voiceWorkIds, cancellationToken); return new ScanVoiceWorksResponse( Results: upsertResults, EndOfResults: false ); } }