using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Sony.ChartBot.ChartApi; using Sony.ChartBot.Client.InputParsers; using Sony.ChartBot.Entities; using Sony.ChartBot.Entities.ChartApi; using Sony.ChartBot.Entities.MessengerApi; using Sony.ChartBot.Entities.Storage; using Sony.ChartBot.Helpers; using Sony.ChartBot.Messages.Helpers; using Sony.ChartBot.Messages.MessageBuilders; using Sony.ChartBot.Repository; namespace Sony.ChartBot.Client.Commands { public class HandleMessageCommand : IMessagingCommand { private readonly ChartApiClient _chartApiClient; private readonly ConversationRepository _conversationRepository; private readonly CountryRepository _countryRepository; private readonly MessageSender _messageSender; private readonly CourtesyInputHelper _courtesyInputHelper; private readonly ArtistAndCountryInputParser _artistAndCountryInputParser; private readonly ChartTrackModelBuilder _chartTrackModelBuilder; public HandleMessageCommand( ChartApiClient chartApiClient, ConversationRepository conversationRepository, CountryRepository countryRepository, MessageSender messageSender, CourtesyInputHelper courtesyInputHelper, ArtistAndCountryInputParser artistAndCountryInputParser, ChartTrackModelBuilder chartTrackModelBuilder ) { _chartApiClient = chartApiClient; _conversationRepository = conversationRepository; _countryRepository = countryRepository; _messageSender = messageSender; _courtesyInputHelper = courtesyInputHelper; _artistAndCountryInputParser = artistAndCountryInputParser; _chartTrackModelBuilder = chartTrackModelBuilder; } public async Task HandleCallbackReceivedAsync(MessagingData input) { // Echos are messages sent by the bot itself - just ignore if (input.message.is_echo) { return; } // Get last message sent by bot to user var lastSentMessage = await _conversationRepository.GetLastAskedQuestionToUserAsync(input.sender.id); if (lastSentMessage == null) { throw new Exception($"Missing last message sent to user {input.recipient.id}"); } // If message already handled - just ignore if (lastSentMessage.MessengerMessageId != null && lastSentMessage.MessengerMessageId.Equals(input.message.mid, StringComparison.CurrentCultureIgnoreCase)) { return; } // Try handling non-command input if (_courtesyInputHelper.IsCourtesyInput(input)) { await HandleCourtesyCallbackReceivedAsync(input); return; } // Get message context by checking last asked question switch (lastSentMessage.InquiryType) { case InquiryType.AskForArtist: await HandleArtistInputReceivedAsync(input); break; case InquiryType.AskForComparison: await HandleComparisonInputReceivedAsync(input, lastSentMessage); break; default: throw new NotSupportedException($"Invalid last message sent to user {input.recipient.id}"); } } private async Task HandleCourtesyCallbackReceivedAsync(MessagingData input) { await _messageSender.BuildAndSendMessagesAsync(input); } private async Task HandleArtistInputReceivedAsync(MessagingData input) { // Parse input Artist artist; SupportedCountry country; try { var structuredData = _artistAndCountryInputParser.ParseInput(input.message.text); artist = structuredData.Item1; country = structuredData.Item2; } catch (InvalidInputException ex) { await _messageSender.SendInputParsingErrorResponseAsync(input, ex.Input, ex.Type); return; } // Try to use user's default country if no country is provided if (country == null) { country = await _countryRepository.GetDefaultCountryAsync(input.sender.id); if (country == null) { throw new Exception($"Default country not found for user {input.sender.id}"); } } // Get chart position input and send response var chartResponse = await _chartApiClient.GetChartPositionsAsync(artist.Name, country.CountryCode); if (chartResponse == null) { await _messageSender.BuildAndSendMessagesAsync(input, artist.Name); } else if (!chartResponse.Tracks.Any()) { var model = (await _chartTrackModelBuilder.BuildModels(chartResponse, country, input.sender.id, includeSubscriptionStatus: true)).First(); await _messageSender.BuildAndSendMessagesAsync( input, model); } else { await _messageSender.BuildAndSendMessagesAsync(input); var model = await _chartTrackModelBuilder.BuildModels(chartResponse, country, input.sender.id, includeSubscriptionStatus: true); await _messageSender.BuildAndSendMessagesAsync>( input, model); } } private async Task HandleComparisonInputReceivedAsync(MessagingData input, MessageRecord lastSentMessage) { // Parse input Artist compareArtist; SupportedCountry compareCountry; try { var structuredData = _artistAndCountryInputParser.ParseInput(input.message.text); compareArtist = structuredData.Item1; compareCountry = structuredData.Item2; } catch (InvalidInputException ex) { await _messageSender.SendInputParsingErrorResponseAsync(input, ex.Input, ex.Type); return; } // Try to use user's default country if no country is provided if (compareCountry == null) { compareCountry = await _countryRepository.GetDefaultCountryAsync(input.sender.id); if (compareCountry == null) { throw new Exception($"Default country not found for user {input.sender.id}"); } } // Last message should cointain a track reference to know what track to compare with var trackReference = lastSentMessage.TrackReference; string originalTrackName, originalArtistName, originalCountryCode; if (string.IsNullOrWhiteSpace(trackReference) || !new TrackReferenceGenerator().TryParseTrackReference(trackReference, out originalArtistName, out originalTrackName, out originalCountryCode)) { throw new Exception("Could not find which track to compare with"); } var originalCountry = _countryRepository.GetSupportedCountry(originalCountryCode); if (originalCountry == null) { throw new Exception($"Invalid stored compare input: Invalid country {originalCountryCode}"); } // Get chart positions for both tracks and send response var originalChartResponse = await _chartApiClient.GetChartPositionsAsync(originalArtistName, originalCountryCode, originalTrackName); if (originalChartResponse == null) { throw new Exception($"No chart position for orginal track {originalTrackName} in comparison"); } var compareChartResponse = await _chartApiClient.GetChartPositionsAsync(compareArtist.Name, compareCountry.CountryCode); if (compareChartResponse == null) { await _messageSender.BuildAndSendMessagesAsync( input, compareArtist.Name, InquiryType.AskForComparison, trackReference); } else if (!compareChartResponse.Tracks.Any()) { var compareModel = (await _chartTrackModelBuilder.BuildModels(compareChartResponse, compareCountry, input.sender.id)).First(); await _messageSender.BuildAndSendMessagesAsync( input, compareModel, InquiryType.AskForComparison, trackReference); } else { var originalModel = (await _chartTrackModelBuilder.BuildModels(originalChartResponse, originalCountry, input.sender.id)).First(); var compareModel = (await _chartTrackModelBuilder.BuildModels(compareChartResponse, compareCountry, input.sender.id)).First(); var messageData = new[] { originalModel, compareModel, }; await _messageSender .BuildAndSendMessagesAsync>( input, messageData); } } } }