using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using PARR.Core.Repositories.Interfaces;
using PARR.Core.Services.NextRunServices;
using PARR.Domain.Common.Rabbit.Messages;
using PARR.Domain.Enums;

namespace PARR.TemplateDistributor
{
    internal class TemplateDistributor : ITemplateDistributor
    {
        private readonly ILogger<TemplateDistributor> logger;
        //private readonly INextRunService nextRunService;
        private readonly INextRunService nextRunService;
        private readonly ITemplateRepository templateService;
        private readonly IRobotConfigurationRepository robotConfigurationService;

        public TemplateDistributor(
            ILogger<TemplateDistributor> logger,
            //INextRunService nextRunService,
            INextRunService nextRunService,
            ITemplateRepository templateService,
            IRobotConfigurationRepository robotConfigurationService
            )
        {
            this.logger = logger;
            this.nextRunService = nextRunService;
            this.templateService = templateService;
            this.robotConfigurationService = robotConfigurationService;
        }


        public async Task DistributeAsync(TemplateDistributorMq mqResponse)
        {
            var jobGroupId = mqResponse.JobGroupId;
            // распределяем шаблоны только в статусе Used
            var templateStatusType = TemplateStatusTypeEnum.Used;

            // вызвать метод распределения, и получить новые даты
            var distributedTemplates = await nextRunService.GetNextRunForJobGroupWithAutoDistributionAsync(jobGroupId, templateStatusType);

            if (distributedTemplates == null)
            {
                logger.LogError("При распределении шаблонов по jobGroupId {jobGroupId} вернулся null. Это ошибка. Прекращаю распределение.", jobGroupId);
                return;
            }

            // получить список шаблонов, сравнить их с распределенными, обновить даты, сохранить
            var groupTemplates = await templateService.Get()
                                            .Include(t => t.RobotConfigurations)
                                            .Where(t => t.Job!.GroupId == jobGroupId && t.StatusTypeId == templateStatusType)
                                            .ToListAsync();

            if (!groupTemplates.Any())
            {
                logger.LogWarning("Для jobGroupId {jobGroupId} не найдено ни одного шаблона в БД. Прекращаю обновление.", jobGroupId);
                return;
            }

            // создать словарь для быстрого поиска
            var distributedDict = distributedTemplates.ToDictionary(t => t.Id);

            int updatedCount = 0;

            foreach (var templateDb in groupTemplates)
            {
                if (distributedDict.TryGetValue(templateDb.Id, out var distributedTemplate))
                {
                    if (templateDb.NextRun != distributedTemplate.NextRun)
                    {
                        templateDb.NextRun = distributedTemplate.NextRun;
                        templateDb.LastRun = distributedTemplate.NextRunOld;
                        templateDb.DateModified = DateTimeOffset.UtcNow;

                        // ставим задание роботу - обновить расписания
                        var config = robotConfigurationService.GetFromTemplateByRobotCode(RobotsEnum.ScheduleOrder, templateDb);
                        //robotConfigurationService.ChangeTaskStatus(TaskStatusEnum.Updating, config);
                        robotConfigurationService.SetUpdateTaskStatusIfAllow(config);

                        updatedCount++;
                    }
                }
                else
                {
                    logger.LogWarning("Шаблон с Id {templateId} не найден в распределённых данных.", templateDb.Id);
                }
            }

            if (updatedCount > 0)
            {
                // сохранить изменения
                if (await templateService.CommitAsync(mqResponse.Initiator))
                {
                    logger.LogInformation("Обновлено {updatedCount} шаблонов в БД для jobGroupId {jobGroupId}. Для расписаний установлен статус: {taskStatus}", updatedCount, jobGroupId, TaskStatusEnum.Updating.ToString());
                }
                else
                {
                    logger.LogError("Ошибка при обновлении записей в БД. jobGroupId {jobGroupId}, требовалось обновить шаблонов: {updatedCount}", jobGroupId, updatedCount);
                }
            }
            else
            {
                logger.LogInformation("Для jobGroupId {jobGroupId} не найдено изменений. Ничего не обновлено.", jobGroupId);
            }
        }
    }
}
