/// <summary>
        /// Sets the specific merchant to use when communicating with the Bank.
        /// If you use multiple mechants you should explicitly call this method to set a specific active merchant, that will be used by other methods,
        /// otherwise the system will try to find a matching merchant automatically and might not select the one you might actually need.
        /// </summary>
        /// <param name="predicate">Will provide list of all available options. Will select the first option where the match returns true. Used LINQ FirstOrDefault internally</param>
        /// <exception cref="TbcBankEcommerceClientConfigurationException">Thrown when merchant configuration not found</exception>
        public void SelectMerchant(Func <TbcBankEcommerceClientOptions, bool> predicate)
        {
            var merchantOptions = _optionsList
                                  .FirstOrDefault(predicate);

            if (merchantOptions == null)
            {
                throw new TbcBankEcommerceClientConfigurationException($"Merchant configuration not found using the predicate");
            }

            _manuallySetActiveOptions = merchantOptions;
        }
        /// <summary>
        /// Sets the specific merchant to use when communicating with the Bank.
        /// If you use multiple mechants you should explicitly call this method to set a specific active merchant, that will be used by other methods,
        /// otherwise the system will try to find a matching merchant automatically and might not select the one you might actually need.
        /// </summary>
        /// <param name="merchantId">MerchantID specified in the configuration options</param>
        /// <exception cref="TbcBankEcommerceClientConfigurationException">Thrown when merchant configuration not found</exception>
        public void SelectMerchant(string merchantId)
        {
            var merchantOptions = _optionsList
                                  .FirstOrDefault(o => o.MerchantId == merchantId);

            if (merchantOptions == null)
            {
                throw new TbcBankEcommerceClientConfigurationException($"Merchant configuration not found with the id '{merchantId}'");
            }

            _manuallySetActiveOptions = merchantOptions;
        }
 private X509Certificate2 CreateCertificate(TbcBankEcommerceClientOptions options)
 {
     try
     {
         return(options.CertData != null
               ? new X509Certificate2(options.CertData, options.CertPassword, X509KeyStorageFlags.MachineKeySet)
               : new X509Certificate2(options.CertPath, options.CertPassword, X509KeyStorageFlags.MachineKeySet));
     }
     catch (Exception ex)
     {
         throw new Exception("Failed to create X509Certificate2", ex);
     }
 }
        private HttpClientHandler GetHttpClientHandler(TbcBankEcommerceClientOptions options)
        {
            if (options.Environment == TbcEnvironment.LegacyProduction)
            {
                return new HttpClientHandler
                       {
                           ClientCertificateOptions = ClientCertificateOption.Manual
                       }
            }
            ;

            return(new HttpClientHandler
            {
                ClientCertificateOptions = ClientCertificateOption.Manual,
                SslProtocols = SslProtocols.Tls12,
            });
        }
        /// <summary>
        /// Sets the specific merchant to use when communicating with the Bank.
        /// If you use multiple mechants you should explicitly call this method to set a specific active merchant, that will be used by other methods,
        /// otherwise the system will try to find a matching merchant automatically and might not select the one you might actually need.
        /// </summary>
        /// <param name="currency">Currency to search for</param>
        /// <exception cref="TbcBankEcommerceClientConfigurationException">Thrown when merchant configuration not found or more than one merchant configuration found with the specified currency</exception>
        public void SelectMerchant(CurrencyCode currency)
        {
            var merchantOptionsList = _optionsList
                                      .Where(o => o.Currencies.Contains(currency))
                                      .ToList();

            if (merchantOptionsList.Count == 0)
            {
                throw new TbcBankEcommerceClientConfigurationException($"Merchant configuration not found using the speficied currency '{currency.ToString()}'");
            }

            if (merchantOptionsList.Count > 1)
            {
                throw new TbcBankEcommerceClientConfigurationException($"More than one merchant configuration not found using the speficied currency '{currency.ToString()}'");
            }

            _manuallySetActiveOptions = merchantOptionsList
                                        .First();
        }
        private TbcBankEcommerceClientOptions GetActiveOptions(CurrencyCode?currency = null)
        {
            if (_manuallySetActiveOptions != null)
            {
                return(_manuallySetActiveOptions);
            }

            TbcBankEcommerceClientOptions activeOptions = null;

            if (currency.HasValue)
            {
                var currencyDefinedOptions = _optionsList
                                             .Where(o => o.Currencies.Contains(currency.Value))
                                             .ToList();

                if (currencyDefinedOptions.Count > 1)
                {
                    throw new TbcBankEcommerceClientConfigurationException($"More than one merchant configuration not found using the speficied currency '{currency.Value.ToString()}'");
                }

                activeOptions = currencyDefinedOptions
                                .First();
            }

            if (activeOptions == null)
            {
                activeOptions = _optionsList
                                .FirstOrDefault();
            }

            if (activeOptions == null)
            {
                throw new TbcBankEcommerceClientConfigurationException("Failed to auto-select active options");
            }

            return(activeOptions);
        }
        private async Task <HttpRequestResult> MakePostRequestAsync(IDictionary <string, string> requestParameters, TbcBankEcommerceClientOptions options)
        {
            if (requestParameters is null)
            {
                throw new ArgumentNullException(nameof(requestParameters));
            }

            StringBuilder queryBuilder = new StringBuilder();

            foreach (var requestParameter in requestParameters)
            {
                if (requestParameter.Value == null)
                {
                    continue;
                }

                queryBuilder.Append($"{requestParameter.Key}={Uri.EscapeDataString(requestParameter.Value)}&");
            }

            if (queryBuilder.Length > 1)
            {
                queryBuilder.Remove(queryBuilder.Length - 1, 1);
            }


            HttpRequestResult result = new HttpRequestResult()
            {
                RequestUrl   = ServiceUrlBuilderHelper.GetMerchantHandlerUrl(options.Environment),
                RequestQuery = queryBuilder.ToString()
            };

            try
            {
                using var handler = GetHttpClientHandler(options);

                handler.ServerCertificateCustomValidationCallback = (message, certificate, chain, sslPolicyErrors) => true;

                using var certificate = CreateCertificate(options);

                handler.ClientCertificates.Add(certificate);

                using var client = new HttpClient(handler);

                using var content = new StringContent(result.RequestQuery, Encoding.UTF8, "application/x-www-form-urlencoded");

                var responseMessage = await client.PostAsync(result.RequestUrl, content);

                result.HttpStatsCode = responseMessage.StatusCode;
                result.Success       = responseMessage.IsSuccessStatusCode;
                result.RawResponse   = await responseMessage.Content.ReadAsStringAsync();
            }
            catch (Exception ex)
            {
                result.Success   = false;
                result.Exception = ex;
            }

            return(result);
        }