private async Task <PaymentModel> GetInvoiceModel(string invoiceId, PaymentMethodId paymentMethodId)
        {
            var invoice = await _InvoiceRepository.GetInvoice(invoiceId);

            if (invoice == null)
            {
                return(null);
            }
            var store = await _StoreRepository.FindStore(invoice.StoreId);

            bool isDefaultPaymentId = false;

            if (paymentMethodId == null)
            {
                paymentMethodId    = store.GetDefaultPaymentId(_NetworkProvider);
                isDefaultPaymentId = true;
            }
            BTCPayNetworkBase network = _NetworkProvider.GetNetwork <BTCPayNetworkBase>(paymentMethodId.bitcoinCode);

            if (network == null && isDefaultPaymentId)
            {
                //TODO: need to look into a better way for this as it does not scale
                network         = _NetworkProvider.GetAll().OfType <BTCPayNetwork>().FirstOrDefault();
                paymentMethodId = new PaymentMethodId(network.bitcoinCode, PaymentTypes.BTCLike);
            }
            if (invoice == null || network == null)
            {
                return(null);
            }
            if (!invoice.Support(paymentMethodId))
            {
                if (!isDefaultPaymentId)
                {
                    return(null);
                }
                var paymentMethodTemp = invoice.GetPaymentMethods()
                                        .Where(c => paymentMethodId.bitcoinCode == c.GetId().bitcoinCode)
                                        .FirstOrDefault();
                if (paymentMethodTemp == null)
                {
                    paymentMethodTemp = invoice.GetPaymentMethods().First();
                }
                network         = paymentMethodTemp.Network;
                paymentMethodId = paymentMethodTemp.GetId();
            }

            var paymentMethod        = invoice.GetPaymentMethod(paymentMethodId);
            var paymentMethodDetails = paymentMethod.GetPaymentMethodDetails();
            var dto         = invoice.EntityToDTO();
            var bitcoinInfo = dto.bitcoinInfo.First(o => o.GetpaymentMethodId() == paymentMethodId);
            var storeBlob   = store.GetStoreBlob();
            var currency    = invoice.ProductInformation.Currency;
            var accounting  = paymentMethod.Calculate();

            ChangellySettings changelly = (storeBlob.ChangellySettings != null && storeBlob.ChangellySettings.Enabled &&
                                           storeBlob.ChangellySettings.IsConfigured())
                ? storeBlob.ChangellySettings
                : null;

            CoinSwitchSettings coinswitch = (storeBlob.CoinSwitchSettings != null && storeBlob.CoinSwitchSettings.Enabled &&
                                             storeBlob.CoinSwitchSettings.IsConfigured())
                ? storeBlob.CoinSwitchSettings
                : null;


            var changellyAmountDue = changelly != null
                ? (accounting.Due.ToDecimal(MoneyUnit.BTC) *
                   (1m + (changelly.AmountMarkupPercentage / 100m)))
                : (decimal?)null;

            var paymentMethodHandler = _paymentMethodHandlerDictionary[paymentMethodId];

            var divisibility = _CurrencyNameTable.GetNumberFormatInfo(paymentMethod.GetId().bitcoinCode, false)?.CurrencyDecimalDigits;

            var model = new PaymentModel()
            {
                bitcoinCode         = network.bitcoinCode,
                RootPath            = this.Request.PathBase.Value.WithTrailingSlash(),
                OrderId             = invoice.OrderId,
                InvoiceId           = invoice.Id,
                DefaultLang         = storeBlob.DefaultLang ?? "en",
                CustomCSSLink       = storeBlob.CustomCSS,
                CustomLogoLink      = storeBlob.CustomLogo,
                HtmlTitle           = storeBlob.HtmlTitle ?? "BTCPay Invoice",
                bitcoinImage        = Request.GetRelativePathOrAbsolute(paymentMethodHandler.GetbitcoinImage(paymentMethodId)),
                BtcAddress          = paymentMethodDetails.GetPaymentDestination(),
                BtcDue              = accounting.Due.ShowMoney(divisibility),
                OrderAmount         = (accounting.TotalDue - accounting.NetworkFee).ShowMoney(divisibility),
                OrderAmountFiat     = OrderAmountFromInvoice(network.bitcoinCode, invoice.ProductInformation),
                CustomerEmail       = invoice.RefundMail,
                RequiresRefundEmail = storeBlob.RequiresRefundEmail,
                ShowRecommendedFee  = storeBlob.ShowRecommendedFee,
                FeeRate             = paymentMethodDetails.GetFeeRate(),
                ExpirationSeconds   = Math.Max(0, (int)(invoice.ExpirationTime - DateTimeOffset.UtcNow).TotalSeconds),
                MaxTimeSeconds      = (int)(invoice.ExpirationTime - invoice.InvoiceTime).TotalSeconds,
                MaxTimeMinutes      = (int)(invoice.ExpirationTime - invoice.InvoiceTime).TotalMinutes,
                ItemDesc            = invoice.ProductInformation.ItemDesc,
                Rate                  = ExchangeRate(paymentMethod),
                MerchantRefLink       = invoice.RedirectURL?.AbsoluteUri ?? "/",
                RedirectAutomatically = invoice.RedirectAutomatically,
                StoreName             = store.StoreName,
                PeerInfo              = (paymentMethodDetails as LightningLikePaymentMethodDetails)?.NodeInfo,
                TxCount               = accounting.TxRequired,
                BtcPaid               = accounting.Paid.ShowMoney(divisibility),
#pragma warning disable CS0618 // Type or member is obsolete
                Status = invoice.StatusString,
#pragma warning restore CS0618 // Type or member is obsolete
                NetworkFee          = paymentMethodDetails.GetNextNetworkFee(),
                IsMultiCurrency     = invoice.GetPayments().Select(p => p.GetPaymentMethodId()).Concat(new[] { paymentMethod.GetId() }).Distinct().Count() > 1,
                ChangellyEnabled    = changelly != null,
                ChangellyMerchantId = changelly?.ChangellyMerchantId,
                ChangellyAmountDue  = changellyAmountDue,
                CoinSwitchEnabled   = coinswitch != null,
                CoinSwitchAmountMarkupPercentage = coinswitch?.AmountMarkupPercentage ?? 0,
                CoinSwitchMerchantId             = coinswitch?.MerchantId,
                CoinSwitchMode    = coinswitch?.Mode,
                StoreId           = store.Id,
                Availablebitcoins = invoice.GetPaymentMethods()
                                    .Where(i => i.Network != null)
                                    .Select(kv =>
                {
                    var availablebitcoinPaymentMethodId = kv.GetId();
                    var availablebitcoinHandler         = _paymentMethodHandlerDictionary[availablebitcoinPaymentMethodId];
                    return(new PaymentModel.Availablebitcoin()
                    {
                        PaymentMethodId = kv.GetId().ToString(),
                        bitcoinCode = kv.Network?.bitcoinCode ?? kv.GetId().bitcoinCode,
                        PaymentMethodName = availablebitcoinHandler.GetPaymentMethodName(availablebitcoinPaymentMethodId),
                        IsLightning =
                            kv.GetId().PaymentType == PaymentTypes.LightningLike,
                        bitcoinImage = Request.GetRelativePathOrAbsolute(availablebitcoinHandler.GetbitcoinImage(availablebitcoinPaymentMethodId)),
                        Link = Url.Action(nameof(Checkout),
                                          new
                        {
                            invoiceId = invoiceId,
                            paymentMethodId = kv.GetId().ToString()
                        })
                    });
                }).Where(c => c.bitcoinImage != "/")
                                    .OrderByDescending(a => a.bitcoinCode == "BTC").ThenBy(a => a.PaymentMethodName).ThenBy(a => a.IsLightning ? 1 : 0)
                                    .ToList()
            };

            paymentMethodHandler.PreparePaymentModel(model, dto, storeBlob);
            if (model.IsLightning && storeBlob.LightningAmountInSatoshi && model.bitcoinCode == "Sats")
            {
                model.Rate = _CurrencyNameTable.DisplayFormatCurrency(paymentMethod.Rate / 100_000_000, paymentMethod.ParentEntity.ProductInformation.Currency);
            }
            model.UISettings      = paymentMethodHandler.GetCheckoutUISettings();
            model.PaymentMethodId = paymentMethodId.ToString();
            var expiration = TimeSpan.FromSeconds(model.ExpirationSeconds);

            model.TimeLeft = expiration.PrettyPrint();
            return(model);
        }
        private async Task <PaymentModel> GetInvoiceModel(string invoiceId, PaymentMethodId paymentMethodId)
        {
            var invoice = await _InvoiceRepository.GetInvoice(invoiceId);

            if (invoice == null)
            {
                return(null);
            }
            var store = await _StoreRepository.FindStore(invoice.StoreId);

            bool isDefaultPaymentId = false;

            if (paymentMethodId == null)
            {
                paymentMethodId    = store.GetDefaultPaymentId(_NetworkProvider);
                isDefaultPaymentId = true;
            }
            var network = _NetworkProvider.GetNetwork(paymentMethodId.CryptoCode);

            if (network == null && isDefaultPaymentId)
            {
                network         = _NetworkProvider.GetAll().FirstOrDefault();
                paymentMethodId = new PaymentMethodId(network.CryptoCode, PaymentTypes.BTCLike);
            }
            if (invoice == null || network == null)
            {
                return(null);
            }
            if (!invoice.Support(paymentMethodId))
            {
                if (!isDefaultPaymentId)
                {
                    return(null);
                }
                var paymentMethodTemp = invoice.GetPaymentMethods(_NetworkProvider)
                                        .Where(c => paymentMethodId.CryptoCode == c.GetId().CryptoCode)
                                        .FirstOrDefault();
                if (paymentMethodTemp == null)
                {
                    paymentMethodTemp = invoice.GetPaymentMethods(_NetworkProvider).First();
                }
                network         = paymentMethodTemp.Network;
                paymentMethodId = paymentMethodTemp.GetId();
            }

            var paymentMethod        = invoice.GetPaymentMethod(paymentMethodId, _NetworkProvider);
            var paymentMethodDetails = paymentMethod.GetPaymentMethodDetails();
            var dto        = invoice.EntityToDTO(_NetworkProvider);
            var cryptoInfo = dto.CryptoInfo.First(o => o.GetpaymentMethodId() == paymentMethodId);
            var storeBlob  = store.GetStoreBlob();
            var currency   = invoice.ProductInformation.Currency;
            var accounting = paymentMethod.Calculate();

            ChangellySettings changelly = (storeBlob.ChangellySettings != null && storeBlob.ChangellySettings.Enabled &&
                                           storeBlob.ChangellySettings.IsConfigured())
                ? storeBlob.ChangellySettings
                : null;

            CoinSwitchSettings coinswitch = (storeBlob.CoinSwitchSettings != null && storeBlob.CoinSwitchSettings.Enabled &&
                                             storeBlob.CoinSwitchSettings.IsConfigured())
                ? storeBlob.CoinSwitchSettings
                : null;


            var changellyAmountDue = changelly != null
                ? (accounting.Due.ToDecimal(MoneyUnit.BTC) *
                   (1m + (changelly.AmountMarkupPercentage / 100m)))
                : (decimal?)null;

            var model = new PaymentModel()
            {
                CryptoCode               = network.CryptoCode,
                RootPath                 = this.Request.PathBase.Value.WithTrailingSlash(),
                PaymentMethodId          = paymentMethodId.ToString(),
                PaymentMethodName        = GetDisplayName(paymentMethodId, network),
                CryptoImage              = GetImage(paymentMethodId, network),
                IsLightning              = paymentMethodId.PaymentType == PaymentTypes.LightningLike,
                OrderId                  = invoice.OrderId,
                InvoiceId                = invoice.Id,
                DefaultLang              = storeBlob.DefaultLang ?? "en",
                HtmlTitle                = storeBlob.HtmlTitle ?? "BTCPay Invoice",
                CustomCSSLink            = storeBlob.CustomCSS?.AbsoluteUri,
                CustomLogoLink           = storeBlob.CustomLogo?.AbsoluteUri,
                LightningAmountInSatoshi = storeBlob.LightningAmountInSatoshi,
                BtcAddress               = paymentMethodDetails.GetPaymentDestination(),
                BtcDue              = accounting.Due.ToString(),
                OrderAmount         = (accounting.TotalDue - accounting.NetworkFee).ToString(),
                OrderAmountFiat     = OrderAmountFromInvoice(network.CryptoCode, invoice.ProductInformation),
                CustomerEmail       = invoice.RefundMail,
                RequiresRefundEmail = storeBlob.RequiresRefundEmail,
                ExpirationSeconds   = Math.Max(0, (int)(invoice.ExpirationTime - DateTimeOffset.UtcNow).TotalSeconds),
                MaxTimeSeconds      = (int)(invoice.ExpirationTime - invoice.InvoiceTime).TotalSeconds,
                MaxTimeMinutes      = (int)(invoice.ExpirationTime - invoice.InvoiceTime).TotalMinutes,
                ItemDesc            = invoice.ProductInformation.ItemDesc,
                Rate                  = ExchangeRate(paymentMethod),
                MerchantRefLink       = invoice.RedirectURL ?? "/",
                RedirectAutomatically = invoice.RedirectAutomatically,
                StoreName             = store.StoreName,
                InvoiceBitcoinUrl     = paymentMethodId.PaymentType == PaymentTypes.BTCLike ? cryptoInfo.PaymentUrls.BIP21 :
                                        paymentMethodId.PaymentType == PaymentTypes.LightningLike ? cryptoInfo.PaymentUrls.BOLT11 :
                                        throw new NotSupportedException(),
                                              PeerInfo            = (paymentMethodDetails as LightningLikePaymentMethodDetails)?.NodeInfo,
                                              InvoiceBitcoinUrlQR = paymentMethodId.PaymentType == PaymentTypes.BTCLike ? cryptoInfo.PaymentUrls.BIP21 :
                                                                    paymentMethodId.PaymentType == PaymentTypes.LightningLike ? cryptoInfo.PaymentUrls.BOLT11.ToUpperInvariant() :
                                                                    throw new NotSupportedException(),
                                                                          TxCount = accounting.TxRequired,
                                                                          BtcPaid = accounting.Paid.ToString(),
#pragma warning disable CS0618 // Type or member is obsolete
                                                                          Status = invoice.StatusString,
#pragma warning restore CS0618 // Type or member is obsolete
                                                                          NetworkFee          = paymentMethodDetails.GetNextNetworkFee(),
                                                                          IsMultiCurrency     = invoice.GetPayments().Select(p => p.GetPaymentMethodId()).Concat(new[] { paymentMethod.GetId() }).Distinct().Count() > 1,
                                                                          ChangellyEnabled    = changelly != null,
                                                                          ChangellyMerchantId = changelly?.ChangellyMerchantId,
                                                                          ChangellyAmountDue  = changellyAmountDue,
                                                                          CoinSwitchEnabled   = coinswitch != null,
                                                                          CoinSwitchAmountMarkupPercentage = coinswitch?.AmountMarkupPercentage ?? 0,
                                                                          CoinSwitchMerchantId             = coinswitch?.MerchantId,
                                                                          CoinSwitchMode   = coinswitch?.Mode,
                                                                          StoreId          = store.Id,
                                                                          AvailableCryptos = invoice.GetPaymentMethods(_NetworkProvider)
                                                                                             .Where(i => i.Network != null)
                                                                                             .Select(kv => new PaymentModel.AvailableCrypto()
                {
                    PaymentMethodId   = kv.GetId().ToString(),
                    CryptoCode        = kv.GetId().CryptoCode,
                    PaymentMethodName = GetDisplayName(kv.GetId(), kv.Network),
                    IsLightning       = kv.GetId().PaymentType == PaymentTypes.LightningLike,
                    CryptoImage       = GetImage(kv.GetId(), kv.Network),
                    Link = Url.Action(nameof(Checkout), new { invoiceId = invoiceId, paymentMethodId = kv.GetId().ToString() })
                }).Where(c => c.CryptoImage != "/")
                                                                                             .OrderByDescending(a => a.CryptoCode == "BTC").ThenBy(a => a.PaymentMethodName).ThenBy(a => a.IsLightning ? 1 : 0)
                                                                                             .ToList()
            };

            var expiration = TimeSpan.FromSeconds(model.ExpirationSeconds);

            model.TimeLeft = expiration.PrettyPrint();
            return(model);
        }
        public async Task <IActionResult> UpdateChangellySettings(string storeId, UpdateChangellySettingsViewModel vm,
                                                                  string command)
        {
            var store = HttpContext.GetStoreData();

            if (store == null)
            {
                return(NotFound());
            }
            if (vm.Enabled)
            {
                if (!ModelState.IsValid)
                {
                    return(View(vm));
                }
            }

            var changellySettings = new ChangellySettings()
            {
                ApiKey                 = vm.ApiKey,
                ApiSecret              = vm.ApiSecret,
                ApiUrl                 = vm.ApiUrl,
                ChangellyMerchantId    = vm.ChangellyMerchantId,
                Enabled                = vm.Enabled,
                AmountMarkupPercentage = vm.AmountMarkupPercentage
            };

            switch (command)
            {
            case "save":
                var storeBlob = store.GetStoreBlob();
                storeBlob.ChangellySettings = changellySettings;
                store.SetStoreBlob(storeBlob);
                await _Repo.UpdateStore(store);

                TempData[WellKnownTempData.SuccessMessage] = "Changelly settings modified";
                _changellyClientProvider.InvalidateClient(storeId);
                return(RedirectToAction(nameof(UpdateStore), new {
                    storeId
                }));

            case "test":
                try
                {
                    var client = new Changelly(_httpClientFactory.CreateClient(), changellySettings.ApiKey, changellySettings.ApiSecret,
                                               changellySettings.ApiUrl);
                    var result = await client.GetCurrenciesFull();

                    TempData[WellKnownTempData.SuccessMessage] = "Test Successful";
                    return(View(vm));
                }
                catch (Exception ex)
                {
                    TempData[WellKnownTempData.ErrorMessage] = ex.Message;
                    return(View(vm));
                }

            default:
                return(View(vm));
            }
        }