using System.Threading.Tasks; using NadekoBot.Core.Services; using NadekoBot.Core.Modules.Gambling.Common; using System.Threading; using System.Linq; using System.Collections.Generic; using Discord; using System; namespace NadekoBot.Core.Modules.Gambling.Services { public class CurrencyRaffleService : INService { public enum JoinErrorType { NotEnoughCurrency, AlreadyJoinedOrInvalidAmount } private readonly SemaphoreSlim _locker = new SemaphoreSlim(1, 1); private readonly DbService _db; private readonly CurrencyService _cs; public Dictionary Games { get; } = new Dictionary(); public CurrencyRaffleService(DbService db, CurrencyService cs) { _db = db; _cs = cs; } public async Task<(CurrencyRaffleGame, JoinErrorType?)> JoinOrCreateGame(ulong channelId, IUser user, int amount, bool mixed, Func onEnded) { await _locker.WaitAsync().ConfigureAwait(false); try { var newGame = false; if (!Games.TryGetValue(channelId, out var crg)) { newGame = true; crg = new CurrencyRaffleGame(mixed ? CurrencyRaffleGame.Type.Mixed : CurrencyRaffleGame.Type.Normal); Games.Add(channelId, crg); } using (var uow = _db.UnitOfWork) { //remove money, and stop the game if this // user created it and doesn't have the money if (!await _cs.RemoveAsync(user.Id, "Currency Raffle Join", amount, uow).ConfigureAwait(false)) { if (newGame) Games.Remove(channelId); return (null, JoinErrorType.NotEnoughCurrency); } if (!crg.AddUser(user, amount)) { await _cs.AddAsync(user.Id, "Curency Raffle Refund", amount, uow).ConfigureAwait(false); return (null, JoinErrorType.AlreadyJoinedOrInvalidAmount); } uow.Complete(); } if (newGame) { var _t = Task.Run(async () => { await Task.Delay(30000).ConfigureAwait(false); await _locker.WaitAsync().ConfigureAwait(false); try { var winner = crg.GetWinner(); var won = crg.Users.Sum(x => x.Amount); using (var uow = _db.UnitOfWork) { await _cs.AddAsync(winner.DiscordUser.Id, "Currency Raffle Win", won, uow); uow.Complete(); } Games.Remove(channelId, out _); var oe = onEnded(winner.DiscordUser, won); } catch { } finally { _locker.Release(); } }); } return (crg, null); } finally { _locker.Release(); } } } }