using JSMR.Application.Scanning.Ports; using JSMR.Domain.Entities; using JSMR.Infrastructure.Data; using Microsoft.EntityFrameworkCore; using System.Text; namespace JSMR.Infrastructure.Ingestion; public class VoiceWorkSearchUpdater(AppDbContext dbContext) : IVoiceWorkSearchUpdater { public async Task UpdateAsync(int[] voiceWorkIds, CancellationToken cancellationToken) { List batch = await dbContext.VoiceWorks .Where(vw => voiceWorkIds.Contains(vw.VoiceWorkId)) .AsSplitQuery() .Include(vw => vw.Circle) .Include(vw => vw.Tags) .ThenInclude(vwt => vwt.Tag) .Include(vw => vw.Creators) .ThenInclude(vwc => vwc.Creator) .Include(vw => vw.EnglishVoiceWorks) .ToListAsync(cancellationToken); Dictionary existingSearches = await dbContext.VoiceWorkSearches .Where(s => voiceWorkIds.Contains(s.VoiceWorkId)) .ToDictionaryAsync(s => s.VoiceWorkId, cancellationToken); int[] tagIds = [.. batch.SelectMany(vw => vw.Tags).Select(vwt => vwt.TagId).Distinct()]; Dictionary englishTags = await dbContext.EnglishTags .Where(et => tagIds.Contains(et.TagId)) .ToDictionaryAsync(et => et.TagId, cancellationToken); foreach (var voiceWork in batch) { try { UpdateSearchText(voiceWork, existingSearches, englishTags); } catch (Exception ex) { Console.WriteLine($"⚠️ Error updating VoiceWorkId {voiceWork.VoiceWorkId}: {ex.Message}"); } } await dbContext.SaveChangesAsync(cancellationToken); } private void UpdateSearchText(VoiceWork voiceWork, Dictionary existingSearches, Dictionary englishTags) { string searchText = GetSearchText(voiceWork, englishTags); if (!existingSearches.TryGetValue(voiceWork.VoiceWorkId, out var searchEntry)) { dbContext.VoiceWorkSearches.Add(new VoiceWorkSearch { VoiceWorkId = voiceWork.VoiceWorkId, SearchText = searchText }); } else { if (!string.Equals(searchEntry.SearchText, searchText, StringComparison.Ordinal)) { searchEntry.SearchText = searchText; } } } private string GetSearchText(VoiceWork voiceWork, Dictionary englishTags) { var english = voiceWork.EnglishVoiceWorks.FirstOrDefault(); var sb = new StringBuilder(); AppendRaw(sb, voiceWork.ProductId); AppendRaw(sb, voiceWork.Circle?.MakerId); AppendRaw(sb, english?.ProductName); AppendRaw(sb, english?.Description); AppendRaw(sb, voiceWork.ProductName); AppendRaw(sb, voiceWork.Description); AppendRaw(sb, voiceWork.Circle?.Name); foreach (var tag in voiceWork.Tags.Select(vwt => vwt.Tag)) { if (tag is null) continue; AppendRaw(sb, tag.Name); if (englishTags.TryGetValue(tag.TagId, out var englishTag)) AppendRaw(sb, englishTag.Name); } foreach (var creator in voiceWork.Creators.Select(vwc => vwc.Creator)) { if (creator is null) continue; AppendRaw(sb, creator?.Name); } string searchText = sb.ToString().Trim(); return searchText; } private static void AppendRaw(StringBuilder sb, string? text) { if (!string.IsNullOrWhiteSpace(text)) sb.Append(text).Append(' '); } }