using System; using System.Collections.Generic; using System.Net.Http; using System.Text.Json; using System.Threading; using System.Threading.Tasks; using FinlyticCore.Models.Trades; using Microsoft.Extensions.Logging; namespace FinlyticBackend.Services; /// /// Defines a service for dispatching push notifications via Firebase Cloud Messaging (FCM). /// public interface IFirebaseNotificationService { /// /// Sends a push notification about a new trade proposal. /// /// The trade proposal details. /// The list of FCM device tokens. /// A cancellation token. /// A task representing the asynchronous operation. Task SendTradeProposalNotificationAsync(TradeProposalDto proposal, List fcmTokens, CancellationToken cancellationToken = default); /// /// Sends a push notification about an update to an existing trade. /// /// The trade update details. /// The list of FCM device tokens. /// A cancellation token. /// A task representing the asynchronous operation. Task SendTradeUpdateNotificationAsync(TradeHourlyUpdateDto update, List fcmTokens, CancellationToken cancellationToken = default); } /// public class FirebaseNotificationService : IFirebaseNotificationService { private readonly HttpClient _httpClient; private readonly ILogger _logger; /// /// Initializes a new instance of the class. /// /// The HTTP client for making API requests. /// The logger instance. public FirebaseNotificationService(HttpClient httpClient, ILogger logger) { _httpClient = httpClient; _logger = logger; } /// public async Task SendTradeProposalNotificationAsync(TradeProposalDto proposal, List fcmTokens, CancellationToken cancellationToken = default) { if (fcmTokens == null || fcmTokens.Count == 0) return; string title = $"🚀 Trade Signal: {proposal.SignalType} {proposal.Symbol}"; string body = $"{proposal.CompanyName} ({proposal.Isin}) - Entry: ${proposal.EntryPrice:F2}, WinRate: {proposal.WinRate:F1}%. {proposal.Reasoning}"; foreach (var token in fcmTokens) { await DispatchFcmMessageAsync(token, title, body, cancellationToken); } } /// public async Task SendTradeUpdateNotificationAsync(TradeHourlyUpdateDto update, List fcmTokens, CancellationToken cancellationToken = default) { if (fcmTokens == null || fcmTokens.Count == 0) return; string title = $"📊 Trade Update: {update.TradeId}"; string body = $"Recommendation: {update.Recommendation} @ ${update.CurrentPrice:F2}. {update.Reasoning}"; foreach (var token in fcmTokens) { await DispatchFcmMessageAsync(token, title, body, cancellationToken); } } private Task DispatchFcmMessageAsync(string fcmToken, string title, string body, CancellationToken cancellationToken) { try { _logger.LogInformation("[{Channel}] FCM Push Notification dispatched to Token [{TokenPrefix}...]: Title='{Title}', Body='{Body}'", "NotificationChannel", fcmToken.Length > 10 ? fcmToken[..10] : fcmToken, title, body); } catch (Exception ex) { _logger.LogError(ex, "[{Channel}] Failed to send FCM push notification to token {Token}", "NotificationChannel", fcmToken); } return Task.CompletedTask; } }