using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Security.Cryptography; using System.Threading.Tasks; using BotFramework.Attributes; using BotFramework.Enums; using Kruzya.TelegramBot.Core; using Kruzya.TelegramBot.Core.AutoDelete; using Kruzya.TelegramBot.Core.Data; using Kruzya.TelegramBot.Core.Extensions; using Kruzya.TelegramBot.Core.Handler; using Kruzya.TelegramBot.Core.Service; using Telegram.Bot; using Telegram.Bot.Types; using Telegram.Bot.Types.Enums; using Telegram.Bot.Types.ReplyMarkups; namespace West.Entertainment.Handler; public class Guess : CommonHandler { private readonly IGuessCache _guessCache; private readonly ThreadSafeRandom _rng; private readonly IReputation _reputationService; private readonly CoreContext _db; private readonly ConcurrentBag _requests; public Guess(IGuessCache guessCache, ThreadSafeRandom rng, IReputation reputationService, CoreContext db, ConcurrentBag requests) : base(db) { _guessCache = guessCache; _rng = rng; _reputationService = reputationService; _db = db; _requests = requests; } [InChat(InChat.Public)] [Command("guess", CommandParseMode.Both)] public async Task HandleGuess() { // Drop user message. _requests.Add(new DeleteRequest { ChatId = Chat.Id, DeleteAt = DateTime.UtcNow.AddSeconds(20), MessageId = Message!.MessageId }); var cooldownOption = await _db.UserValues.FindOrCreateOption(Chat.Id, From.Id, "guessCooldown"); var cooldown = cooldownOption.GetValue(); if (cooldown > DateTime.Now) { await Reply($"Следующее использование через {cooldown - DateTime.Now:hh\\:mm\\:ss}."); return; } var guessDict = _guessCache.GetOr(Chat.Id, new ConcurrentDictionary()); var doesExist = guessDict.Any(pair => pair.Value.UserId == From.Id); if (doesExist) { await Bot.SendTextMessageAsync(Chat, "Вы уже запустили игру."); return; } var messageId = RawUpdate.Message!.MessageId; var guessedNumber = RandomNumberGenerator.GetInt32(1, 4); // Console.WriteLine(guessedNumber); var guessData = new GuessData { Number = guessedNumber, UserId = From.Id }; var keyBoard = new InlineKeyboardMarkup(new List { new("1") { CallbackData = $"guess|{From.Id}|answer|1" }, new("2") { CallbackData = $"guess|{From.Id}|answer|2" }, new("3") { CallbackData = $"guess|{From.Id}|answer|3" } }); var message = await Bot.SendTextMessageAsync(Chat.Id, "Выберите число от 1 до 3.", replyToMessageId: messageId, replyMarkup: keyBoard ); if (!guessDict.TryAdd(message.MessageId, guessData)) { return; } _guessCache.SetValue(Chat.Id, guessDict, -1); } [InChat(InChat.Public)] [Update(UpdateFlag.CallbackQuery)] public async Task HandleGuessResponse() { var messageId = CallbackQuery.Message?.MessageId; if (messageId == null || CallbackQuery.Data == null) { return; } var fromUser = CallbackQuery.From; var fromId = fromUser.Id; var callbackData = CallbackQuery.Data.Split('|'); if (callbackData.Length < 4 || callbackData[0] != "guess" || callbackData[1] != fromId.ToString() || callbackData[2] != "answer") { return; } var guessDict = _guessCache.GetOr(Chat.Id, new ConcurrentDictionary()); if (!guessDict.TryGetValue((int) messageId, out var data) || fromId != data.UserId) { return; } if (!int.TryParse(callbackData[3], out var responseNumber)) { return; } await Bot.AnswerCallbackQueryAsync(CallbackQuery.Id); guessDict.TryRemove((int) messageId, out _); _guessCache.SetValue(Chat.Id, guessDict, -1); var now = DateTime.Now; var nextUse = now.AddHours(1); var postFix = $"\nЗагаданное число: {data.Number}.\nСледующая попытка через: {nextUse - now:hh\\:mm\\:ss}"; string message; if (responseNumber == data.Number) { await _reputationService.IncrementReputationAsync(Chat, From, 20); message = $"{fromUser.ToHtml()} угадал! +20 кармы.\n"; } else { message = $"{fromUser.ToHtml()} не угадал!\n\nОтвет: {responseNumber}."; } var cooldownOption = await _db.UserValues.FindOrCreateOption(Chat.Id, From.Id, "guessCooldown"); cooldownOption.SetValue(nextUse); _db.AddOrUpdate(cooldownOption); await Bot.EditMessageTextAsync(Chat, (int) messageId, message + postFix, parseMode: ParseMode.Html); // Drop bot message. _requests.Add(new DeleteRequest { ChatId = Chat.Id, DeleteAt = DateTime.UtcNow.AddSeconds(20), MessageId = (int) messageId }); } protected override async Task Reply(string text) { // TODO: move feature with autocleaning to Core CommonHandler. var message = await Bot.SendTextMessageAsync(Chat.Id, text, replyToMessageId: Message?.MessageId, parseMode: ParseMode.Html); _requests.Add(new DeleteRequest { ChatId = Chat.Id, DeleteAt = DateTime.UtcNow.AddSeconds(20), MessageId = message.MessageId }); return message; } }