namespace Hims.Infrastructure.Helpers
{
    using System.Threading.Tasks;

    using Domain.Configurations;

    using RestSharp;

    using Shared.UserModels.PayU;

    using Hims.Domain.Helpers;

    /// <summary>
    /// The pay u helper.
    /// </summary>
    public class PayUHelper : IPayUHelper
    {
        /// <summary>
        /// The payU configuration.
        /// </summary>
        private readonly IPayUConfiguration payUConfiguration;

        /// <summary>
        /// The client.
        /// </summary>
        private RestClient client;

        /// <summary>
        /// Initializes a new instance of the <see cref="PayUHelper"/> class.
        /// </summary>
        /// <param name="payUConfiguration">
        /// The pay u configuration.
        /// </param>
        public PayUHelper(IPayUConfiguration payUConfiguration) => this.payUConfiguration = payUConfiguration;

        /// <inheritdoc />
        public Task<IRestResponse> FetchStatusAsync(string merchantTransactionIds)
        {
            this.client = new RestClient(this.payUConfiguration.PayUUrl);
            var request = new RestRequest("payment/payment/chkMerchantTxnStatus", Method.POST);
            request.AddParameter("merchantKey", this.payUConfiguration.Key, type: ParameterType.QueryString);
            request.AddParameter("merchantTransactionIds", merchantTransactionIds, ParameterType.QueryString);
            request.AddHeader("Authorization", this.payUConfiguration.AuthHeader);
            return this.client.ExecuteAsync(request);
        }

        /// <inheritdoc />
        public Task<IRestResponse> RefundAsync(long paymentId, decimal amount)
        {
            this.client = new RestClient(this.payUConfiguration.PayUUrl);
            var request = new RestRequest("payment/merchant/refundPayment", Method.POST);
            request.AddParameter("merchantKey", this.payUConfiguration.Key, type: ParameterType.QueryString);
            request.AddParameter("paymentId", paymentId, ParameterType.QueryString);
            request.AddParameter("refundAmount", amount, ParameterType.QueryString);
            request.AddHeader("Authorization", this.payUConfiguration.AuthHeader);
            return this.client.ExecuteAsync(request);
        }

        /// <summary>
        /// The fetch refund status async.
        /// </summary>
        /// <param name="paymentId">
        /// The payment id.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        public Task<IRestResponse> FetchRefundStatusAsync(int paymentId)
        {
            this.client = new RestClient(this.payUConfiguration.PayUUrl);
            var request = new RestRequest("treasury/ext/merchant/getRefundDetailsByPayment", Method.GET);
            request.AddParameter("merchantKey", this.payUConfiguration.Key, type: ParameterType.QueryString);
            request.AddParameter("paymentId", paymentId, ParameterType.QueryString);
            request.AddHeader("Authorization", this.payUConfiguration.AuthHeader);
            return this.client.ExecuteAsync(request);
        }

        /// <inheritdoc />
        public Task<IRestResponse> PayoutAuthentication()
        {
            this.client = new RestClient(this.payUConfiguration.PayoutOauthURL);
            var request = new RestRequest("token", Method.POST);
            request.AddParameter("client_id", this.payUConfiguration.ClientId, type: ParameterType.GetOrPost);
            request.AddParameter("grant_type", "password", ParameterType.GetOrPost);

            // request.AddParameter("username", "payouttest4@mailinator.com", ParameterType.GetOrPost);
            // request.AddParameter("password", "Tester@123", ParameterType.GetOrPost);
            request.AddParameter("username", "vikas@sujainfo.com", ParameterType.GetOrPost);
            request.AddParameter("password", "Vikas@1!@#$", ParameterType.GetOrPost);
            request.AddParameter("scope", "create_payout_transactions", ParameterType.GetOrPost);
            return this.client.ExecuteAsync(request);
        }

        /// <inheritdoc />
        public Task<IRestResponse> PayoutAccountDetails(PayoutModel model)
        {
            this.client = new RestClient(this.payUConfiguration.PayUUrl);
            var request = new RestRequest("payout/merchant/getAccountDetail", Method.GET);
            request.AddHeader("Authorization", model.Token_Type + " " + model.Access_Token);
            request.AddHeader("payoutMerchantId", this.payUConfiguration.PayoutMerchantId);
            return this.client.ExecuteAsync(request);
        }

