using Microsoft.Extensions.Logging;
using PARR.Domain.Entities;
using PARR.Domain.Enums;
using PARR.EsppApi;
using PARR.EsppApi.Constants;
using PARR.EsppApi.Models.Query;
using PARR.EsppOrderManager.Settings;

namespace PARR.EsppOrderManager.Services
{
    internal class EsppOrderService : IEsppOrderService
    {
        private readonly ILogger<EsppOrderService> logger;
        private readonly IEsppApiService esppApiService;
        private readonly EsppPoligonSettings esppPoligonSettings;

        public EsppOrderService(
            ILogger<EsppOrderService> logger,
            IEsppApiService esppApiService,
            EsppPoligonSettings esppPoligonSettings
            )
        {
            this.logger = logger;
            this.esppApiService = esppApiService;
            this.esppPoligonSettings = esppPoligonSettings;
        }


        public async Task<bool> ChangeOrderToEsppAsync(Order order, string resultMsg, TimeSpan duration)
        {
            // Наряд нужно провести по всем статусам
            // Найти наряд, посмотреть его текущий статус (вдруг статус в ЕСПП был изменен, а в бд нет)
            // Сначала взять в работу
            // Списать ТНК
            // Выполнить

            var esppOrderResult = await esppApiService.FindOrderByRecordIdAsync(order.Number);
            if (!esppOrderResult.IsSuccess || esppOrderResult.Data == null)
            {
                logger.LogError($"Не найден наряд в ЕСПП: {order.Number}");
                return false;
            }

            // проверяем, совпадает ли NextStatus со статусом в ЕСПП
            // Если совпадают, значит в еспп поменяли и не изменили в БД раньше (может ошибка была, может руками кто сделал)
            // так что говорим, как будто бы все ок
            if (IsEquelEsppStatusAndNextStatus(order.NextStatusCode!.Value, esppOrderResult.Data.StatusEnum))
            {
                logger.LogInformation($"Для наряда {order.Number}, статус в ЕСПП совпадает с {nameof(order.NextStatusCode)} = {order.NextStatus!.Description}. " +
                    $"Статус в ЕСПП менять не нужно.");

                return true;
            }

            // Установить статус 2-В работе
            if (order.NextStatusCode == (int)OrderStatusEnum.InWork)
                if (esppOrderResult.Data.StatusEnum == OrderStatusEnum.New || esppOrderResult.Data.StatusEnum == OrderStatusEnum.Stop)
                    return await SetInWorkStatusAsync(order.Number, "");//resultMsg);

            // Списать трудозатраты и установить статус 4-Выполнен
            if (order.NextStatusCode == (int)OrderStatusEnum.Complete)
            {
                var statusIsWork = esppOrderResult.Data.StatusEnum == OrderStatusEnum.InWork;

                // если текущий статус != 2-В работе, сначала меняем статус на 2-В работе, а затем уже списываем трудозатраты и меняем на 4-Выполнен
                if (!statusIsWork)
                    statusIsWork = await SetInWorkStatusAsync(order.Number, "");//resultMsg);

                if (statusIsWork)
                {
                    // заполняем ТНК
                    var tnk = new AddMtnkQuery
                    {
                        JobOperation = order!.Template!.Job!.WorkName,
                        RecordId = order.Number,
                        Time = duration.ToString("hh\\:mm")
                    };

                    if (esppPoligonSettings.IsEnabled)
                    {
                        //для теста, подемеяем значения из БД
                        tnk.JobOperation = esppPoligonSettings.TnkValue;
                    }

                    return await SetCompleteStatusAsync(order.Number, resultMsg, tnk);
                }
                else
                {
                    logger.LogError($"Для наряда {order.Number} не могу изменить статус на {OrderStatusEnum.Complete}, так как текущий статус не {OrderStatusEnum.InWork}. " +
                        $"Текущий статус в ЕСПП: {esppOrderResult.Data.Status}");

                    return false;
                }

            }

            return false;
        }


        /// <summary>
        /// Установка статуса 4-Выполнен
        /// </summary>
        /// <param name="orderNumber"></param>
        /// <param name="resultMsg"></param>
        /// <param name="tnk"></param>
        /// <returns></returns>
        private async Task<bool> SetCompleteStatusAsync(string orderNumber, string resultMsg, AddMtnkQuery tnk)
        {
            // списываем трудозатраты
            var resultTnk = await esppApiService.AddMTnkAsync(tnk);
            if (!resultTnk.IsSuccess)
            {
                logger.LogError(resultTnk.Exception, $"Ошибка при списывании трудозатрат для наряда {orderNumber}.");

                return false;
            }
            else
                logger.LogDebug($"В ЕСПП, для наряда {orderNumber} списаны трудозатраты. Операция: {tnk.JobOperation}, время: {tnk.Time}");

            // выполняем наряд
            var result = await esppApiService.SetStatusIsDoneAsync(orderNumber, resultMsg, EsppOrderClosingCodeEnum.Auto);

            if (result.IsSuccess)
            {
                logger.LogDebug($"В ЕСПП, для наряда {orderNumber} установлен статус {OrderStatusEnum.Complete}");

                return true;
            }
            else
            {
                logger.LogError(result.Exception, $"В ЕСПП, для наряда {orderNumber} не удалось установить статус {OrderStatusEnum.Complete}.");

                return false;
            }
        }


        /// <summary>
        /// Установка статуса 2-В работе
        /// </summary>
        /// <param name="orderNumber"></param>
        /// <param name="resultMsg"></param>
        /// <returns></returns>
        private async Task<bool> SetInWorkStatusAsync(string orderNumber, string resultMsg = "")
        {
            var result = await esppApiService.SetStatusInWorkAsync(orderNumber, resultMsg);

            if (result.IsSuccess)
            {
                logger.LogDebug($"В ЕСПП, для наряда {orderNumber} установлен статус {OrderStatusEnum.InWork}");

                return true;
            }
            else
            {
                logger.LogError(result.Exception, $"В ЕСПП, для наряда {orderNumber} не удалось установить статус {OrderStatusEnum.InWork}.");

                return false;
            }
        }


        /// <summary>
        /// Совпадает ли NextStatus и Еспп статусом
        /// </summary>
        /// <returns></returns>
        private bool IsEquelEsppStatusAndNextStatus(int nextStatusCode, OrderStatusEnum esppStatus)
        {
            return nextStatusCode == (int)esppStatus;
        }

    }
}
