import 'dart:async';

import 'package:flutter/material.dart';

import '../../domain/entities/notification.dart' as domain;
import '../datasources/notification_remote_data_source.dart';
import '../services/realtime_notification_service.dart';
import '../services/secure_storage.dart';

/// Service centralisé de gestion des notifications.
///
/// Ce service gère:
/// - Le compteur de notifications non lues
/// - Le chargement des notifications depuis l'API
/// - Les notifications in-app
/// - Les listeners pour les changements
///
/// **Usage avec Provider:**
/// ```dart
/// // Dans main.dart
/// ChangeNotifierProvider(
///   create: (_) => NotificationService(
///     NotificationRemoteDataSource(http.Client()),
///     SecureStorage(),
///   )..initialize(),
/// ),
///
/// // Dans un widget
/// final notificationService = Provider.of<NotificationService>(context);
/// final unreadCount = notificationService.unreadCount;
/// ```
class NotificationService extends ChangeNotifier {
  NotificationService(this._dataSource, this._secureStorage);

  final NotificationRemoteDataSource _dataSource;
  final SecureStorage _secureStorage;

  List<domain.Notification> _notifications = [];
  bool _isLoading = false;
  Timer? _refreshTimer;

  // Service de notifications temps réel
  RealtimeNotificationService? _realtimeService;
  StreamSubscription<SystemNotification>? _systemNotificationSubscription;

  /// Liste de toutes les notifications
  List<domain.Notification> get notifications => List.unmodifiable(_notifications);

  /// Nombre total de notifications
  int get totalCount => _notifications.length;

  /// Nombre de notifications non lues
  int get unreadCount => _notifications.where((n) => !n.isRead).length;

  /// Indique si les notifications sont en cours de chargement
  bool get isLoading => _isLoading;

  /// Initialise le service (à appeler au démarrage de l'app).
  Future<void> initialize() async {
    await loadNotifications();
    // Actualise les notifications toutes les 2 minutes
    _startPeriodicRefresh();
  }

  /// Charge les notifications depuis l'API.
  Future<void> loadNotifications() async {
    _isLoading = true;
    notifyListeners();

    try {
      final userId = await _secureStorage.getUserId();
      if (userId == null || userId.isEmpty) {
        _isLoading = false;
        notifyListeners();
        return;
      }

      final notificationModels = await _dataSource.getNotifications(userId);
      _notifications = notificationModels.map((model) => model.toEntity()).toList();

      // Trie par timestamp décroissant (les plus récentes en premier)
      _notifications.sort((a, b) => b.timestamp.compareTo(a.timestamp));
    } catch (e) {
      debugPrint('[NotificationService] Erreur chargement: $e');
    } finally {
      _isLoading = false;
      notifyListeners();
    }
  }

  /// Marque une notification comme lue.
  Future<void> markAsRead(String notificationId) async {
    try {
      await _dataSource.markAsRead(notificationId);

      // Mise à jour locale
      final index = _notifications.indexWhere((n) => n.id == notificationId);
      if (index != -1) {
        _notifications[index] = _notifications[index].copyWith(isRead: true);
        notifyListeners();
      }
    } catch (e) {
      debugPrint('[NotificationService] Erreur marquage lu: $e');
      rethrow;
    }
  }

  /// Marque toutes les notifications comme lues.
  Future<void> markAllAsRead() async {
    try {
      final userId = await _secureStorage.getUserId();
      if (userId == null) return;

      await _dataSource.markAllAsRead(userId);

      // Mise à jour locale
      _notifications = _notifications.map((n) => n.copyWith(isRead: true)).toList();
      notifyListeners();
    } catch (e) {
      debugPrint('[NotificationService] Erreur marquage tout lu: $e');
      rethrow;
    }
  }

  /// Supprime une notification.
  Future<void> deleteNotification(String notificationId) async {
    try {
      await _dataSource.deleteNotification(notificationId);

      // Mise à jour locale
      _notifications.removeWhere((n) => n.id == notificationId);
      notifyListeners();
    } catch (e) {
      debugPrint('[NotificationService] Erreur suppression: $e');
      rethrow;
    }
  }

  /// Ajoute une nouvelle notification (simulation ou depuis push notification).
  ///
  /// Utilisé pour afficher une notification in-app quand une nouvelle
  /// notification arrive via Firebase Cloud Messaging.
  void addNotification(domain.Notification notification) {
    _notifications.insert(0, notification);
    notifyListeners();
  }

  /// Démarre l'actualisation périodique des notifications.
  void _startPeriodicRefresh() {
    _refreshTimer?.cancel();
    _refreshTimer = Timer.periodic(
      const Duration(minutes: 2),
      (_) => loadNotifications(),
    );
  }

  /// Arrête l'actualisation périodique.
  void stopPeriodicRefresh() {
    _refreshTimer?.cancel();
    _refreshTimer = null;
  }

  /// Connecte le service de notifications temps réel.
  ///
  /// Cette méthode remplace le polling par des notifications push en temps réel.
  /// Le polling est automatiquement désactivé lorsque le service temps réel est connecté.
  ///
  /// [service] : Le service de notifications temps réel à connecter.
  void connectRealtime(RealtimeNotificationService service) {
    _realtimeService = service;

    // IMPORTANT : Arrêter le polling puisqu'on passe en temps réel
    stopPeriodicRefresh();
    debugPrint('[NotificationService] Polling arrêté, passage en mode temps réel');

    // Écouter les notifications système en temps réel
    _systemNotificationSubscription = service.systemNotificationStream.listen(
      _handleSystemNotification,
      onError: (error) {
        debugPrint('[NotificationService] Erreur dans le stream de notifications système: $error');
      },
    );

    debugPrint('[NotificationService] Service de notifications temps réel connecté');
  }

  /// Gère les notifications système reçues en temps réel.
  ///
  /// Cette méthode est appelée automatiquement lorsqu'une notification
  /// est reçue via WebSocket.
  void _handleSystemNotification(SystemNotification notification) {
    debugPrint('[NotificationService] Notification système reçue: ${notification.title}');

    // Convertir en entité domain
    final domainNotification = domain.Notification(
      id: notification.notificationId,
      title: notification.title,
      message: notification.message,
      type: _parseNotificationType(notification.type),
      timestamp: notification.timestamp,
      isRead: false,
      eventId: null,
      userId: '', // Le userId sera récupéré du contexte
      metadata: null,
    );

    // Ajouter à la liste locale (en tête de liste pour avoir les plus récentes en premier)
    addNotification(domainNotification);

    debugPrint('[NotificationService] Notification ajoutée à la liste locale: ${notification.title}');
  }

  /// Parse le type de notification depuis une chaîne.
  domain.NotificationType _parseNotificationType(String type) {
    switch (type.toLowerCase()) {
      case 'event':
        return domain.NotificationType.event;
      case 'friend':
        return domain.NotificationType.friend;
      case 'reminder':
        return domain.NotificationType.reminder;
      default:
        return domain.NotificationType.other;
    }
  }

  /// Déconnecte le service de notifications temps réel.
  ///
  /// Le polling est automatiquement redémarré lorsque le service est déconnecté.
  void disconnectRealtime() {
    _systemNotificationSubscription?.cancel();
    _systemNotificationSubscription = null;
    _realtimeService = null;

    // Redémarrer le polling si déconnecté du temps réel
    _startPeriodicRefresh();
    debugPrint('[NotificationService] Service temps réel déconnecté, reprise du polling');
  }

  @override
  void dispose() {
    disconnectRealtime();
    stopPeriodicRefresh();
    super.dispose();
  }
}