        /// <inheritdoc />
        public Task<IRestResponse> PayoutSmartSendAsync(PayoutModel model)
        {
            this.client = new RestClient(baseUrl: this.payUConfiguration.PayUUrl);
            var request = new RestRequest(resource: "payout/smartPay", method: Method.POST);
            request.AddJsonBody(new
            {
                amount = model.Amount,
                merchantRefId = model.MerchantRefId,
                custEmail = model.Email,
                custName = model.UserName,
                custMoblie = model.Mobile,
                description = model.Description
            });
            request.AddHeader(name: "Authorization", value: model.Token_Type + " " + model.Access_Token);
            request.AddHeader(name: "payoutMerchantId", value: this.payUConfiguration.PayoutMerchantId);
            return this.client.ExecuteAsync(request: request);
        }

        /// <inheritdoc />
        public Task<IRestResponse> PayoutPaymentAsync(PayoutModel model)
        {
            this.client = new RestClient(baseUrl: this.payUConfiguration.PayUUrl);
            var request = new RestRequest(resource: "payout/payment", method: Method.POST);
            request.AddJsonBody(
                new[]
                    {
                        new
                            {
                                beneficiaryAccountNumber = model.AccountNumber,
                                beneficiaryIfscCode = model.IfscCode,
                                beneficiaryName = model.UserName,
                                beneficiaryEmail = model.Email,
                                beneficiaryMobile = model.Mobile,
                                description = model.Description,
                                purpose = model.Purpose,
                                amount = model.Amount,
                                batchId = model.BatchId,
                                merchantRefId = model.MerchantRefId,
                                paymentType = model.PaymentType
                            }
                    });
            request.AddHeader(name: "Authorization", value: model.Token_Type + " " + model.Access_Token);
            request.AddHeader(name: "payoutMerchantId", value: this.payUConfiguration.PayoutMerchantId);
            request.AddHeader("Content-Type", "application/json");
            return this.client.ExecuteAsync(request: request);
        }

        /// <inheritdoc />
        public Task<IRestResponse> AddWebHook(PayoutModel model)
        {
            this.client = new RestClient(baseUrl: this.payUConfiguration.PayUUrl);
            var request = new RestRequest(resource: "payout/v2/webhook", method: Method.POST);
            request.AddJsonBody(
                new[]
                    {
                        new
                            {
                                webhook = "default",
                                values = new
                                             {
                                                 url = this.payUConfiguration.WebHooks,
                                                 authorization = this.payUConfiguration.AuthorizationKey
                                             },
                            }
                    });
            request.AddHeader(name: "Authorization", value: model.Token_Type + " " + model.Access_Token);
            request.AddHeader(name: "payoutMerchantId", value: this.payUConfiguration.PayoutMerchantId);
            request.AddHeader("Content-Type", "application/json");
            return this.client.ExecuteAsync(request: request);
        }

        /// <summary>
        /// The delete web hook.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        public Task<IRestResponse> DeleteWebHook(PayoutModel model)
        {
            this.client = new RestClient(baseUrl: this.payUConfiguration.PayUUrl);
            var request = new RestRequest(resource: "payout/v2/webhook/delete", method: Method.POST);
            request.AddJsonBody(
                new
                {
                    webhook = new[] { "default" }
                });
            request.AddHeader(name: "Authorization", value: model.Token_Type + " " + model.Access_Token);
            request.AddHeader(name: "payoutMerchantId", value: this.payUConfiguration.PayoutMerchantId);
            request.AddHeader("Content-Type", "application/json");
            return this.client.ExecuteAsync(request: request);
        }

        /// <inheritdoc />
        public Task<IRestResponse> FetchPayoutTransfers(PayoutModel model)
        {
            this.client = new RestClient(this.payUConfiguration.PayUUrl);
            var request = new RestRequest("payout/payment/listTransactions", Method.POST);
            request.AddParameter("txnId", string.Empty, type: ParameterType.GetOrPost);
            request.AddParameter("merchantRefId", string.Empty, ParameterType.GetOrPost);
            request.AddParameter("batchId", string.Empty, ParameterType.GetOrPost);
            request.AddParameter("transferStatus", string.Empty, ParameterType.GetOrPost);
            request.AddParameter("from", null, ParameterType.GetOrPost);
            request.AddParameter("to", null, ParameterType.GetOrPost);
            request.AddParameter("page", model.PageIndex, ParameterType.GetOrPost);
            request.AddParameter("pageSize", model.PageSize, ParameterType.GetOrPost);
            request.AddHeader(name: "Authorization", value: model.Token_Type + " " + model.Access_Token);
            request.AddHeader(name: "payoutMerchantId", value: this.payUConfiguration.PayoutMerchantId);
            return this.client.ExecuteAsync(request);
        }
    }
}
