private Lottery(CasinoTest instance, string id)
        {
            CasinoTestInstance = instance;
            Id = id;

            for (int i = 1; i <= PoolSize; i++)
            {
                _collector[i] = 0;
            }

            var subscription = CasinoTestInstance.GetDocumentStore.Subscriptions.Create <Bet>(database: CasinoTestInstance.GetDocumentStore.Database,
                                                                                              predicate: (bet) => bet.LotteryId == Id);

            var worker = CasinoTestInstance.GetDocumentStore.Subscriptions.GetSubscriptionWorker <Bet>(subscription, database: CasinoTestInstance.GetDocumentStore.Database);

            worker.Run((batch) =>
            {
                foreach (var bet in batch.Items)
                {
                    if (bet.Result.BetStatus == Bet.Status.Closed)
                    {
                        CasinoTestInstance.GetDocumentStore.Subscriptions.Delete(subscription);
                        _collecting.Set();
                        return;
                    }

                    foreach (var number in bet.Result.Numbers)
                    {
                        _collector[number]++;
                    }
                }
            });
        }
        public static async Task <User> RegisterOrLoad(CasinoTest instance, string email, string name)
        {
            using (var session = instance.GetClusterSessionAsync)
            {
                var result = await session.Advanced.ClusterTransaction.GetCompareExchangeValueAsync <string>(email);

                if (result?.Value != null)
                {
                    return(await session.LoadAsync <User>(result.Value));
                }
            }

            var user = new User
            {
                Email  = email,
                Name   = name,
                Credit = 1000
            };

            using (var session = instance.GetClusterSessionAsync)
            {
                await session.StoreAsync(user);

                session.Advanced.ClusterTransaction.CreateCompareExchangeValue(user.Email, user.Id);
                await session.SaveChangesAsync();
            }

            return(user);
        }
        public async Task ChangeBet(CasinoTest instance, string betId, int[] numbers, int price)
        {
            if (price <= 0)
            {
                throw new ArgumentException("Price must be positive number.");
            }

            using (var session = instance.GetSessionAsync)
            {
                var bet = await session.LoadAsync <Bet>(betId);

                var user = await session.LoadAsync <User>(Id);

                await Lottery.ValidateOpen(session, bet.LotteryId);

                user.Credit += bet.Price;
                if (user.Credit < price)
                {
                    throw new InsufficientFunds("Not enough credit");
                }

                bet.Price   = price;
                bet.Numbers = numbers;

                user.Credit -= price;
                await session.StoreAsync(bet);

                await session.StoreAsync(user);

                await session.SaveChangesAsync();
            }
        }
 public static async Task AddAvatar(CasinoTest instance, string id, string path)
 {
     using (var stream = new FileStream(path, FileMode.Open))
         using (var session = instance.GetSessionAsync)
         {
             session.Advanced.Attachments.Store(id, "Avatar", stream);
             await session.SaveChangesAsync();
         }
 }
        public static async Task Delete(CasinoTest instance, string email)
        {
            using (var session = instance.GetClusterSessionAsync)
            {
                var result = await session.Advanced.ClusterTransaction.GetCompareExchangeValueAsync <string>(email);

                session.Advanced.ClusterTransaction.DeleteCompareExchangeValue(email, result.Index);
                session.Delete(result.Value);
                await session.SaveChangesAsync();
            }
        }
        public static async Task <Lottery> CreateLottery(CasinoTest casinoInstance)
        {
            var lottery = new Lottery(casinoInstance, $"Lottery/{DateTime.UtcNow}/" + Guid.NewGuid())
            {
                DueTime = DateTime.UtcNow.AddMinutes(1),
                Status  = LotteryStatus.Open
            };

            using (var session = casinoInstance.GetSessionAsync)
            {
                session.Advanced.WaitForReplicationAfterSaveChanges(timeout: TimeSpan.FromSeconds(180), replicas: casinoInstance.ReplicaCount());
                await session.StoreAsync(lottery, lottery.Id);

                await session.SaveChangesAsync();
            }

            return(lottery);
        }
        public async Task PlaceBet(CasinoTest instance, string lotteryId, int[] numbers, int price)
        {
            if (price <= 0)
            {
                throw new ArgumentException("Price must be positive number.");
            }

            using (var session = instance.GetSessionAsync)
            {
                var user = await session.LoadAsync <User>(Id);

                if (user.Credit < price)
                {
                    throw new InsufficientFunds("Not enough credit");
                }

                var bet = new Bet
                {
                    UserId    = Id,
                    LotteryId = lotteryId,
                    Numbers   = numbers,
                    Price     = price,
                    BetStatus = Bet.Status.Active
                };

                session.Advanced.GetMetadataFor(bet)[Constants.Documents.Metadata.Expires] = DateTime.UtcNow.AddMinutes(10);

                await session.StoreAsync(bet);

                user.Credit -= price;
                user.Bets.Add(bet.Id);

                await Lottery.ValidateOpen(session, lotteryId);

                session.CountersFor(lotteryId).Increment(DateTime.UtcNow.ToString("yyyy MMMM dd hh:mm"));

                await session.SaveChangesAsync();
            }
        }
        public async Task DeleteBet(CasinoTest instance, string betId)
        {
            using (var session = instance.GetSessionAsync)
            {
                var user = await session.LoadAsync <User>(Id);

                var bet = await session.LoadAsync <Bet>(betId);

                await Lottery.ValidateOpen(session, bet.LotteryId);

                bet.BetStatus = Bet.Status.Deleted;

                if (user.Bets.Remove(betId))
                {
                    user.Credit += bet.Price;
                    await session.StoreAsync(bet);

                    await session.StoreAsync(user);

                    await session.SaveChangesAsync();
                }
            }
        }