using System.Text;
using System.Xml.Serialization;
using ProfitGroup.NotifyService.Core.Configs;
using ProfitGroup.NotifyService.Models;
using ProfitGroup.NotifyService.Services;
using ProfitGroup.NotifyService.Data.Core.Data.Entities;

namespace ProfitGroup.NotifyService.Core.Handlers
{
    public class RouteHandler
    {
        private readonly ILogger<RouteHandler> _logger;
        private readonly INotifyService _notifyService;

        public RouteHandler(ILogger<RouteHandler> logger, INotifyService notifyService)
        {
            _notifyService = notifyService;
            _logger = logger ?? throw new Exception("Инициализация логирования прошла с ошибкой");
        }

        public async Task<IResult> SoapIntegration(HttpContext context)
        {
            var result = Results.Empty;
            var content = await context.Request.ParseBodyAsync() ?? string.Empty;
            _logger.LogInformation(content);

            if (string.IsNullOrEmpty(content))
            {
                var requestMessage = $"Тело запроса не может быть пустым";
                _logger.LogInformation(requestMessage);
                return Results.BadRequest(requestMessage);
            }

            var model = ContentDeserializer.Deserialize<Envelope>(content, out string message);

            if (model == null)
            {
                var requestMessage = $"Не удалось десериализовать полученный объект. {message}";
                _logger.LogInformation(requestMessage);
                return Results.BadRequest(requestMessage);
            }

            var confirmation = model.Body.MTConfirmation.Confirmation;

            switch ((ObjectTypes)confirmation.ObjectType)
            {
                case ObjectTypes.Specification:
                    result = await UpdateSpecificationInfoCardAsync(model);
                    break;

                case ObjectTypes.Sample:
                    result = await UpdateSampleInfoCardAsync(model);
                    break;

                case ObjectTypes.Method:
                    result = await SaveMethodInDatabase(model);
                    break;

                case ObjectTypes.Parameter:
                    result = await SaveParameterInDatabase(model);
                    break;

                default:
                    result = Results.BadRequest(
                        $"Не удалось определить тип объекта, на который записывать информацию. Неверный ObjectType");
                    break;
            }

            return result;
        }

        private async Task<IResult> SaveParameterInDatabase(Envelope model)
        {
            var confirmation = model.Body.MTConfirmation.Confirmation;

            var isSuccess = await _notifyService.SaveParameterLog(confirmation.ID, Convert.ToInt32(confirmation.Version), confirmation.StatusCode, confirmation.StatusText);

            if (!isSuccess)
            {
                var message = "Ответ успешно получен. Не удалось записать информацию о параметре в базу данных";
                _logger.LogError(message);
                Results.BadRequest(message);
            }
            
            var messageText =
                $"Данные об успешном формировании получены и записаны в базу, тип: Параметр, ID: {confirmation.ID}, Version: {confirmation.Version}";
            _logger.LogInformation(messageText);
            return Results.Ok(messageText);
        }

        private async Task<IResult> SaveMethodInDatabase(Envelope model)
        {
            var confirmation = model.Body.MTConfirmation.Confirmation;

            var isSuccess = await _notifyService.SaveMethodLog(confirmation.ID, Convert.ToInt32(confirmation.Version), confirmation.StatusCode, confirmation.StatusText);

            if (!isSuccess)
            {
                var message = "Ответ успешно получен. Не удалось записать информацию о методе в базу данных";
                _logger.LogError(message);
                Results.BadRequest(message);
            }
            
            var messageText =
                $"Данные об успешном формировании получены и записаны в базу, тип: Метод, ID: {confirmation.ID}, Version: {confirmation.Version}";
            _logger.LogInformation(messageText);
            return Results.Ok(messageText);
        }

