using AutoMapper;
using FluentValidation;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using PARR.API.Contracts.V1;
using PARR.API.Contracts.V1.Requests;
using PARR.API.Contracts.V1.Requests.Queries;
using PARR.API.Contracts.V1.Responses;
using PARR.API.Contracts.V1.Responses.Base;
using PARR.API.Controllers.V1.Base;
using PARR.API.Extensions;
using PARR.API.Services.Interfaces;
using PARR.API.Settings;
using PARR.Core.Common.Helpers;
using PARR.Core.Common.Interfaces.RabbitServices;
using PARR.Core.Extensions;
using PARR.Core.Repositories.Interfaces;
using PARR.Core.Repositories.Interfaces.Job;
using PARR.Core.Repositories.Interfaces.Unit;
using PARR.Core.Services.MatchingStatusService;
using PARR.Core.Services.UnitFilterService;
using PARR.Domain.Common.Pagination;
using PARR.Domain.Common.Rabbit.Messages;
using PARR.Domain.Common.Roles;
using PARR.Domain.Entities.Base.History;
using PARR.Domain.Entities.Job;
using PARR.Domain.Enums;

namespace PARR.API.Controllers.V1
{
    /// <summary>
    /// Управление работами
    /// </summary>
    [Authorize(Roles = ParrRoles.Administrator.Role)]
    public class JobController : BaseApiController
    {
        private readonly ILogger<JobController> logger;
        private readonly IMapper mapper;
        private readonly IUriService uriService;
        private readonly IJobRepository jobService;
        private readonly ITemplateRepository templateService;
        //private readonly IValidator<JobRequest> jobValidator;
        private readonly IRabbitService mqService;
        private readonly MqSettings mqSettings;
        private readonly IClientService clientService;
        private readonly IJobAutoControlRepository jobAutoControlService;
        private readonly IMatchingStatusService matchingStatusService;

        public JobController(
            ILogger<JobController> logger,
            IMapper mapper,
            IUriService uriService,
            IJobRepository jobService,
            ITemplateRepository templateService,
            IJobGroupRepository jobGroupService,
            //IValidator<JobRequest> jobValidator,
            IUnitFilterService unitFilterService,
            IUnitRepository unitService,
            IRabbitService mqService,
            MqSettings mqSettings,
            IClientService clientService,
            IJobAutoControlRepository jobAutoControlService,
            IMatchingStatusService matchingStatusService
            )
        {
            this.logger = logger;
            this.mapper = mapper;
            this.uriService = uriService;
            this.jobService = jobService;
            this.templateService = templateService;
            //this.jobValidator = jobValidator;
            this.mqService = mqService;
            this.mqSettings = mqSettings;
            this.clientService = clientService;
            this.jobAutoControlService = jobAutoControlService;
            this.matchingStatusService = matchingStatusService;
        }

        /// <summary>
        /// Получить список заданий на выполнение работ(Job) постранично
        /// </summary>
        /// <returns></returns>
        [HttpGet(ApiRoutes.Job.GetAll)]
        public async Task<IActionResult> GetAll([FromQuery] PaginationQuery paginationQuery, [FromQuery] JobQuery filter)
        {
            var paginationFilter = mapper.Map<PaginationFilter>(paginationQuery);

            IQueryable<Job> query = jobService.Get().Include(t => t.AutoControl);

            query = query.OrderBy(t => t.Name);

            if (!string.IsNullOrEmpty(filter.Name))
            {
                //query = query.Where(t => t.Name.ToLower().Contains(filter.Name.ToLower()));
                query = query.Where(t=>EF.Functions.Like(t.Name.ToLower(), SqlHelpers.RegexToLike(filter.Name)));
            }
                

            if (filter.GroupId.HasValue)
                query = query.Where(t => t.GroupId == filter.GroupId.Value);

            if (filter.TnkId.HasValue)
                query = query.Where(t => t.TnkId == filter.TnkId.Value);


            if (filter.IsFull)
            {
                query = query
                    .Include(t => t.Tnk)
                    .Include(t => t.Group).ThenInclude(t => t.GroupType)
                    .Include(t => t.Group).ThenInclude(t => t.GroupingUnitField);

                query = query
                    .Include(t => t.UnitFilters)
                        .ThenInclude(t => t.FieldFilters)
                            .ThenInclude(t => t.UnitField)
                    .Include(t => t.UnitFilters)
                        .ThenInclude(t => t.RelationshipFilters)
                            .ThenInclude(t => t.UnitField);
            }

            var jobs = await jobService.GetPage(query, paginationFilter).ToListAsync();

            if (!jobs.Any())
                return NoContent();

            var response = mapper.Map<List<JobResponse>>(jobs);//TODO Migration to job

            foreach (var jobResponse in response)
            {
                //jobResponse.TemplatesCount = await templateService.Get().CountAsync(t => t.JobId == jobResponse.Id);
                jobResponse.TemplatesCount = await GetCountTemplatesAsync(jobResponse.Id);

                if (filter.IsFull)
                {
                    jobResponse.MatchingStatus = await GetMatchingStatusAsync(jobResponse.Id);
                }
            }

            var paginationResponse = new PagedResponse<JobResponse>(response, true).GetPaginatedProps(paginationFilter, query);

            return Ok(paginationResponse);
        }


