public async Task <ActionResult <TransactionViewModel> > CreateIntent(CreateIntentBody createIntentBody)
        {
            try
            {
                Logger.LogInformation("Creating intent of {Amount} by {User} for {Event}", createIntentBody.Amount, createIntentBody.UserId, createIntentBody.EventId);
                var result = await TransactionService.CreateIntent(createIntentBody);

                return(result);
            }
            catch (Exception e)
            {
                Logger.LogError(e.ToString());
                return(BadRequest(e));
            }
        }
        /// <inheritdoc />
        /// <exception cref="UserNotFoundException">Thrown when the user is not found</exception>
        /// <exception cref="Exception">Thrown if error</exception>
        /// <exception cref="EventNotFoundException">Thrown if the event is not found</exception>
        public async Task <TransactionViewModel> CreateIntent(CreateIntentBody createIntentBody)
        {
            var user = await ApplicationContext.Users
                       .Include(x => x.PaymentMethods)
                       .FirstOrDefaultAsync(x => x.Id == createIntentBody.UserId);

            var e = await ApplicationContext.Events.AsSplitQuery()
                    .Include(x => x.Promos)
                    .Include(x => x.Host)
                    .Include(x => x.Tickets)
                    .Include(x => x.Transactions)
                    .FirstOrDefaultAsync(x => x.Id == createIntentBody.EventId);

            if (user == null)
            {
                Logger.LogInformation("User was not found");
                throw new UserNotFoundException();
            }

            // if the user doesn't have a customer id or payment method throw exception
            if (user.StripeCustomerId == null || !user.PaymentMethods.Any())
            {
                throw new Exception("Not enough stripe info");
            }

            if (e == null)
            {
                Logger.LogInformation("Event was not found");
                throw new EventNotFoundException();
            }

            // if the host of the event hasn't setup a bank account throw exception
            if (e.Host.StripeAccountId == null)
            {
                throw new Exception("The host doesn't have enough stripe info");
            }

            // gets a promo that's currently active
            var promo = e.Promos.FirstOrDefault(x => x.Active && x.Start < DateTime.Now && DateTime.Now < x.End);

            if (promo != null)
            {
                // applies discount to price
                createIntentBody.Amount -= (createIntentBody.Amount * promo.Discount / 100);
                Logger.LogInformation("Found promo for event");
            }

            // Stipee api create intent options
            var options = new PaymentIntentCreateOptions()
            {
                Amount               = createIntentBody.Amount,
                Currency             = "gbp",
                OnBehalfOf           = e.Host.StripeAccountId,
                Customer             = user.StripeCustomerId,
                ConfirmationMethod   = "manual",
                ApplicationFeeAmount = 10,
                TransferData         = new PaymentIntentTransferDataOptions()
                {
                    Destination = e.Host.StripeAccountId
                },
                PaymentMethodTypes = new List <string>
                {
                    "card"
                },
                Metadata = new Dictionary <string, string>
                {
                    { "EventId", e.Id.ToString() },
                    { "PromoId", promo?.Id.ToString() }
                },
            };

            var service = new PaymentIntentService();

            try
            {
                var ticket = e.Tickets.FirstOrDefault(x => x.Available);

                // if there's no tickets left then throw exception
                if (ticket == null)
                {
                    throw new Exception("Out of tickets");
                }

                // Sends request to Strip api to create intent
                var intent = service.Create(options);

                e.TicketsLeft = e.Tickets.Count(x => x.Available) - 1;

                ticket.User      = user;
                ticket.Available = false;

                // records transaction using Stripe response
                Transaction transaction = new Transaction()
                {
                    Amount         = intent.Amount,
                    User           = user,
                    Paid           = intent.Status == "succeeded",
                    StripeIntentId = intent.Id,
                    Start          = DateTime.Now,
                    Updated        = DateTime.Now,
                    Status         = Enum.Parse <PaymentStatus>(intent.Status, true),
                    Ticket         = ticket,
                    Event          = e,
                    ClientSecret   = intent.ClientSecret,
                    PromoId        = promo?.Id
                };

                await ApplicationContext.Transactions.AddAsync(transaction);

                await ApplicationContext.SaveChangesAsync();

                // start the intent timout method
                CheckOnIntent(transaction.StripeIntentId, ticket.Id, e.Id);

                return(Mapper.Map <TransactionViewModel>(transaction));
            }
            catch (Exception exception)
            {
                Console.WriteLine(exception);
                throw;
            }
        }