using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using PARR.Core.Repositories.Interfaces;
using PARR.Domain.Entities;
using PARR.EsppApi.Models;

namespace PARR.EsppOrderLoader.Services
{
    internal class OrderItemService : IOrderItemService
    {
        private readonly ILogger<OrderItemService> logger;
        private readonly IOrderRepository orderService;
        private readonly ITemplateRepository templateService;
        private readonly IOrderStatusRepository orderStatusService;

        public OrderItemService(
            ILogger<OrderItemService> logger,
            IOrderRepository orderService,
            ITemplateRepository templateService,
            IOrderStatusRepository orderStatusService
            )
        {
            this.orderService = orderService;
            this.templateService = templateService;
            this.orderStatusService = orderStatusService;
            this.logger = logger;
        }

        public async Task WriteOrderAsync(EsppOrder esppOrder)
        {
            try
            {
                logger.LogDebug("Начинаю обработку наряда {EsppOrderNumber}", esppOrder.Number);

                var existOrder = await orderService.Get()
                    .FirstOrDefaultAsync(t => t.Number.ToLower() == esppOrder.Number.ToLower());

                if (existOrder != null)
                {
                    logger.LogInformation("Наряд {EsppOrderNumber} уже существует в БД. Пропускаю.", esppOrder.Number);
                    return;
                }

                logger.LogDebug("Поиск шаблона для наряда {EsppOrderNumber}", esppOrder.Number);

                var template = await templateService.Get()
                    .Include(t => t.Job)
                    .FirstOrDefaultAsync(t => t.Name.ToLower() == esppOrder.TemplateName.ToLower());

                if (template == null)
                {
                    logger.LogWarning(
                        "Не найден шаблон для наряда {EsppOrderNumber} с именем шаблона {TemplateName}. " +
                        "Краткое описание: {ShortName}, рабочая группа: {WorkGroup}",
                        esppOrder.Number,
                        esppOrder.TemplateName,
                        esppOrder.ShortName,
                        esppOrder.WorkGroup);
                }
                else
                {
                    logger.LogDebug(
                        "Найден шаблон {TemplateId} для наряда {EsppOrderNumber}",
                        template.Id,
                        esppOrder.Number);
                }

                var statusCode = (int)orderStatusService.GetOrderStatusByName(esppOrder.Status);

                var newOrder = new Order
                {
                    Id = Guid.NewGuid(),
                    Number = esppOrder.Number,
                    WorkGroup = esppOrder.WorkGroup,
                    ShortName = esppOrder.ShortName,
                    TemplateId = template?.Id,
                    StatusCode = statusCode,
                    GenerateDate = template == null
                        ? null
                        : CalcGenerationDate(template.NextRun, template.LastRun),
                    ExpirationDate = esppOrder.ExpirationDateUTC,
                    DateCreated = DateTimeOffset.UtcNow
                };

                logger.LogDebug("Создание нового наряда {OrderNumber} в БД", esppOrder.Number);

                var createResult = await orderService.CreateAsync(newOrder);
                var commitResult = await orderService.CommitAsync();

                if (!createResult || !commitResult)
                {
                    logger.LogError(
                        "Ошибка при добавлении нового наряда в БД. " +
                        "Номер наряда: {EsppOrderNumber}, рабочая группа: {WorkGroup}, " +
                        "краткое описание: {ShortName}",
                        esppOrder.Number,
                        esppOrder.WorkGroup,
                        esppOrder.ShortName);
                }
                else
                {
                    logger.LogInformation(
                        "Успешно добавлен наряд в БД: {EsppOrderNumber}, краткое описание: {ShortName}",
                        esppOrder.Number,
                        esppOrder.ShortName);
                }
            }
            catch (Exception ex)
            {
                logger.LogError(
                    ex,
                    "Произошла ошибка при обработке наряда {EsppOrderNumber}",
                    esppOrder?.Number ?? "неизвестно");
                throw;
            }
        }


        /// <summary>
        /// Рассчет GenerationDate относительно текущей даты и nextRun из ApplicationInWorks
        /// </summary>
        /// <param name="nextRun">Следующее время запуска</param>
        /// <param name="lastRun">Последнее время запуска</param>
        /// <returns>Рассчитанная дата генерации</returns>
        private DateTimeOffset? CalcGenerationDate(DateTimeOffset nextRun, DateTimeOffset? lastRun)
        {
            if (DateTimeOffset.UtcNow > nextRun)
            {
                return nextRun;
            }

            if (lastRun.HasValue)
            {
                return lastRun.Value;
            }

            return null;
        }
    }
}