using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; using PARR.Core.Repositories.Interfaces.Unit; using PARR.Core.Services.UnitFilterService.Models; using PARR.Domain.Entities.Job; using PARR.TemplateMatcher.Services.GroupedSync; internal class UnitInTemplateConflictMapper : IUnitInTemplateConflictMapper { private readonly ILogger logger; private readonly IUnitRepository unitRepository; private readonly IUnitKiiUnitRepository unitKiiUnitRepository; public UnitInTemplateConflictMapper( ILogger logger, IUnitRepository unitRepository, IUnitKiiUnitRepository unitKiiUnitRepository) { this.logger = logger; this.unitRepository = unitRepository; this.unitKiiUnitRepository = unitKiiUnitRepository; } public async Task>> BuildMappingAsync( IEnumerable unitFilterResults, Job maxJob, CancellationToken cancellationToken = default) { logger.LogDebug("Начало разрешения конфликтов и построения маппинга для юнитов в шаблонах."); var unitFilterResultsList = unitFilterResults.ToList(); if (!unitFilterResultsList.Any()) return new Dictionary>(); var potentialAssignments = new Dictionary>(); var allPotentialRelatedUnitIds = new HashSet(); var allUnitInTemplateIds = new HashSet(); foreach (var dto in unitFilterResultsList) { var relatedUnitIds = maxJob.IsParentRelationships == true ? dto.Children.Select(c => c.UnitId).ToList() : dto.Parents.Select(p => p.UnitId).ToList(); var unitInTemplateId = dto.Id; allUnitInTemplateIds.Add(unitInTemplateId); allPotentialRelatedUnitIds.UnionWith(relatedUnitIds); foreach (var relatedId in relatedUnitIds) { if (!potentialAssignments.TryGetValue(relatedId, out var list)) { list = new List(); potentialAssignments[relatedId] = list; } list.Add(unitInTemplateId); } } if (!allPotentialRelatedUnitIds.Any()) return new Dictionary>(); var relatedUnitNames = await unitRepository.Get() .AsNoTracking() .Where(u => allPotentialRelatedUnitIds.Contains(u.Id)) .ToDictionaryAsync(u => u.Id, u => u.Name ?? u.Id.ToString(), cancellationToken); // Загружаем идентификаторы КИИ через ваш реальный репозиторий var kiiUnitIds = new HashSet(await unitKiiUnitRepository.Get() .Select(k => k.UnitId) .ToListAsync(cancellationToken)); logger.LogDebug("Загружено {KiiCount} идентификаторов КИИ юнитов для приоритезации.", kiiUnitIds.Count); var unitInTemplateToBestRelatedUnit = new Dictionary(); foreach (var unitInTemplateId in allUnitInTemplateIds) { var candidates = potentialAssignments .Where(kvp => kvp.Value.Contains(unitInTemplateId)) .Select(kvp => kvp.Key) .ToList(); if (candidates.Count == 0) continue; if (candidates.Count == 1) { unitInTemplateToBestRelatedUnit[unitInTemplateId] = candidates[0]; continue; } var kiiCandidates = candidates.Where(id => kiiUnitIds.Contains(id)).ToList(); var candidatesToConsider = kiiCandidates.Any() ? kiiCandidates : candidates; var relationshipCounts = new Dictionary(); foreach (var candidateId in candidatesToConsider) { int totalRelationships = 0; foreach (var dto in unitFilterResultsList) { if (maxJob.IsParentRelationships == true && dto.Children.Any(c => c.UnitId == candidateId)) totalRelationships += dto.Children.Count; else if (maxJob.IsParentRelationships == false && dto.Parents.Any(p => p.UnitId == candidateId)) totalRelationships += dto.Parents.Count; } relationshipCounts[candidateId] = totalRelationships; } var bestCandidate = candidatesToConsider[0]; int bestCount = relationshipCounts[bestCandidate]; foreach (var candidateId in candidatesToConsider.Skip(1)) { int currentCount = relationshipCounts[candidateId]; if (currentCount > bestCount || (currentCount == bestCount && string.Compare( relatedUnitNames.GetValueOrDefault(candidateId, candidateId.ToString()), relatedUnitNames.GetValueOrDefault(bestCandidate, bestCandidate.ToString()), StringComparison.OrdinalIgnoreCase) < 0)) { bestCandidate = candidateId; bestCount = currentCount; } } unitInTemplateToBestRelatedUnit[unitInTemplateId] = bestCandidate; } logger.LogDebug("Разрешение конфликтов завершено. Найдено {Count} однозначных назначений.", unitInTemplateToBestRelatedUnit.Count); var reverseMapping = new Dictionary>(); foreach (var kvp in unitInTemplateToBestRelatedUnit) { if (!reverseMapping.TryGetValue(kvp.Value, out var list)) { list = new List(); reverseMapping[kvp.Value] = list; } list.Add(kvp.Key); } return reverseMapping; } }