public HttpResponseMessage ThreeDSecureCallback(Guid invoiceKey, Guid paymentKey, [FromBody]threeDSecurePostback values)
        {
        
              SagePayDirectIntegration sagePayDirectIntegration = new SagePayDirectIntegration(_directProcessor.Settings);

            // Query merchello for associated invoice and payment objects
            var invoice = _merchelloContext.Services.InvoiceService.GetByKey(invoiceKey);
            var payment = _merchelloContext.Services.PaymentService.GetByKey(paymentKey);

            if (invoice == null)
            {
                var ex = new NullReferenceException(string.Format("Invalid argument exception. Arguments: invoiceKey={0}, paymentKey={1}", invoiceKey, paymentKey));
                LogHelper.Error<SagePayApiController>("Payment not authorized.", ex);
                throw ex;
            }

            // Complete payment with Sagepay

            IThreeDAuthRequest request = sagePayDirectIntegration.ThreeDAuthRequest();
            request.Md = values.MD;
            request.PaRes = values.PaRes;
            IDirectPaymentResult result = sagePayDirectIntegration.ProcessDirect3D(request);

            if (result.Status != ResponseStatus.OK)
            {
                return ShowError(result.StatusDetail);

            }
            // Store some SagePay data in payment
            payment.ReferenceNumber = result.VpsTxId;
            payment.ExtendedData.SetValue(Constants.ExtendedDataKeys.SagePayTransactionCode, result.VpsTxId);

            // Authorize and save payment
            var authorizeResult = _directProcessor.AuthorizePayment(invoice, payment);
            _merchelloContext.Services.GatewayProviderService.Save(payment);
            if (!authorizeResult.Payment.Success)
            {
                LogHelper.Error<SagePayApiController>("Payment is not authorized.", authorizeResult.Payment.Exception);
                _merchelloContext.Services.GatewayProviderService.ApplyPaymentToInvoice(payment.Key, invoice.Key, AppliedPaymentType.Denied, "SagePay: request capture authorization error: " + authorizeResult.Payment.Exception.Message, 0);
                return ShowError(authorizeResult.Payment.Exception.Message);
            }

            _merchelloContext.Services.GatewayProviderService.ApplyPaymentToInvoice(payment.Key, invoice.Key, AppliedPaymentType.Debit, "SagePay: capture authorized", 0);

            // Capture payment
            var providerKeyGuid = new Guid(Constants.GatewayProviderSettingsKey);
            var paymentGatewayMethod = _merchelloContext.Gateways.Payment.GetPaymentGatewayMethods().First(item => item.PaymentMethod.ProviderKey == providerKeyGuid);

            var captureResult = paymentGatewayMethod.CapturePayment(invoice, payment, payment.Amount, null);
            if (!captureResult.Payment.Success)
            {
                LogHelper.Error<SagePayApiController>("Payment not captured.", captureResult.Payment.Exception);
                return ShowError(captureResult.Payment.Exception.Message);
            }

            Notification.Trigger("OrderConfirmation", new Merchello.Core.Gateways.Payment.PaymentResult(Attempt<Merchello.Core.Models.IPayment>.Succeed(payment), invoice, true), new[] { invoice.BillToEmail });
            
            
            // Redirect to ReturnUrl (with token replacement for an alternative means of order retrieval)
            var returnUrl = payment.ExtendedData.GetValue(Constants.ExtendedDataKeys.ReturnUrl);
            var response = Request.CreateResponse(HttpStatusCode.Moved);

            Func<string, string> adjustUrl = (url) =>
            {
                if (!url.StartsWith("http")) url = GetWebsiteUrl() + (url[0] == '/' ? "" : "/") + url;
                url = url.Replace("{invoiceKey}", invoice.Key.ToString(), StringComparison.InvariantCultureIgnoreCase);
                url = url.Replace("{paymentKey}", payment.Key.ToString(), StringComparison.InvariantCultureIgnoreCase);
                return url;
            };

            var redirectUrl = adjustUrl("/App_Plugins/Merchello.SagePay/3dsecureFinished.aspx?");
            redirectUrl += "&redirect=" + Base64Encode(returnUrl.Replace("%INVOICE%", invoice.Key.ToString().EncryptWithMachineKey()));
            response.Headers.Location = new Uri(redirectUrl);
            return response;
        }
        public HttpResponseMessage PaypalCallback(Guid invoiceKey, Guid paymentKey)
        {
            IPayPalNotificationRequest payPalNotificationRequest = new SagePayDirectIntegration(_directProcessor.Settings).GetPayPalNotificationRequest();

            if (payPalNotificationRequest.Status != ResponseStatus.OK)
            {
                //var ex = new Exception(string.Format("Invalid payment status.  Detail: {0}", paymentResult.StatusDetail));
                //LogHelper.Error<SagePayApiController>("Sagepay error processing payment.", ex);
                return ShowError(payPalNotificationRequest.StatusDetail);
            }

            // Query merchello for associated invoice and payment objects
            var invoice = _merchelloContext.Services.InvoiceService.GetByKey(invoiceKey);
            var payment = _merchelloContext.Services.PaymentService.GetByKey(paymentKey);

            if (invoice == null || payment == null || invoice.CustomerKey == null)
            {
                var ex = new NullReferenceException(string.Format("Invalid argument exception. Arguments: invoiceKey={0}, paymentKey={1}", invoiceKey, paymentKey));
                LogHelper.Error<SagePayApiController>("Payment not authorized.", ex);
                throw ex;
            }

            // Complete payment with Sagepay
            // Once again, the sagepay integration kit provided by sagepay does not support paypal integration with sagepay direct so we have to build the post manually.
            NameValueCollection sagePayResponseValues = new NameValueCollection();
            using (var client = new HttpClient())
            {
                var values = new Dictionary<string, string> { };
                values.Add("Accept", "YES");
                values.Add("VPSProtocol", "3.00");
                values.Add("TxType", "COMPLETE");
                values.Add("VPSTxId", payment.ExtendedData.GetValue(Constants.ExtendedDataKeys.SagePayTransactionCode));
                values.Add("Amount", invoice.Total.ToString("n2"));
   
                var content = new FormUrlEncodedContent(values);

                var sagePayResponse = client.PostAsync(string.Format("https://{0}.sagepay.com/gateway/service/complete.vsp", _directProcessor.Settings.Environment), content).Result;

                var responseString = sagePayResponse.Content.ReadAsStringAsync().Result.Replace("\r\n", "&");

                sagePayResponseValues = HttpUtility.ParseQueryString(responseString);
                if (sagePayResponseValues["Status"] != "OK")
                {
                    return ShowError(sagePayResponseValues["StatusDetail"]);    
                }
                

            }


            // Get a ref to the customer so the invoice Key can be stored in their extended data.
            // This can be retrieved on the receipt page
            //var customer = _merchelloContext.Services.CustomerService.GetByKey(invoice.CustomerKey.Value);
            //customer.ExtendedData.SetValue(Constants.ExtendedDataKeys.InvoiceKey, invoice.Key.ToString());

            // Store some SagePay data in payment
            payment.ReferenceNumber = sagePayResponseValues["VPSTxId"];
            payment.ExtendedData.SetValue(Constants.ExtendedDataKeys.SagePayTransactionCode, sagePayResponseValues["VPSTxId"]);

            // Authorize and save payment
            var authorizeResult = _directProcessor.AuthorizePayment(invoice, payment);
            _merchelloContext.Services.GatewayProviderService.Save(payment);
            if (!authorizeResult.Payment.Success)
            {
                LogHelper.Error<SagePayApiController>("Payment is not authorized.", authorizeResult.Payment.Exception);
                _merchelloContext.Services.GatewayProviderService.ApplyPaymentToInvoice(payment.Key, invoice.Key, AppliedPaymentType.Denied, "SagePay: request capture authorization error: " + authorizeResult.Payment.Exception.Message, 0);
                return ShowError(authorizeResult.Payment.Exception.Message);
            }

            _merchelloContext.Services.GatewayProviderService.ApplyPaymentToInvoice(payment.Key, invoice.Key, AppliedPaymentType.Debit, "SagePay: capture authorized", 0);

            // Capture payment
            var providerKeyGuid = new Guid(Constants.GatewayProviderSettingsKey);
            var paymentGatewayMethod = _merchelloContext.Gateways.Payment.GetPaymentGatewayMethods().First(item => item.PaymentMethod.ProviderKey == providerKeyGuid);

            var captureResult = paymentGatewayMethod.CapturePayment(invoice, payment, payment.Amount, null);
            if (!captureResult.Payment.Success)
            {
                LogHelper.Error<SagePayApiController>("Payment not captured.", captureResult.Payment.Exception);
                return ShowError(captureResult.Payment.Exception.Message);
            }

            // Redirect to ReturnUrl (with token replacement for an alternative means of order retrieval)
            var returnUrl = payment.ExtendedData.GetValue(Constants.ExtendedDataKeys.ReturnUrl);
            var response = Request.CreateResponse(HttpStatusCode.Moved);
            response.Headers.Location = new Uri(returnUrl.Replace("%INVOICE%", invoice.Key.ToString().EncryptWithMachineKey()));
            return response;
        }