import 'package:cloud_functions/cloud_functions.dart'; import 'package:em2rp/models/alert_model.dart'; import 'package:em2rp/models/user_model.dart'; import 'package:em2rp/utils/debug_log.dart'; import 'package:firebase_auth/firebase_auth.dart'; /// Service d'envoi d'emails via Cloud Functions class EmailService { final FirebaseFunctions _functions = FirebaseFunctions.instanceFor(region: 'us-central1'); /// Envoie un email d'alerte à un utilisateur /// /// [alert] : L'alerte à envoyer /// [userId] : ID de l'utilisateur destinataire /// [templateType] : Type de template à utiliser (par défaut: 'alert-individual') Future sendAlertEmail({ required AlertModel alert, required String userId, String templateType = 'alert-individual', }) async { try { // Vérifier que l'utilisateur est authentifié final currentUser = FirebaseAuth.instance.currentUser; if (currentUser == null) { DebugLog.error('[EmailService] Utilisateur non authentifié'); return false; } DebugLog.info('[EmailService] Envoi email alerte ${alert.id} à $userId'); final result = await _functions.httpsCallable('sendAlertEmail').call({ 'alertId': alert.id, 'userId': userId, 'templateType': templateType, }); final data = result.data as Map; final success = data['success'] as bool? ?? false; final skipped = data['skipped'] as bool? ?? false; if (skipped) { final reason = data['reason'] as String? ?? 'unknown'; DebugLog.info('[EmailService] Email non envoyé: $reason'); return false; } if (success) { DebugLog.info('[EmailService] Email envoyé avec succès'); return true; } return false; } catch (e) { DebugLog.error('[EmailService] Erreur envoi email', e); return false; } } /// Envoie un email d'alerte à plusieurs utilisateurs /// /// [alert] : L'alerte à envoyer /// [userIds] : Liste des IDs des utilisateurs destinataires Future> sendAlertEmailToMultipleUsers({ required AlertModel alert, required List userIds, String templateType = 'alert-individual', }) async { final results = {}; DebugLog.info('[EmailService] Envoi emails à ${userIds.length} utilisateurs'); // Envoyer en parallèle (max 5 à la fois pour éviter surcharge) final batches = >[]; for (var i = 0; i < userIds.length; i += 5) { batches.add(userIds.sublist( i, i + 5 > userIds.length ? userIds.length : i + 5, )); } for (final batch in batches) { final futures = batch.map((userId) => sendAlertEmail( alert: alert, userId: userId, templateType: templateType, )); final batchResults = await Future.wait(futures); for (var i = 0; i < batch.length; i++) { results[batch[i]] = batchResults[i]; } } final successCount = results.values.where((v) => v).length; DebugLog.info('[EmailService] $successCount/${ userIds.length} emails envoyés'); return results; } /// Détermine si une alerte doit être envoyée immédiatement ou en digest /// /// [alert] : L'alerte à vérifier /// Returns: true si immédiat, false si digest bool shouldSendImmediate(AlertModel alert) { // Les alertes critiques sont envoyées immédiatement if (alert.severity == AlertSeverity.critical) { return true; } // Types d'alertes toujours immédiates const immediateTypes = [ AlertType.lost, // Équipement perdu AlertType.eventCancelled, // Événement annulé ]; return immediateTypes.contains(alert.type); } /// Envoie un email d'alerte en tenant compte des préférences /// /// [alert] : L'alerte à envoyer /// [userIds] : Liste des IDs des utilisateurs destinataires Future sendAlertWithPreferences({ required AlertModel alert, required List userIds, }) async { if (userIds.isEmpty) { DebugLog.warning('[EmailService] Aucun utilisateur à notifier'); return; } final immediate = shouldSendImmediate(alert); if (immediate) { DebugLog.info('[EmailService] Envoi immédiat (alerte critique)'); await sendAlertEmailToMultipleUsers( alert: alert, userIds: userIds, templateType: 'alert-individual', ); } else { DebugLog.info('[EmailService] Ajout au digest (alerte non critique)'); // Les alertes non critiques seront envoyées dans le digest quotidien // La Cloud Function sendDailyDigest s'en occupera // Rien à faire ici, les alertes sont déjà dans Firestore } } }