using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using PARR.Core.Repositories.Interfaces;
using PARR.Core.Services.NextRunServices;
using PARR.Domain.Entities;
using PARR.Domain.Entities.Base.History;
using PARR.Domain.Enums;

namespace PARR.NextRun.Services
{
    internal class NextRunUpdateService : INextRunUpdateService
    {
        private readonly ILogger<NextRunUpdateService> logger;
        private readonly ITemplateRepository templateService;
        private readonly INextRunService nextRunService;
        private readonly IRobotConfigurationRepository robotConfigurationService;

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

        public async Task UpdateNextRunForTemplatesAsync(Func<IQueryable<Template>, IQueryable<Template>> filter, Func<IHistoryInitiator> getInitiator, string operationName)
        {
            var query = templateService.Get()
                                        .Include(t => t.RobotConfigurations)
                                        .Where(t => t.StatusTypeId == TemplateStatusTypeEnum.Used);

            var templates = await filter(query).ToListAsync();

            logger.LogInformation("[{operationName}] Найдено шаблонов в статусе Used для обработки: {count}", operationName, templates.Count);

            if (!templates.Any())
            {
                logger.LogInformation("[{operationName}] Шаблоны не найдены, выходим", operationName);
                return;
            }

            var updatedCount = 0;

            foreach (var template in templates)
            {
                var wasUpdated = await UpdateNextRunAsync(template);

                if (wasUpdated)
                    updatedCount++;
            }

            if (updatedCount == 0)
            {
                logger.LogInformation("[{operationName}] Нет изменённых nextRun, сохранение не требуется", operationName);
                return;
            }

            var initiator = getInitiator();
            var commitResult = await templateService.CommitAsync(initiator);

            if (commitResult)
                logger.LogInformation("[{operationName}] Успешно обновлено {count} шаблонов", operationName, updatedCount);
            else
                logger.LogError("[{operationName}] Ошибка при сохранении {count} шаблонов в БД", operationName, updatedCount);

        }



        /// <summary>
        /// Обновляет если надо nextRun для одного шаблона, если может, ставит задание на обновление
        /// </summary>
        /// <param name="template"></param>
        /// <param name="nextRunService"></param>
        /// <param name="robotConfigurationService"></param>
        /// <param name="templateName"></param>
        /// <param name="logger"></param>
        /// <returns></returns>
        private async Task<bool> UpdateNextRunAsync(Template template)
        {
            var newNextRun = await nextRunService.GetNextRunForTemplateAsync(template.Id, false);

            if (!newNextRun.HasValue)
            {
                logger.LogError("При расчете nextRun для шаблона {templateId}, '{templateName}' вернулся null. Это значит что при расчете возникла ошибка.", template.Id, template.Name);
                return false;
            }

            if (template.NextRun == newNextRun.Value)
            {
                logger.LogDebug("NextRun для шаблона {templateId}, '{templateName}' не изменился: {nextRun}", template.Id, template.Name, newNextRun.Value);
                return false;
            }

            logger.LogInformation("Обновление NextRun: шаблон {templateId}, '{templateName}'. Было: {oldNextRun}, стало: {newNextRun}", template.Id, template.Name, template.NextRun, newNextRun.Value);

            template.LastRun = template.NextRun;
            template.NextRun = newNextRun.Value;

            //так как nextRun обновился, пробуем поставить задание на обновление
            var config = robotConfigurationService.GetFromTemplateByRobotCode(RobotsEnum.ScheduleOrder, template);
            robotConfigurationService.SetUpdateTaskStatusIfAllow(config);

            //шаблон изменен и нужен Commit
            return true;
        }

    }
}
