using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; using PARR.Core.Repositories.Interfaces.JobGroupRepositories; using PARR.Core.Repositories.Interfaces.JobRepositories; using PARR.Domain.Entities.Base.History; using PARR.Domain.Entities.JobEntities; using PARR.Domain.Enums; using PARR.TemplateMatcher.Services.GroupedSync; using PARR.TemplateMatcher.Services.Interfaces; namespace PARR.TemplateMatcher.Services.Implementations { internal class TemplateMatcher : ITemplateMatcher { private readonly ILogger _logger; private readonly IJobRepository _jobService; private readonly IJobGroupRepository _jobGroupService; private readonly IEnumerable _synchronizers; public TemplateMatcher( ILogger logger, IJobRepository jobService, IJobGroupRepository jobGroupService, IEnumerable synchronizers ) { _logger = logger; _jobService = jobService; _jobGroupService = jobGroupService; _synchronizers = synchronizers; } public async Task SyncTemplatesForJob(Guid jobId, HistoryInitiator initiator) { _logger.LogDebug("Начало синхронизации шаблонов для JobId {JobId}", jobId); var job = await GetJobWithGroupAndAutoControlAsync(jobId); if (job == null) { _logger.LogError("Job с Id {JobId} не найден.", jobId); return; } // Проверяем, является ли Job "групповым" bool isGroupJob = job.Group != null && job.Group.GroupType?.Code == JobGroupTypesEnum.Group; if (isGroupJob && job.Group!.GroupingUnitFieldId.HasValue) { _logger.LogInformation("Job {JobId} является групповым. Передаём в GroupedSynchronizer.", jobId); // Находим нужный синхронизатор var synchronizer = _synchronizers.FirstOrDefault(s => s is GroupedTemplateSynchronizer); if (synchronizer != null) { // Так как Job групповой, вызываем синхронизацию для его JobGroup await synchronizer.SyncTemplatesForJobGroupAsync(job.GroupId, initiator); } else { _logger.LogError("GroupedTemplateSynchronizer не найден."); } return; } else { _logger.LogInformation("Job {JobId} является обычным. Передаём в SimpleSynchronizer.", jobId); // Находим нужный синхронизатор var synchronizer = _synchronizers.FirstOrDefault(s => s is SimpleTemplateSynchronizer); if (synchronizer != null) { await synchronizer.SyncTemplatesForJobAsync(jobId, initiator); } else { _logger.LogError("SimpleTemplateSynchronizer не найден."); } return; } } public async Task SyncTemplatesForJobGroup(Guid jobGroupId, HistoryInitiator initiator) { _logger.LogDebug("Начало синхронизации шаблонов для JobGroup {JobGroupId}", jobGroupId); var jobGroup = await _jobGroupService.Get() .AsNoTracking() .Include(jg => jg.GroupType) .FirstOrDefaultAsync(jg => jg.Id == jobGroupId); if (jobGroup == null || jobGroup.GroupType == null) { _logger.LogWarning("JobGroup {JobGroupId} не найден или не содержит GroupType.", jobGroupId); return; } // Определяем стратегию по типу группы switch (jobGroup.GroupType.Code) { case JobGroupTypesEnum.Group: // Проверяем, есть ли GroupingUnitFieldId — это признак "настоящей" группировки if (jobGroup.GroupingUnitFieldId.HasValue) { _logger.LogInformation("JobGroup {JobGroupId} является Group с GroupingUnitFieldId. Передаём в GroupedTemplateSynchronizer.", jobGroupId); var synchronizer = _synchronizers.FirstOrDefault(s => s is GroupedTemplateSynchronizer); if (synchronizer != null) { await synchronizer.SyncTemplatesForJobGroupAsync(jobGroupId, initiator); } else { _logger.LogError("GroupedTemplateSynchronizer не найден для JobGroup {JobGroupId}.", jobGroupId); } } else { _logger.LogInformation("JobGroup {JobGroupId} является Group, но не имеет GroupingUnitFieldId. Обрабатываем как Collection.", jobGroupId); //await SyncJobGroupAsCollectionAsync(jobGroupId, initiator); } break; case JobGroupTypesEnum.Umbrella: _logger.LogInformation("JobGroup {JobGroupId} является Umbrella. Обрабатываем как Collection (каждый Job — независимо).", jobGroupId); await SyncJobGroupAsCollectionAsync(jobGroupId, initiator); break; case JobGroupTypesEnum.Simple: default: _logger.LogInformation("JobGroup {JobGroupId} имеет тип Simple. Обрабатываем как Collection.", jobGroupId); await SyncJobGroupAsCollectionAsync(jobGroupId, initiator); break; } } public async Task UpdateTemplatesForJobGroup(Guid jobGroupId, HistoryInitiator initiator) { _logger.LogDebug("Начало обновления шаблонов для JobGroup {JobGroupId}", jobGroupId); var jobGroup = await _jobGroupService.Get() .AsNoTracking() .Include(jg => jg.GroupType) .FirstOrDefaultAsync(jg => jg.Id == jobGroupId); if (jobGroup == null || jobGroup.GroupType == null) { _logger.LogWarning("JobGroup {JobGroupId} не найден или не содержит GroupType.", jobGroupId); return; } switch (jobGroup.GroupType.Code) { case JobGroupTypesEnum.Group: if (jobGroup.GroupingUnitFieldId.HasValue) { _logger.LogWarning("UpdateTemplatesForJobGroup не поддерживается для Group с GroupingUnitFieldId. Id: {JobGroupId}", jobGroupId); } else { _logger.LogInformation("JobGroup {JobGroupId} — Group без GroupingUnitFieldId. Обновляем как Collection.", jobGroupId); await UpdateJobGroupAsCollectionAsync(jobGroupId, initiator); } break; case JobGroupTypesEnum.Umbrella: _logger.LogInformation("JobGroup {JobGroupId} — Umbrella. Обновляем как Collection.", jobGroupId); await UpdateJobGroupAsCollectionAsync(jobGroupId, initiator); break; case JobGroupTypesEnum.Simple: default: _logger.LogInformation("JobGroup {JobGroupId} — Simple. Обновляем как Collection.", jobGroupId); await UpdateJobGroupAsCollectionAsync(jobGroupId, initiator); break; } } public async Task UpdateTemplatesForJob(Guid jobId, HistoryInitiator initiator) { _logger.LogDebug("Начало обновления шаблонов для JobId {JobId}", jobId); var job = await GetJobWithGroupAndAutoControlAsync(jobId); if (job == null) { _logger.LogError("Job с Id {JobId} не найден.", jobId); return; } // Проверяем, является ли Job "групповым" bool isGroupJob = job.Group != null && job.Group.GroupType?.Code == JobGroupTypesEnum.Group; if (isGroupJob && job.Group!.GroupingUnitFieldId.HasValue) { _logger.LogInformation("Job {JobId} является групповым. Передаём в GroupedSynchronizer для Update.", jobId); // Находим нужный синхронизатор var synchronizer = _synchronizers.FirstOrDefault(s => s is GroupedTemplateSynchronizer); if (synchronizer != null) { // Вызов UpdateTemplatesForJobAsync для GroupedTemplateSynchronizer (который делает предупреждение) await synchronizer.UpdateTemplatesForJobAsync(jobId, initiator); } else { _logger.LogError("GroupedTemplateSynchronizer не найден."); } return; } else { _logger.LogInformation("Job {JobId} является обычным. Передаём в SimpleSynchronizer для Update.", jobId); // Находим нужный синхронизатор var synchronizer = _synchronizers.FirstOrDefault(s => s is SimpleTemplateSynchronizer); if (synchronizer != null) { await synchronizer.UpdateTemplatesForJobAsync(jobId, initiator); } else { _logger.LogError("SimpleTemplateSynchronizer не найден."); } return; } } // --- Вспомогательные методы --- private async Task SyncJobGroupAsCollectionAsync(Guid jobGroupId, HistoryInitiator initiator) { _logger.LogDebug("Синхронизация JobGroup {JobGroupId} как Collection (по каждому Job'у отдельно)", jobGroupId); var jobIds = await _jobService.Get() .AsNoTracking() .Where(j => j.GroupId == jobGroupId) .Select(j => j.Id) .ToListAsync(); if (!jobIds.Any()) { _logger.LogWarning("JobGroup {JobGroupId} не содержит Job'ов.", jobGroupId); return; } _logger.LogDebug("Найдено {Count} Job'ов в JobGroup {JobGroupId}", jobIds.Count, jobGroupId); var simpleSynchronizer = _synchronizers.FirstOrDefault(s => s is SimpleTemplateSynchronizer); if (simpleSynchronizer == null) { _logger.LogError("SimpleTemplateSynchronizer не найден для синхронизации Job'ов в JobGroup {JobGroupId}.", jobGroupId); return; } foreach (var jobId in jobIds) { _logger.LogDebug("Синхронизация Job {JobId} в рамках JobGroup {JobGroupId}", jobId, jobGroupId); await simpleSynchronizer.SyncTemplatesForJobAsync(jobId, initiator); } _logger.LogInformation("Синхронизация JobGroup {JobGroupId} как Collection завершена.", jobGroupId); } private async Task UpdateJobGroupAsCollectionAsync(Guid jobGroupId, HistoryInitiator initiator) { _logger.LogDebug("Обновление JobGroup {JobGroupId} как Collection (по каждому Job'у)", jobGroupId); var jobIds = await _jobService.Get() .AsNoTracking() .Where(j => j.GroupId == jobGroupId) .Select(j => j.Id) .ToListAsync(); if (!jobIds.Any()) { _logger.LogWarning("JobGroup {JobGroupId} не содержит Job'ов.", jobGroupId); return; } foreach (var jobId in jobIds) { _logger.LogDebug("Обновление шаблонов для Job {JobId} в рамках JobGroup {JobGroupId}", jobId, jobGroupId); await UpdateTemplatesForJob(jobId, initiator); } _logger.LogInformation("Обновление JobGroup {JobGroupId} как Collection завершено.", jobGroupId); } private async Task GetJobWithGroupAndAutoControlAsync(Guid jobId) { return await _jobService.Get() .AsNoTracking() .Include(j => j.Group) .ThenInclude(j => j!.GroupType) .Include(j => j.AutoControl) .FirstOrDefaultAsync(j => j.Id == jobId); } } }