using LiteCqrs; using Microsoft.EntityFrameworkCore; using TeleWave.Application.Broadcast; using TeleWave.Application.Common.Interfaces; using TeleWave.Application.Common.Models; using TeleWave.Domain.Programming; namespace TeleWave.Application.Programming.Templates.Transfer; public sealed class ExportGridQueryHandler(IAppDbContext dbContext) : IQueryHandler> { public async Task> Handle( ExportGridQuery query, CancellationToken cancellationToken ) { var channel = await dbContext .Channels.AsNoTracking() .FirstOrDefaultAsync(c => c.Id == query.ChannelId, cancellationToken); if (channel is null) return Result.Failure(ChannelErrors.NotFound); var template = await dbContext .ScheduleTemplates.AsNoTracking() .Include(t => t.Layers) .ThenInclude(l => l.Slots) .AsSplitQuery() .FirstOrDefaultAsync(t => t.ChannelId == query.ChannelId, cancellationToken); if (template is null) return Result.Failure(ChannelErrors.TemplateNotFound); var groups = await dbContext .Groups.AsNoTracking() .ToDictionaryAsync(g => g.Id, g => g.Name, cancellationToken); var junctions = await dbContext .JunctionTemplates.AsNoTracking() .ToDictionaryAsync(j => j.Id, j => j.Name, cancellationToken); var layers = template .Layers.OrderBy(l => l.Priority) .Select(layer => new GridConfigLayer( layer.Name, layer.Priority, [ .. layer .Slots.OrderBy(s => s.Weekday ?? -1) .ThenBy(s => s.TargetStart) .Select(slot => ToConfig(slot, groups, junctions)), ], layer.IsEnabled, layer.IsBackground, LayerApplicability.FromJson(layer.ApplicabilityJson) )) .ToList(); return Result.Success( new GridConfig( layers, Channel: new GridConfigChannel( channel.Name, channel.DayStartTime, channel.UtcOffsetMinutes ), Rules: PlanningRules.FromJson(template.RulesJson), FallbackGroup: Name(template.FallbackGroupId, groups), DefaultJunction: Name(template.DefaultJunctionId, junctions) ) ); } private static GridConfigSlot ToConfig( Slot slot, IReadOnlyDictionary groups, IReadOnlyDictionary junctions ) => new( slot.Title, slot.TargetStart, slot.TargetDurationMinutes, slot.Daypart, slot.SlotKind, slot.Weekday, Name(slot.GroupId, groups), SlotStrategy.FromJson(slot.StrategyJson), RepeatSource.FromJson(slot.RepeatSourceJson), slot.BlockMode, slot.BlockValue, slot.OverflowPolicy, slot.IsAnchor, slot.MaxDriftMinutes, slot.SnapToMinutes, Name(slot.JunctionBetweenId, junctions), Name(slot.JunctionAfterId, junctions) ); /// Имя по ссылке. Пропавшая ссылка выгружается пустой — файл важнее её сохранности. private static string? Name(Guid? id, IReadOnlyDictionary names) => id is { } value ? names.GetValueOrDefault(value) : null; }