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<ScanVoiceWorksResponse> 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
        );
    }
}