using JSMR.Application.Integrations.Chobit.Models;
using JSMR.Application.Integrations.Chobit.Ports;
using JSMR.Application.Integrations.DLSite.Models;
using JSMR.Application.Integrations.DLSite.Models.ReleasedWorks;
using JSMR.Application.Integrations.DLSite.Ports;
using JSMR.Application.Scanning.Contracts;
using JSMR.Application.Scanning.Ports;
using JSMR.Domain.Enums;
using JSMR.Infrastructure.Common.Languages;

namespace JSMR.Infrastructure.Scanning;

public class VoiceWorkIngestBuilder(
    IDLSiteClient dlsiteClient,
    IChobitClient chobitClient,
    IReleasedWorksProvider releasedWorksProvider,
    ILanguageIdentifier languageIdentifier) : IVoiceWorkIngestBuilder
{
    public async Task<VoiceWorkIngest[]> BuildAsync(VoiceWorkScanResult scanResult, CancellationToken cancellationToken)
    {
        string[] productIds = [.. scanResult.Works.Where(x => !string.IsNullOrWhiteSpace(x.ProductId)).Select(x => x.ProductId!)];

        Task<VoiceWorkDetailCollection> detailsTask = dlsiteClient.GetVoiceWorkDetailsAsync(productIds, cancellationToken);
        Task<ChobitResultCollection> chobitTask = chobitClient.GetSampleInfoAsync(productIds, cancellationToken);
        Task<ReleasedWorksCollection> releasedTask = releasedWorksProvider.GetReleasedWorksAsync(scanResult, cancellationToken);

        await Task.WhenAll(detailsTask, chobitTask, releasedTask);

        VoiceWorkDetailCollection voiceWorkDetails = await detailsTask;
        ChobitResultCollection chobitResults = await chobitTask;
        ReleasedWorksCollection releasedWorkCollection = await releasedTask;

        List<VoiceWorkIngest> ingests = [];

        foreach (DLSiteWork work in scanResult.Works)
        {
            voiceWorkDetails.TryGetValue(work.ProductId!, out VoiceWorkDetails? details);
            chobitResults.TryGetValue(work.ProductId, out ChobitResult? chobit);
            releasedWorkCollection.TryGetValue(work.ProductId, out ReleasedWork? releasedWork);

            VoiceWorkIngest ingest = new()
            {
                MakerId = work.MakerId,
                MakerName = work.Maker,
                ProductId = work.ProductId,
                Title = details?.Title ?? work.ProductName,
                Description = work.Description ?? string.Empty,
                Tags = work.Tags,
                Creators = work.Creators,
                WishlistCount = details?.WishlistCount ?? 0,
                Downloads = Math.Max(work.Downloads, details?.DownloadCount ?? 0),
                HasTrial = work.HasTrial || (details?.HasTrial ?? false),
                HasChobit = chobit?.Count > 0,
                StarRating = work.StarRating,
                Votes = work.Votes,
                AgeRating = details?.AgeRating ?? work.AgeRating,
                HasImage = !string.IsNullOrEmpty(work.ImageUrl) && !work.ImageUrl.Contains("no_img", StringComparison.OrdinalIgnoreCase),
                SupportedLanguages = details?.SupportedLanguages ?? [],
                ExpectedDate = work.ExpectedDate,
                SalesDate = work.SalesDate,
                RegistrationDate = details?.RegistrationDate,
                AI = details?.AI ?? AIGeneration.None,
                Series = details?.Series,
                Translation = details?.Translation,
                Localizations = GetLocalizationIngests(releasedWork)
            };

            ingests.Add(ingest);
        }

        return [.. ingests];
    }

    private VoiceWorkLocalizationIngest[] GetLocalizationIngests(ReleasedWork? releasedWork)
    {
        if (releasedWork is null)
            return [];

        Language titleLanguage = languageIdentifier.GetLanguage(releasedWork.Title);
        Language descriptionLanguage = languageIdentifier.GetLanguage(releasedWork.Description);

        if (titleLanguage is not Language.English && descriptionLanguage is not Language.English)
            return [];

        VoiceWorkLocalizationIngest localizationIngest = new()
        {
            Title = releasedWork.Title,
            Description = releasedWork.Description,
            Language = Language.English
        };

        return [localizationIngest];
    }
}