using Hcs.ClientNet.Api.Payload.Payments;
using Hcs.ClientNet.Api.Request.Exception;
using Hcs.ClientNet.Internal;
using Hcs.Service.Async.Payments;
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace Hcs.ClientNet.Api.Request.Payments
{
    internal class ImportNotificationsOfOrderExecutionRequest(ClientBase client) : PaymentsRequestBase(client)
    {
        protected override bool CanBeRestarted => false;

        internal async Task<bool> ExecuteAsync(ImportNotificationsOfOrderExecutionPayload payload, CancellationToken token)
        {
            ThrowIfPayloadIncorrect(payload);

            // http://open-gkh.ru/Payment/importNotificationsOfOrderExecutionRequest.html
            var request = new importNotificationsOfOrderExecutionRequest
            {
                Id = Constants.SIGNED_XML_ELEMENT_ID,
                version = "10.0.1.1",
                Items = [GetNotificationFromPayload(payload)]
            };

            var result = await SendAndWaitResultAsync(request, async asyncClient =>
            {
                var response = await asyncClient.importNotificationsOfOrderExecutionAsync(CreateRequestHeader(), request);
                return response.AckRequest.Ack;
            }, token);

            result.Items.OfType<ErrorMessageType>().ToList().ForEach(error =>
            {
                throw RemoteException.CreateNew(error.ErrorCode, error.Description);
            });

            result.Items.OfType<CommonResultType>().ToList().ForEach(commonResult =>
            {
                commonResult.Items.OfType<ErrorMessageType>().ToList().ForEach(error =>
                {
                    throw RemoteException.CreateNew(error.ErrorCode, error.Description);
                });
            });

            return true;
        }

        private void ThrowIfPayloadIncorrect(ImportNotificationsOfOrderExecutionPayload payload)
        {
            if (string.IsNullOrEmpty(payload.orderId))
            {
                throw new ArgumentException($"{nameof(payload.orderId)} is empty");
            }

            if (payload.month.HasValue && !payload.year.HasValue)
            {
                throw new ArgumentException($"{nameof(payload.month)} has value but {nameof(payload.year)} has not");
            }

            if (!payload.month.HasValue && payload.year.HasValue)
            {
                throw new ArgumentException($"{nameof(payload.year)} has value but {nameof(payload.month)} has not");
            }

            if (string.IsNullOrEmpty(payload.paymentDocumentId))
            {
                throw new ArgumentException($"{nameof(payload.paymentDocumentId)} is empty");
            }

            if (string.IsNullOrEmpty(payload.paymentDocumentGUID))
            {
                throw new ArgumentException($"{nameof(payload.paymentDocumentGUID)} is empty");
            }
        }

        private importNotificationsOfOrderExecutionRequestNotificationOfOrderExecution139Type GetNotificationFromPayload(ImportNotificationsOfOrderExecutionPayload payload)
        {
            var notification = new importNotificationsOfOrderExecutionRequestNotificationOfOrderExecution139Type()
            {
                TransportGUID = Guid.NewGuid().ToString(),
                OrderInfo = new NotificationOfOrderExecution139TypeOrderInfo()
                {
                    OrderID = payload.orderId,
                    OrderDate = payload.orderDate,
                    Amount = payload.amount,
                    Items = [payload.paymentDocumentId, payload.paymentDocumentGUID],
                    ItemsElementName = [ItemsChoiceType4.PaymentDocumentID, ItemsChoiceType4.PaymentDocumentGUID]
                }
            };

            if (payload.onlinePayment.HasValue && payload.onlinePayment.Value)
            {
                notification.OrderInfo.OnlinePayment = true;
                notification.OrderInfo.OnlinePaymentSpecified = true;
            }

            if (payload.month.HasValue)
            {
                notification.OrderInfo.MonthAndYear = new NotificationOfOrderExecution139TypeOrderInfoMonthAndYear()
                {
                    Year = payload.year.Value,
                    Month = payload.month.Value
                };
            }

            return notification;
        }
    }
}