        private async Task<IResult> UpdateSampleInfoCardAsync(Envelope model)
        {
            var confirmation = model.Body.MTConfirmation.Confirmation;

            var sample = await _notifyService.GetSampleAsync(confirmation.ID);

            if (sample == null)
            {
                var errorText =
                    $"Проба не найдена. Проба: {confirmation.ID}";
                _logger.LogError(errorText);
                return Results.NotFound(errorText);
            }

            var infoCard = await _notifyService.GetSampleInfoCardAsync((int)sample.SC);

            if (infoCard == null)
            {
                var errorText =
                    $"Инфокарта не найдена. Проба: {confirmation.ID}, наименование группы параметров инфокарты: {Config.SampleInfoCardFieldName}";
                _logger.LogError(errorText);
                return Results.NotFound(errorText);
            }

            var updateParams = new Dictionary<string, string>
            {
                { $"{Config.SampleInfoFieldStatusCodeName}{confirmation.ResponseType}", confirmation.StatusCode },
                { $"{Config.SampleInfoFieldStatusTextName}{confirmation.ResponseType}", confirmation.StatusText },
            };

            if (await _notifyService.UpdateSampleInfoCardAsync(infoCard, updateParams) == false)
            {
                var errorText =
                    $"При обновлении парамметров произошла ошибка, проверьте, что наименования всех параметров в конфигурационном файле заполнены верно. Спецификация: {confirmation.ID}, версия: {confirmation.Version}";
                _logger.LogError(errorText);
                return Results.Problem(errorText);
            }

            var messageText =
                $"Обновление параметров произошло успешно. Проба: {confirmation.ID}";
            _logger.LogInformation(messageText);

            return Results.Ok(messageText);
        }

        private async Task<IResult> UpdateSpecificationInfoCardAsync(Envelope model)
        {
            var confirmation = model.Body.MTConfirmation.Confirmation;

            if (int.TryParse(confirmation.Werks, out var locate) == false)
            {
                var errorText = $"Полученое неверное значение локации. Полученное значение: \"{locate}\"";
                _logger.LogError(errorText);
                return Results.BadRequest(errorText);
            }

            var specification = await _notifyService.GetSpecificationAsync(confirmation.ID, Convert.ToInt32(confirmation.Version));

            if (specification == null)
            {
                var errorText =
                    $"Спецификация не найдена. Спецификация: {confirmation.ID}, версия: {confirmation.Version}";
                _logger.LogError(errorText);
                return Results.NotFound(errorText);
            }

            var infoCard =
                await _notifyService.GetSpecificationInfoCardAsync((int)specification.SP, Convert.ToInt32(confirmation.Version), locate);

            if (infoCard == null)
            {
                var errorText =
                    $"Инфокарта не найдена. Спецификация: {confirmation.ID}, версия: {confirmation.Version}, локация: {locate}";
                _logger.LogError(errorText);
                return Results.NotFound(errorText);
            }

            var updateParams = new Dictionary<string, string>
            {
                { Config.SpecificationInfoFieldStatusCodeName, confirmation.StatusCode },
                {
                    Config.SpecificationInfoFieldStatusTextName,
                    confirmation.StatusText.Split('/').FirstOrDefault() ?? string.Empty
                },
                {
                    Config.SpecificationInfoFieldAENNR,
                    confirmation.StatusText.Split('/').LastOrDefault() ?? string.Empty
                },
            };

            if (Config.ActionType == AttributeSaveAction.PushToInfoCard)
            {
                //updateParams.Add(Config.InfoFieldAennr, confirmation.AENNR);
            }

            if (await _notifyService.UpdateSpecificationInfoCardAsync(infoCard, updateParams))
            {
                #region AENNR

                // if (Config.ActionType == AttributeSaveAction.PushToAttribute)
                // {
                //     var aennerIsUpdated =
                //         await _notifyService.UpdateAttribute(specification, specificationAttribute,
                //             confirmation.AENNR);
                //
                //     if (aennerIsUpdated == false)
                //     {
                //         var errorText =
                //             $"Не удалось создать или обновить атрибут AENNR в спецификации. Спецификация: {confirmation.ID}, версия: {confirmation.Version}";
                //         _logger.LogError(errorText);
                //         return false;
                //     }
                // }

                #endregion
            }
            else
            {
                var errorText =
                    $"При обновлении парамметров произошла ошибка, проверьте, что наименования всех параметров в конфигурационном файле заполнены верно. Спецификация: {confirmation.ID}, версия: {confirmation.Version}";
                _logger.LogError(errorText);
                return Results.Problem(errorText);
            }

            var messageText =
                $"Обновление параметров произошло успешно. Спецификация: {confirmation.ID}, версия: {confirmation.Version}";
            _logger.LogInformation(messageText);

            return Results.Ok(messageText);
        }
    }
}