public IHttpActionResult SaveSponsor(SponsorModel requestModel)
        {
            if (!ModelState.IsValid)
            {
                return(Json(new { Success = false, Message = "Invalid Data" }));
            }

            var battle = _videoBattleService.Get(requestModel.BattleId); //todo: query picture battles when ready

            if (battle == null)
            {
                return(Json(new { Success = false, Message = "Invalid Battle" }));
            }

            var isProductOnlySponsorship = requestModel.SponsorshipType == SponsorshipType.OnlyProducts;

            var userId = ApplicationContext.Current.CurrentUser.Id;

            //there is a possibility that a sponsor is increasing the sponsorship amount. In that case, the new sponsorship status will automatically
            //be of same status as that of previous one for the same battle
            //lets find if the sponsor already exist for this battle?
            var existingSponsors = _sponsorService.GetSponsors(userId, requestModel.BattleId, requestModel.BattleType, null);

            var newSponsorStatus = SponsorshipStatus.Pending;

            //so is the current customer already an sponsor for this battle?
            if (existingSponsors.Any())
            {
                newSponsorStatus = existingSponsors.First().SponsorshipStatus;
            }

            if (!isProductOnlySponsorship)
            {
                //are issued credits sufficient?
                var issuedCreditsCount = _creditService.GetUsableCreditsCount(userId);
                if ((issuedCreditsCount < battle.MinimumSponsorshipAmount && newSponsorStatus != SponsorshipStatus.Accepted) || requestModel.SponsorshipCredits > issuedCreditsCount)
                {
                    VerboseReporter.ReportError("Insufficient credits to become sponsor", "save_sponsor");
                    return(RespondFailure());
                }
            }

            //mark the credits as spent credits
            var spentCredit = new Credit()
            {
                CreditContextKey      = string.Format(CreditContextKeyNames.BattleSponsor, battle.Id),
                CreditCount           = requestModel.SponsorshipCredits,
                CreditTransactionType = CreditTransactionType.Spent,
                CreditType            = CreditType.Transactional,
                PaymentTransactionId  = 0,
                CreatedOnUtc          = DateTime.UtcNow,
                UserId = userId
            };

            _creditService.Insert(spentCredit);

            //create the sponsor and set the status to pending or an existing status as determined above. (the status will be marked accepted or rejected or cancelled by battle owner)
            var sponsor = new Sponsor()
            {
                BattleId          = requestModel.BattleId,
                BattleType        = requestModel.BattleType,
                SponsorshipAmount = isProductOnlySponsorship ? 0 : requestModel.SponsorshipCredits,
                UserId            = userId,
                SponsorshipStatus = newSponsorStatus,
                DateCreated       = DateTime.UtcNow,
                DateUpdated       = DateTime.UtcNow
            };

            //save the sponsor
            _sponsorService.Insert(sponsor);

            if (!isProductOnlySponsorship)
            {
                //save the prizes only sponsorship prizes
                SaveSponsorProductPrizes(requestModel.Prizes);
            }


            var battleOwner = _userService.Get(battle.ChallengerId);

            var sponsorCustomer = _userService.Get(userId);

            //send notification to battle owner
            _emailSender.SendSponsorAppliedNotificationToBattleOwner(battleOwner, sponsorCustomer, battle);

            return(Json(new { Success = true }));
        }
        public IHttpActionResult ProcessPayment(FormCollection parameters)
        {
            //first get the payment processor
            var paymentMethodName = parameters.Get(PaymentParameterNames.PaymentMethodTypeName);

            if (string.IsNullOrEmpty(paymentMethodName))
            {
                VerboseReporter.ReportError("Invalid payment method", "process_payment");
                return(RespondFailure());
            }

            //the transaction amount
            decimal amount;
            var     amountString = parameters.Get(PaymentParameterNames.Amount) ?? "0";

            decimal.TryParse(amountString, out amount);

            PaymentMethodType methodType;

            if (System.Enum.TryParse(paymentMethodName, out methodType))
            {
                methodType = PaymentMethodType.CreditCard;
            }

            //get the payment processor now
            var paymentProcessor = _paymentProcessingService.GetPaymentProcessorPlugin(amount, methodType);

            if (paymentProcessor == null)
            {
                VerboseReporter.ReportError("Invalid payment method", "process_payment");
                return(RespondFailure());
            }

            //convert form collection to dictionary to check if parameters are valid
            var formCollectionDictionary = parameters.ToDictionary(pair => pair.Key, pair => (object)pair.Value);

            var isValid = paymentProcessor.AreParametersValid(formCollectionDictionary);

            UserPaymentMethod paymentMethod = null;

            if (!isValid)
            {
                //the parameters are not valid. but that may also mean that the user is selecting an already saved payment method
                //and so he wouldn't have sent that data again
                var savedPaymentMethodIdString = parameters.Get(PaymentParameterNames.UserSavedPaymentMethodId);
                int savedPaymentMethodId;
                if (int.TryParse(savedPaymentMethodIdString, out savedPaymentMethodId))
                {
                    var userPaymentMethods =
                        _paymentMethodService.Get(x => x.UserId == ApplicationContext.Current.CurrentUser.Id && x.Id == savedPaymentMethodId, null);

                    if (userPaymentMethods.Any())
                    {
                        paymentMethod = userPaymentMethods.First();
                        isValid       = true;
                    }
                }
                //still invalid? something is not right then.
                if (!isValid)
                {
                    VerboseReporter.ReportError("Invalid parameters to process payment", "process_payment");
                    return(RespondFailure());
                }
            }

            //we save the payment method in our database if it's CreditCard
            if (paymentProcessor.Supports(PaymentMethodType.CreditCard))
            {
                if (paymentMethod == null)
                {
                    #region saving payment method to database
                    var creditCardNumber = parameters.Get(PaymentParameterNames.CardNumber);
                    //let's validate the card for level 1 check (luhn's test) first before storing
                    var isCardValid = PaymentCardHelper.IsCardNumberValid(creditCardNumber);
                    //card number
                    if (!isCardValid)
                    {
                        VerboseReporter.ReportError("Invalid card number", "process_payment");
                        return(RespondFailure());
                    }
                    //expiration date
                    var expireMonth = parameters.Get(PaymentParameterNames.ExpireMonth);
                    var expireYear  = parameters.Get(PaymentParameterNames.ExpireYear);
                    if (!expireYear.IsInteger() || !expireMonth.IsInteger())
                    {
                        VerboseReporter.ReportError("Invalid expiration month or year", "process_payment");
                        return(RespondFailure());
                    }
                    //card issuer
                    var cardIssuer = PaymentCardHelper.GetCardTypeFromNumber(creditCardNumber);
                    if (!cardIssuer.HasValue)
                    {
                        VerboseReporter.ReportError("Unsupported card provider", "process_payment");
                        return(RespondFailure());
                    }


                    var nameOnCard = parameters.Get(PaymentParameterNames.NameOnCard);
                    //encrypt credit card info to store in db
                    var key  = ConfigurationManager.AppSettings.Get("EncryptionKey");
                    var salt = ConfigurationManager.AppSettings.Get("Salt");

                    var cardNumber = _cryptographyService.Encrypt(creditCardNumber, key, salt); //encrypt the card info
                    //fine if the card is valid, but is the card number already in our record, then not possible to save the same again
                    if (_paymentMethodService.DoesCardNumberExist(cardNumber))
                    {
                        VerboseReporter.ReportError("The card number is already saved in records", "process_payment");
                        return(RespondFailure());
                    }

                    paymentMethod = new UserPaymentMethod()
                    {
                        UserId            = ApplicationContext.Current.CurrentUser.Id,
                        IsVerified        = false,
                        PaymentMethodType = PaymentMethodType.CreditCard,
                        CardIssuerType    = cardIssuer.ToString().ToLowerInvariant(),
                        CardNumber        = creditCardNumber,
                        CardNumberMasked  = PaymentCardHelper.MaskCardNumber(creditCardNumber),
                        NameOnCard        = nameOnCard,
                    };
                    //save this payment method
                    _paymentMethodService.Insert(paymentMethod);
                    #endregion
                }
            }


            //we need to see if we should only authorize or capture as well
            //the idea is if it's a sponsorship context, it's better to authorize the payment transaction and capture later when
            //the sponsorship is accepted //we thought of initially only authorizing sponsorship transactions and capture when it's accepted.
            //but that flow doesn't seem to work quite well, thoughts?
            var authorizeOnly = false; // (parameters.Get(PaymentParameterNames.PaymentContext) ?? string.Empty) == "sponsor";

            //so we are ready for payment processing, let's create a paymenttrasaction for storing in our db
            var paymentTransaction = new PaymentTransaction()
            {
                IsLocalTransaction = true,
                PaymentStatus      = PaymentStatus.Pending,
                TransactionAmount  = amount,
                TransactionGuid    = Guid.NewGuid(),
                CreatedOn          = DateTime.UtcNow,
                UserIpAddress      = WebHelper.GetClientIpAddress()
            };
            _paymentTransactionService.Insert(paymentTransaction);

            //now proceed further with the payment
            //create the transaction request
            var transactionRequest = new TransactionRequest()
            {
                Amount                     = amount,
                CurrencyIsoCode            = "USD",//TODO: SET CURRENCY AS SELECTED BY USER
                PaymentProcessorSystemName = paymentProcessor.PluginInfo.SystemName,
                UserId                     = ApplicationContext.Current.CurrentUser.Id,
                Parameters                 = formCollectionDictionary,
                TransactionUniqueId        = paymentTransaction.TransactionGuid.ToString()
            };


            var response = paymentProcessor.Process(transactionRequest, authorizeOnly);
            //update values of transaction parameters for future reference
            paymentTransaction.TransactionCodes = response.ResponseParameters;
            //update payment transaction
            _paymentTransactionService.Update(paymentTransaction);

            if (response.Success)
            {
                //let's verify the payment method first if it's not
                if (paymentMethod != null && !paymentMethod.IsVerified)
                {
                    paymentMethod.IsVerified = true;
                    _paymentMethodService.Update(paymentMethod);
                }

                //now since the response was success, we can actually assign some credits to the user
                var creditCount = amount * (1 / _paymentSettings.CreditExchangeRate);
                var credit      = new Credit()
                {
                    PaymentTransactionId = paymentTransaction.Id,
                    CreatedOnUtc         = DateTime.UtcNow,
                    CreditCount          = creditCount,
                    CreditExchangeRate   = _paymentSettings.CreditExchangeRate,
                    //if it's authorize only transaction, we assign the credits, but they won't be usable before they are approved by capture
                    CreditTransactionType = CreditTransactionType.Issued,
                    CreditType            = CreditType.Transactional,
                    IsExpired             = false
                };

                //save credit
                _creditService.Insert(credit);

                //get total available credits of user
                var usableCreditCount = _creditService.GetUsableCreditsCount(ApplicationContext.Current.CurrentUser.Id);
                return(RespondSuccess(new {
                    UsableCreditCount = usableCreditCount
                }));
            }
            VerboseReporter.ReportError("An error occured while processing payment", "process_payment");
            return(RespondFailure());
        }