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;
}
}