        /// <summary>
        /// Получить задание на выполнение работ по id
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpGet(ApiRoutes.Job.Get)]
        public async Task<IActionResult> GetById([FromRoute] Guid id)
        {
            var job = await jobService.Get()
                                .Include(t => t.Tnk)
                                .Include(t => t.Group).ThenInclude(t => t.GroupType)
                                .Include(t => t.Group).ThenInclude(t => t.GroupingUnitField)
                                .Include(t => t.UnitFilters)
                                    .ThenInclude(t => t.FieldFilters)
                                        .ThenInclude(t => t.UnitField)
                                .Include(t => t.UnitFilters)
                                    .ThenInclude(t => t.RelationshipFilters)
                                        .ThenInclude(t => t.UnitField)
                                .Include(t => t.AutoControl)
                                .FirstOrDefaultAsync(t => t.Id == id);

            if (job == null)
                return NotFound();

            var response = mapper.Map<JobResponse>(job);

            response.TemplatesCount = await GetCountTemplatesAsync(id); //await templateService.Get().CountAsync(t => t.JobId == id);
            response.MatchingStatus = await GetMatchingStatusAsync(id);

            //var statistics = await GetStatisticsAsync(response.Id);
            //BindStatistics(response, statistics);

            return Ok(new Response<JobResponse>(response, true));
        }


