public CancelTicketResponse CancelTicket(long hostId, CancelTicketRequest value, out string status)
        {
            AdmissionServices admissionServices = new AdmissionServices();
            var ticket = admissionServices.GetTicketByTicketNo(hostId, value.TicketNumber);

            if (ticket == null)
            {
                status = CancelTicketStatuses.TicketNotFound;
                return(null);
            }
            else
            {
                return(CancelAndRefundTicket(hostId, ticket.TicketId.Value, out status));
            }
        }
        //TODO: performance optimize this method to cancel tickets in bulk
        public CancelTicketResponse CancelAndRefundTicket(long hostId, long ticketId, out string status)
        {
            CancelTicketResponse result = null;

            AdmissionServices admissionServices = new AdmissionServices();

            //Get ticket info
            var ticket = admissionServices.GetTicketById(ticketId);

            if (ticket == null)
            {
                status = CancelTicketStatuses.TicketNotFound;
                return(null);
            }
            if (ticket.Status == TicketStatuses.Used)
            {
                status = CancelTicketStatuses.TicketAlreadyUsed;
                return(null);
            }
            if (ticket.Status == TicketStatuses.Cancelled)
            {
                status = CancelTicketStatuses.TicketAlreadyCancelled;
                return(null);
            }

            //Get event info
            var eventInfo = GetEventByRef(hostId, ticket.EventReferenceId);

            if (eventInfo == null)
            {
                status = CancelTicketStatuses.EventNotFound;
                return(null);
            }
            //Validate event status
            if (eventInfo.Status != EventStatuses.Active)
            {
                status = CancelTicketStatuses.EventNotActive;
                return(null);
            }
            //Validate if event start date is over
            if (DateTime.UtcNow >= eventInfo.StartDate)
            {
                status = CancelTicketStatuses.EventHasAlreadyStarted;
                return(null);
            }

            //Get event tier
            EventsServices eventsServices = new EventsServices();
            var            eventTier      = eventsServices.GetEventTiersByRef(hostId, ticket.TierReferenceId);

            if (eventTier == null)
            {
                status = CancelTicketStatuses.TierNotFound;
                return(null);
            }

            //Get customer info
            CustomerServices customerServices = new CustomerServices();
            var customer = customerServices.GetCustomerByRef(hostId, ticket.CustomerReferenceId);

            if (customer == null)
            {
                status = CancelTicketStatuses.CustomerNotFound;
                return(null);
            }

            //Refund the customer using funds from the event address
            WalletServices walletServices = new WalletServices();

            walletServices.Transfer(eventInfo.WalletAddress, customer.WalletAddress, ticket.PaidPrice.Value, ticket.BookingId, "Refund");

            //Update ticket status to cancelled
            admissionServices.UpdateTicketStatus(ticketId, TicketStatuses.Cancelled);

            //Update ticket availability
            BookingServices bookingServices = new BookingServices();

            bookingServices.UpdateAvailableTickets(eventTier.TierId.Value, eventTier.AvailableTickets.Value + 1);

            //Commit to blockchain
            ContractApi blockchainContract = new ContractApi();

            blockchainContract.CancelTicket(ticket.TicketNo);

            status = CancelEventStatuses.Success;

            result                 = new CancelTicketResponse();
            result.EventTitle      = ticket.EventTitle;
            result.TierTitle       = ticket.TierTitle;
            result.PaidPrice       = ticket.PaidPrice;
            result.NewTicketStatus = TicketStatuses.Cancelled;

            return(result);
        }