        /// <summary>
        /// Создать задание на выполнение работ (Job)
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [HttpPost(ApiRoutes.Job.Create)]
        public async Task<IActionResult> Create([FromBody] JobRequest request)
        {
            //#region Валидация
            //var jobValidateResult = await jobValidator.ValidateAsync(request);//Валидация параметров самого задания

            //if (!jobValidateResult.IsValid)
            //    return BadRequest(new Response(jobValidateResult.Errors));
            //#endregion

            //TODO: !!!!!!! проверить, если тип ЗОНТИК или ГРУППИРОВКА, то обязательно должны быть заполнены поля min max

            #region Проверка существования работы с такими же параметрами

            var isExistTheSameLinks = await jobService.Get()
                                            .Include(t => t.Group).ThenInclude(t => t.GroupType)
                                            .CountAsync(t =>
                                                //t.Group!.GroupType!.Code == JobGroupTypesEnum.Umbrella
                                                (t.Group!.GroupType!.Code == JobGroupTypesEnum.Umbrella || t.Group!.GroupType!.Code == JobGroupTypesEnum.Group) &&
                                                t.GroupId == request.GroupId &&
                                                (t.MinValueRelationships == request.MinValueRelationships ||
                                                t.MaxValueRelationships == request.MaxValueRelationships)
                                            );

            if (isExistTheSameLinks > 0)
                return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel { FieldName = nameof(request.Name), Message = $"Работа с указанным диапазоном связей пересекается с уже имеющейся в базе данных({request.MinValueRelationships}-{request.MaxValueRelationships})" } }));

            #endregion


            var job = mapper.Map<Job>(request);

            job.AutoControl = new JobAutoControl
            {
                JobId = job.Id,
                IsEnable = request.IsEnableAutoControl,
                InitUsedScheduleState = request.InitUsedScheduleState,
                InitUsedTemplateState = request.InitUsedTemplateState
            };

            if (!await jobService.CreateAsync(job) || !await jobService.CommitAsync())
                return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel { Message = "Ошибка при созании задания на выполнение работ" } }));

            logger.LogInformation($"Пользователь {User.Identity?.Name} добавил задание на выполнение работ: {job.Id}, {job.Name}, {job.WorkName}");

            var createdJob = await jobService.Get()
                                .Include(t => t.Tnk)
                                .Include(t => t.Group).ThenInclude(t => t.GroupType)
                                .Include(t => t.Group).ThenInclude(t => t.GroupingUnitField)
                                .Include(t => t.UnitFilters)
                                    .ThenInclude(t => t.FieldFilters)
                                        .ThenInclude(t => t.UnitField)
                                .Include(t => t.UnitFilters)
                                    .ThenInclude(t => t.RelationshipFilters)
                                .Include(t => t.AutoControl)
                                .FirstOrDefaultAsync(t => t.Id == job.Id);

            var locationUri = uriService.GetUri(ApiRoutes.Job.Get, ApiRoutes.Job.getParam, createdJob!.Id);

            var response = mapper.Map<JobResponse>(createdJob);
            // так как мы только что создали Job, то у него нет шаблонов, смело ставим = 0 (ускоряем запрос)
            response.TemplatesCount = 0;
            response.MatchingStatus = await GetMatchingStatusAsync(response.Id);

            return Created(locationUri, new Response<JobResponse>(response, true));
        }


        /// <summary>
        /// Обновить задание на выполнение работ (Job)
        /// </summary>
        /// <param name="id"></param>
        /// <param name="request"></param>
        /// <returns></returns>
        [HttpPut(ApiRoutes.Job.Update)]
        public async Task<IActionResult> Update([FromRoute] Guid id, [FromBody] JobRequest request)
        {
            //var resultValidate = await jobValidator.ValidateAsync(request);
            //if (!resultValidate.IsValid)
            //    return BadRequest(new Response(resultValidate.Errors));

            var orig = await jobService.Get()
                                .Include(t => t.Tnk)
                                .Include(t => t.Group).ThenInclude(t => t.GroupType)
                                .Include(t => t.Group).ThenInclude(t => t.GroupingUnitField)
                                .Include(t => t.UnitFilters)
                                    .ThenInclude(t => t.FieldFilters)
                                .Include(t => t.UnitFilters)
                                    .ThenInclude(t => t.RelationshipFilters)
                                .Include(t => t.AutoControl)
                                .AsSingleQuery()
                                .FirstOrDefaultAsync(t => t.Id == id);

            if (orig == null)
                return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel { Message = $"Ошибка при изменении задания на выполнение работ. Не найдено задание с Id: {id}" } }));

            // если изменили маску шаблона, ниже отправим в очередь, на изменение связанных имен шаблонов
            var isChangedTemplateNameMask = orig.TemplateNameMask != request.TemplateNameMask.Trim();


            //TODO: ВОТ ЭТО ВООБЩЕ МЫ БУДЕМ ПРОВЕРЯТЬ, АААА???? - Проверка существования работы с такими же параметрами

            //TODO: !!!!!!! проверить, если тип ЗОНТИК или ГРУППИРОВКА, то обязательно должны быть заполнены поля min max

            #region обновление полей задания на работу

            orig.Name = request.Name.Trim();
            orig.WorkName = request.WorkName.Trim();
            orig.MinValueRelationships = request.MinValueRelationships;
            orig.MaxValueRelationships = request.MaxValueRelationships;
            orig.IsParentRelationships = request.IsParentRelationships;
            orig.TemplateNameMask = request.TemplateNameMask.Trim();
            orig.WorkGroupMask = request.WorkGroupMask.Trim();
            orig.TnkId = request.TnkId;
            orig.GroupId = request.GroupId;
            orig.ResponseAreaMask = request.ResponseAreaMask.Trim();

            if (orig.AutoControl != null)
            {
                orig.AutoControl.IsEnable = request.IsEnableAutoControl;
                orig.AutoControl.InitUsedScheduleState = request.InitUsedScheduleState;
                orig.AutoControl.InitUsedTemplateState = request.InitUsedTemplateState;
            }
            else
            {
                // автоконтрол не загружен, проверяем есть ли он в бд, если нет, то создадим
                var existAutoControl = await jobAutoControlService.Get().FirstOrDefaultAsync(t => t.JobId == id);
                if (existAutoControl != null)
                {
                    logger.LogError($"При обновлении job {id}, не загрузась связь с JobAutoControl, но она есть. Не стал обновлять Job, вернул ошибку.");
                    return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel { Message = $"Ошибка при изменении задания на выполнение работ." } }));
                }
                else
                {
                    var autoControl = new JobAutoControl
                    {
                        JobId = id,
                        InitUsedScheduleState = request.InitUsedScheduleState,
                        InitUsedTemplateState = request.InitUsedTemplateState,
                        IsEnable = request.IsEnableAutoControl
                    };
                    orig.AutoControl = autoControl;
                    logger.LogWarning($"При обновлении job {id}, отсутствовала запись в таблице JobAutoControl, создал ее. {autoControl.ToJson()}");
                }
            }


            orig.DateModified = DateTimeOffset.UtcNow;
            #endregion

            var job = mapper.Map<Job>(request);
            job.Id = id;//На всякий. Пусть будет для чистоты

            UpdateUnitFilters(orig, job);//Обновление вложенных дочерних элементов-фильтров

            if (!await jobService.CommitAsync())
                return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel { Message = "Ошибка при изменении задания на выполнение работ." } }));

            // если изменили маску, отправим задание на переименование связанных шаблонов
            if (isChangedTemplateNameMask)
            {
                var mqResult = await SendRequestToUpdateTemplates(id);
                //todo: если ошибка. пользователя не предупреждаем... возможно ему это и не нужно знать...ну не переименуются шаблоны, может они переименуются позже...
            }

            logger.LogInformation($"Пользователь {User.Identity?.Name} обновил задание на выполнение работ: {orig.Id}," +
                $" {orig.Name}, {orig.WorkName}, {orig.MinValueRelationships}, {orig.MaxValueRelationships}," +
                $" {orig.TemplateNameMask}, {orig.TnkId}, {nameof(orig.GroupId)}");


            var updatedJob = await jobService.Get()
                                        .Include(t => t.Tnk)
                                        .Include(t => t.Group).ThenInclude(t => t.GroupType)
                                        .Include(t => t.Group).ThenInclude(t => t.GroupingUnitField)
                                        .Include(t => t.UnitFilters)
                                            .ThenInclude(t => t.FieldFilters)
                                            .ThenInclude(t => t.UnitField)
                                        .Include(t => t.UnitFilters)
                                            .ThenInclude(t => t.RelationshipFilters)
                                        .Include(t => t.AutoControl)
                                        .FirstAsync(t => t.Id == orig.Id);

            var response = mapper.Map<JobResponse>(updatedJob);
            response.TemplatesCount = await GetCountTemplatesAsync(id); //await templateService.Get().CountAsync(t => t.JobId == id);
            response.MatchingStatus = await GetMatchingStatusAsync(id);

            //не используется
            //var statistics = await GetStatisticsAsync(response.Id);
            //BindStatistics(response, statistics);

            return Ok(new Response<JobResponse>(response, true));
        }


        private void UpdateUnitFilters(Job orig, Job mappedRequest)
        {
            orig.UnitFilters.Clear();

            foreach (var mappedUnitFilter in mappedRequest.UnitFilters)
            {
                var newUnitFilter = new JobUnitFilter
                {
                    UnitFilter = mappedUnitFilter.UnitFilter,
                    DateCreated = DateTimeOffset.UtcNow,
                    JobId = orig.Id
                };

                foreach (var newRequestFieldFilter in mappedUnitFilter.FieldFilters)
                {
                    var newFieldFilter = CreateFieldFilter(newUnitFilter.Id, newRequestFieldFilter.FieldId, newRequestFieldFilter.ValueMask, newRequestFieldFilter.IsInverse);

                    newUnitFilter.FieldFilters.Add(newFieldFilter);
                }

                foreach (var newRequestRelationshipFilter in mappedUnitFilter.RelationshipFilters)
                {
                    var newRelationshipFilter = CreateRelationshipFilter(newRequestRelationshipFilter.FieldId,
                                                                            newRequestRelationshipFilter.IsParent,
                                                                            newRequestRelationshipFilter.IsFullMatch,
                                                                            newRequestRelationshipFilter.IsInverse,
                                                                            newRequestRelationshipFilter.ValueMask);
                    newUnitFilter.RelationshipFilters.Add(newRelationshipFilter);
                }

                orig.UnitFilters.Add(newUnitFilter);
            }

            #region old
            /* Писал полноценный апдейт, но Миша сказал что нахрен это - просто все удаляем, а потом создаём заново... Ох уж этот Миша...
            //Сразу удаляем UnitFilter которых нет
            var toDelete = orig.UnitFilters.Where(t => !mappedRequest.UnitFilters.Any(e => e.Id == t.Id));
            foreach (var item in toDelete)
                orig.UnitFilters.Remove(item);

            foreach (var mappedUnitFilter in mappedRequest.UnitFilters)
            {
                var origUnitFilter = orig.UnitFilters.FirstOrDefault(t => t.Id == mappedUnitFilter.Id);

                if (origUnitFilter == null)
                {
                    var newUnitFilter = new JobUnitFilter
                    {
                        UnitFilter = mappedUnitFilter.UnitFilter,
                        DateCreated = DateTimeOffset.UtcNow,
                        JobId = orig.Id
                    };

                    foreach (var newRequestFieldFilter in mappedUnitFilter.FieldFilters)
                    {
                        var newFieldFilter = CreateFieldFilter(newUnitFilter.Id, newRequestFieldFilter.FieldId, newRequestFieldFilter.ValueMask);

                        newUnitFilter.FieldFilters.Add(newFieldFilter);
                    }

                    foreach (var newRequestRelationshipFilter in mappedUnitFilter.RelationshipFilters)
                    {
                        var newRelationshipFilter = CreateRelationshipFilter(newRequestRelationshipFilter.FieldId,
                                                                                newRequestRelationshipFilter.IsParent,
                                                                                newRequestRelationshipFilter.IsFullMatch,
                                                                                newRequestRelationshipFilter.IsInverse,
                                                                                newRequestRelationshipFilter.ValueMask);
                        newUnitFilter.RelationshipFilters.Add(newRelationshipFilter);
                    }

                    orig.UnitFilters.Add(newUnitFilter);
                }
                else
                {
                    #region Непосредственно UnitFilter
                    if (origUnitFilter.UnitFilter != mappedUnitFilter.UnitFilter)
                    {
                        origUnitFilter.UnitFilter = mappedUnitFilter.UnitFilter;
                        origUnitFilter.DateModified = DateTimeOffset.UtcNow;
                    }
                    #endregion

                    #region FieldFilters
                    //Сразу удаляем неактуальные
                    var fieldFiltersToDelete = origUnitFilter.FieldFilters.Where(t => !mappedUnitFilter.FieldFilters.Any(m => m.FieldId == t.FieldId));
                    foreach (var item in fieldFiltersToDelete)
                        origUnitFilter.FieldFilters.Remove(item);

                    //Перебираем FieldFilter
                    foreach (var mappedFieldFilter in mappedUnitFilter.FieldFilters)
                    {
                        var origFieldFilter = origUnitFilter.FieldFilters.FirstOrDefault(t => t.FieldId == mappedFieldFilter.FieldId);

                        if (origFieldFilter == null)//Нет в БД? не проблема - создадим
                        {
                            var newFieldFilter = CreateFieldFilter(origUnitFilter.Id, mappedFieldFilter.FieldId, mappedFieldFilter.ValueMask);
                            origUnitFilter.FieldFilters.Add(newFieldFilter);
                        }
                        else
                        {
                            if (origFieldFilter.ValueMask != mappedFieldFilter.ValueMask)
                            {
                                origFieldFilter.ValueMask = mappedFieldFilter.ValueMask;
                                origFieldFilter.DateModified = DateTimeOffset.UtcNow;
                            }
                        }
                    }
                    #endregion

                    #region RelationshipFilters
                    //Сразу удаляем неактуальные
                    var relationshipFiltersToDelete = origUnitFilter.RelationshipFilters.Where(t => !mappedUnitFilter.RelationshipFilters.Any(m => m.FieldId == t.FieldId));
                    foreach (var item in relationshipFiltersToDelete)
                        origUnitFilter.RelationshipFilters.Remove(item);

                    //Перебираем RelationshipFilters
                    foreach (var mappedRelationshipFilter in mappedUnitFilter.RelationshipFilters)
                    {
                        var origRelationshipFilter = origUnitFilter.RelationshipFilters.FirstOrDefault(t => t.FieldId == mappedRelationshipFilter.FieldId);

                        if (origRelationshipFilter == null)//Нет в БД? не проблема - создадим
                        {
                            var newRelationshipFilter = CreateRelationshipFilter(mappedRelationshipFilter.FieldId,
                                                                                    mappedRelationshipFilter.IsParent,
                                                                                    mappedRelationshipFilter.IsFullMatch,
                                                                                    mappedRelationshipFilter.IsInverse,
                                                                                    mappedRelationshipFilter.ValueMask);

                            origUnitFilter.RelationshipFilters.Add(newRelationshipFilter);
                        }
                        else
                        {
                            if (origRelationshipFilter.IsParent != mappedRelationshipFilter.IsParent)
                                origRelationshipFilter.IsParent = mappedRelationshipFilter.IsParent;

                            if (origRelationshipFilter.ValueMask != mappedRelationshipFilter.ValueMask)
                                origRelationshipFilter.ValueMask = mappedRelationshipFilter.ValueMask;

                            if (origRelationshipFilter.IsFullMatch != mappedRelationshipFilter.IsFullMatch)
                                origRelationshipFilter.IsFullMatch = mappedRelationshipFilter.IsFullMatch;

                            if (origRelationshipFilter.IsInverse != mappedRelationshipFilter.IsInverse)
                                origRelationshipFilter.IsInverse = mappedRelationshipFilter.IsInverse;
                        }
                    }
                    #endregion
                }
            }*/

            #endregion
        }

        private static JobRelationshipFilter CreateRelationshipFilter(Guid fieldId, bool isParent, bool isFullMatch, bool isInverse, string valueMask)
        {
            return new JobRelationshipFilter
            {
                FieldId = fieldId,
                IsParent = isParent,
                IsFullMatch = isFullMatch,
                IsInverse = isInverse,
                ValueMask = valueMask
            };
        }

        private static JobFieldFilter CreateFieldFilter(Guid unitFilterId, Guid fieldId, string valueMask, bool isInverse)
        {
            return new JobFieldFilter
            {
                UnitFilterId = unitFilterId,
                DateCreated = DateTimeOffset.UtcNow,
                FieldId = fieldId,
                ValueMask = valueMask,
                IsInverse = isInverse
            };
        }


        /// <summary>
        /// Удалить задание на выполнение работ (только если нет связанных шаблонов)
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpDelete(ApiRoutes.Job.Delete)]
        public async Task<IActionResult> Delete([FromRoute] Guid id)
        {
            var job = await jobService.Get().Include(t => t.Tnk)
                                .FirstOrDefaultAsync(t => t.Id == id);

            if (job == null)
                return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel {
                    Message = $"Ошибка при удалении задания на выполнение работ. Не найдено задание на выполнение работ Id: {id}"
                } }));

            var templateCount = await templateService.Get().CountAsync(t => t.JobId == id);

            if (templateCount > 0)
                return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel {
                    Message = $"Ошибка при удалении задания на выполнение работ. С данным заданием связаны шаблоны: {templateCount} шт."
                } }));

            if (!jobService.Delete(job) || !await jobService.CommitAsync())
                return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel {
                    Message = $"Ошибка при удалении задания на выполнение работ"
                } }));

            logger.LogInformation($"Пользователь {User.Identity?.Name} удалил задание на выполнение работ: {job.Id},{job.Name}," +
                $" {job.WorkName}, {job.MinValueRelationships}, {job.MaxValueRelationships}," +
                $" {job.TemplateNameMask}, {job.TnkId}, {job.GroupId}");

            return NoContent();
        }


        /// <summary>
        /// Загрузка статистики
        /// </summary>
        /// <param name="jobId"></param>
        /// <returns></returns>
        private async Task<JobStatModel> GetStatisticsAsync(Guid jobId)
        {
            var statResult = await jobService.Get()
                            .Include(t => t.Templates)
                                .ThenInclude(t => t.RobotConfigurations)
                            .Where(x => x.Id == jobId)
                            .Select(t => new
                            {
                                TemplateActivated = t.Templates.Count(x => x.IsActiveTemplate),
                                TemplateSynchronized = t.Templates.Count(x => x.RobotConfigurations.Any(c => c.TaskStatusCode == (int)TaskStatusEnum.Ok && c.RobotCode == (int)RobotsEnum.TemplateOrder)),
                                TemplateErrors = t.Templates.Count(x => x.RobotConfigurations.Any(c => c.RobotStatusCode == (int)RobotStatusEnum.Error && c.RobotCode == (int)RobotsEnum.TemplateOrder)),
                                ScheduleActivated = t.Templates.Count(x => x.IsActiveSchedule),
                                ScheduleSynchronized = t.Templates.Count(x => x.RobotConfigurations.Any(c => c.TaskStatusCode == (int)TaskStatusEnum.Ok && c.RobotCode == (int)RobotsEnum.ScheduleOrder)),
                                ScheduleErrors = t.Templates.Count(x => x.RobotConfigurations.Any(c => c.RobotStatusCode == (int)RobotStatusEnum.Error && c.RobotCode == (int)RobotsEnum.ScheduleOrder))

                            }).FirstOrDefaultAsync();

            return new JobStatModel
            {
                ScheduleStatistics = new ScheduleStats { Activated = statResult?.ScheduleActivated ?? 0, Errors = statResult?.ScheduleErrors ?? 0, Synchronized = statResult?.ScheduleSynchronized ?? 0 },
                TemplateStatistics = new TemplateStats { Activated = statResult?.TemplateActivated ?? 0, Errors = statResult?.TemplateErrors ?? 0, Synchronized = statResult?.TemplateSynchronized ?? 0 }
            };
        }


        private void BindStatistics(JobResponse job, JobStatModel statistics)
        {
            //job.TemplateStatistics = new TemplateStats { Activated = statistics.TemplateStatistics.Activated, Errors = statistics.TemplateStatistics.Errors, Synchronized = statistics.TemplateStatistics.Synchronized };
            //job.ScheduleStatistics = new ScheduleStats { Activated = statistics.ScheduleStatistics.Activated, Errors = statistics.ScheduleStatistics.Errors, Synchronized = statistics.ScheduleStatistics.Synchronized };
        }


        private async Task<bool> SendRequestToUpdateTemplates(Guid jobId)
        {
            var request = new TemplateMatcherMq
            {
                Id = jobId,
                EntityType = SyncTaskEntityTypeEnum.Job,
                Action = TemplateMatcherActionEnum.Update,
                Initiator = new HistoryInitiator
                {
                    InitiatorIp = clientService.GetClientIp()?.ToString(),
                    InitiatorParrComponentId = ParrComponentsEnum.Api,
                    InitiatorComment = $"В GUI изменено имя шаблона, при сохранении Job отправлен запрос на обновление связанных шаблонов"
                }
            };

            //var msg = JsonSerializer.Serialize(request);

            //var result = await mqService.SendAsync(mqSettings.TemplatesMatcher, new[] { msg });
            var result = await mqService.SendAsync(mqSettings.TemplatesMatcher, new List<object> { request });

            logger.LogDebug("Получен код отпрвки: {IsSuccess}", result.IsSuccess);

            if (!result.IsSuccess)
            {
                logger.LogError($"Ошибка при отправке запроса в очередь на обновление связанных шаблонов, после обновления маски шаблона. {request.ToJson()}");
                return false;
            }

            logger.LogInformation($"После изменения маски шаблона в jobId: {jobId}, отправлен запрос в очередь на переименование связанных шаблонов: {request.ToJson()}");

            return true;
        }


        /// <summary>
        /// Получить кол-во шаблонов в Job
        /// </summary>
        /// <param name="jobId"></param>
        /// <returns></returns>
        private async Task<int> GetCountTemplatesAsync(Guid jobId)
        {
            // Получаем только шаблоны в статусе used
            return await templateService.Get().CountAsync(t => t.JobId == jobId && t.StatusTypeId == TemplateStatusTypeEnum.Used);
        }

        /// <summary>
        /// Получить статус matching`a
        /// </summary>
        /// <param name="jobId"></param>
        /// <returns></returns>
        private async Task<MatchingStatusResponse?> GetMatchingStatusAsync(Guid jobId)
        {
            var statusMatching = await matchingStatusService.GetStatusAsync(jobId, SyncTaskEntityTypeEnum.Job);

            return mapper.Map<MatchingStatusResponse>(statusMatching);
        }

    }


    public class JobStatModel
    {
        public required TemplateStats TemplateStatistics { get; set; }

        public required ScheduleStats ScheduleStatistics { get; set; }
    }


}
