import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:dio/dio.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:uuid/uuid.dart';
import '../models/room.dart';
import '../models/message.dart';
import 'chat_config_loader.dart';
import 'chat_info_service.dart';
import 'package:geosector_app/core/constants/app_keys.dart';
import 'package:geosector_app/core/services/api_service.dart';
import 'package:geosector_app/app.dart'; // Pour accéder à connectivityService

/// Service de chat avec règles métier configurables via YAML
/// Les permissions sont définies dans chat_config.yaml
class ChatService {
  static ChatService? _instance;
  static ChatService get instance => _instance!;
  
  late final Dio _dio;
  late final Box<Room> _roomsBox;
  late final Box<Message> _messagesBox;
  
  late int _currentUserId;
  late String _currentUserName;
  late int _currentUserRole;
  late int? _currentUserEntite;
  
  Timer? _syncTimer;
  DateTime? _lastSyncTimestamp;
  static const Duration _syncInterval = Duration(seconds: 30); // Sync toutes les 30 secondes
  static const Duration _initialSyncDelay = Duration(seconds: 10); // Délai avant première sync
  
  /// Initialisation avec gestion des rôles et configuration YAML
  static Future<void> init({
    required String apiUrl,
    required int userId,
    required String userName,
    required int userRole,
    int? userEntite,
    String? authToken,
  }) async {
    _instance = ChatService._();
    
    // Charger la configuration depuis le YAML
    await ChatConfigLoader.instance.loadConfig();
    
    // Les boxes sont déjà ouvertes par HiveService dans splash_page
    // On vérifie juste qu'elles sont disponibles et on les récupère
    if (!Hive.isBoxOpen(AppKeys.chatRoomsBoxName)) {
      throw Exception('Chat rooms box not open. Please ensure HiveService is initialized.');
    }
    if (!Hive.isBoxOpen(AppKeys.chatMessagesBoxName)) {
      throw Exception('Chat messages box not open. Please ensure HiveService is initialized.');
    }
    
    // Récupérer les boxes déjà ouvertes
    _instance!._roomsBox = Hive.box<Room>(AppKeys.chatRoomsBoxName);
    _instance!._messagesBox = Hive.box<Message>(AppKeys.chatMessagesBoxName);
    
    // Configurer l'utilisateur
    _instance!._currentUserId = userId;
    _instance!._currentUserName = userName;
    _instance!._currentUserRole = userRole;
    _instance!._currentUserEntite = userEntite;
    
    // Configurer Dio
    _instance!._dio = Dio(BaseOptions(
      baseUrl: apiUrl,
      connectTimeout: const Duration(seconds: 10),
      receiveTimeout: const Duration(seconds: 10),
      headers: authToken != null ? {'Authorization': 'Bearer $authToken'} : {},
    ));
    
    // Charger le dernier timestamp de sync depuis Hive
    await _instance!._loadSyncTimestamp();
    
    // Faire la sync initiale complète au login avec délai de 10 secondes
    debugPrint('⏳ Sync initiale chat programmée dans 10 secondes...');
    Future.delayed(_initialSyncDelay, () async {
      await _instance!.getRooms(forceFullSync: true);
      debugPrint('✅ Sync initiale complète effectuée au login');
    });

    // Démarrer la synchronisation incrémentale périodique
    _instance!._startSync();
  }
  
  ChatService._();
  
  /// Obtenir les destinataires possibles selon le rôle
  Future<List<Map<String, dynamic>>> getPossibleRecipients({String? search}) async {
    try {
      // L'API utilise le token pour identifier l'utilisateur et son rôle
      String endpoint = '/chat/recipients';
      final params = <String, dynamic>{};
      
      if (search != null && search.isNotEmpty) {
        params['search'] = search;
      }
      
      final response = await _dio.get(endpoint, queryParameters: params);
      
      // Gérer différents formats de réponse
      if (response.data is List) {
        return List<Map<String, dynamic>>.from(response.data);
      } else if (response.data is Map && response.data['recipients'] != null) {
        return List<Map<String, dynamic>>.from(response.data['recipients']);
      } else if (response.data is Map && response.data['data'] != null) {
        return List<Map<String, dynamic>>.from(response.data['data']);
      } else {
        debugPrint('⚠️ Format inattendu pour /chat/recipients: ${response.data.runtimeType}');
        return [];
      }
    } catch (e) {
      debugPrint('⚠️ Erreur getPossibleRecipients: $e');
      // Fallback sur logique locale selon le rôle
      return _getLocalRecipients();
    }
  }
  
  /// Logique locale de récupération des destinataires
  List<Map<String, dynamic>> _getLocalRecipients() {
    // Cette méthode devrait accéder à la box membres de l'app principale
    // Pour l'instant on retourne une liste vide
    return [];
  }
  
  /// Vérifier si l'utilisateur peut créer une conversation avec un destinataire
  bool canCreateConversationWith(int recipientRole, {int? recipientEntite}) {
    return ChatConfigLoader.instance.canSendMessageTo(
      senderRole: _currentUserRole,
      recipientRole: recipientRole,
      senderEntite: _currentUserEntite,
      recipientEntite: recipientEntite,
    );
  }
  
  /// Obtenir les rooms avec synchronisation incrémentale
  Future<List<Room>> getRooms({bool forceFullSync = false}) async {
    // DÉSACTIVATION TEMPORAIRE - Retour direct du cache sans appeler l'API
    debugPrint('🚫 API /chat/rooms désactivée - utilisation du cache uniquement');
    return _roomsBox.values.toList()
      ..sort((a, b) => (b.lastMessageAt ?? b.createdAt)
          .compareTo(a.lastMessageAt ?? a.createdAt));

    /* Code original commenté pour désactiver les appels API
    // Vérifier la connectivité
    if (!connectivityService.isConnected) {
      debugPrint('📵 Pas de connexion réseau - utilisation du cache');
      return _roomsBox.values.toList()
        ..sort((a, b) => (b.lastMessageAt ?? b.createdAt)
            .compareTo(a.lastMessageAt ?? a.createdAt));
    }

    try {
      // Déterminer si on fait une sync complète ou incrémentale
      final now = DateTime.now();
      final needsFullSync = forceFullSync ||
          _lastFullSync == null ||
          now.difference(_lastFullSync!).compareTo(_fullSyncInterval) > 0;

      Response response;

      if (needsFullSync || _lastSyncTimestamp == null) {
        // Synchronisation complète
        debugPrint('🔄 Synchronisation complète des rooms...');
        // response = await _dio.get('/chat/rooms'); // COMMENTÉ - Désactivation GET /chat/rooms
        return; // Retour anticipé pour éviter l'appel API
        _lastFullSync = now;
      } else {
        // Synchronisation incrémentale
        final isoTimestamp = _lastSyncTimestamp!.toUtc().toIso8601String();
        // debugPrint('🔄 Synchronisation incrémentale depuis $isoTimestamp');
        // response = await _dio.get('/chat/rooms', queryParameters: { // COMMENTÉ - Désactivation GET /chat/rooms
        //   'updated_after': isoTimestamp,
        // });
        return; // Retour anticipé pour éviter l'appel API
      }

      // Extraire le timestamp de synchronisation fourni par l'API
      if (response.data is Map && response.data['sync_timestamp'] != null) {
        _lastSyncTimestamp = DateTime.parse(response.data['sync_timestamp']);
        // debugPrint('⏰ Timestamp de sync reçu de l\'API: $_lastSyncTimestamp');

        // Sauvegarder le timestamp pour la prochaine session
        await _saveSyncTimestamp();
      } else {
        // L'API doit toujours retourner un sync_timestamp
        debugPrint('⚠️ Attention: L\'API n\'a pas retourné de sync_timestamp');
        // On utilise le timestamp actuel comme fallback mais ce n'est pas idéal
        _lastSyncTimestamp = now;
      }

      // Vérifier s'il y a des changements (pour sync incrémentale)
      if (!needsFullSync && response.data is Map && response.data['has_changes'] == false) {
        // debugPrint('✅ Aucun changement depuis la dernière sync');
        return _roomsBox.values.toList()
          ..sort((a, b) => (b.lastMessageAt ?? b.createdAt)
              .compareTo(a.lastMessageAt ?? a.createdAt));
      }

      // Gérer différents formats de réponse API
      List<dynamic> roomsData;
      if (response.data is Map) {
        if (response.data['rooms'] != null) {
          roomsData = response.data['rooms'] as List;
          final hasChanges = response.data['has_changes'] ?? true;
          debugPrint('✅ Réponse API: ${roomsData.length} rooms, has_changes: $hasChanges');
        } else if (response.data['data'] != null) {
          roomsData = response.data['data'] as List;
        } else {
          roomsData = [];
        }
      } else if (response.data is List) {
        roomsData = response.data as List;
      } else {
        roomsData = [];
      }

      // Parser les rooms
      final rooms = <Room>[];
      final deletedRoomIds = <String>[];

      for (final json in roomsData) {
        try {
          // Vérifier si la room est marquée comme supprimée
          if (json['deleted'] == true) {
            deletedRoomIds.add(json['id']);
            continue;
          }

          final room = Room.fromJson(json);
          rooms.add(room);
        } catch (e) {
          debugPrint('❌ Erreur parsing room: $e');
        }
      }

      // Appliquer les modifications à Hive
      if (needsFullSync) {
        // Sync complète : remplacer tout mais préserver certaines données locales
        final existingRooms = Map.fromEntries(
          _roomsBox.values.map((r) => MapEntry(r.id, r))
        );

        await _roomsBox.clear();
        for (final room in rooms) {
          final existingRoom = existingRooms[room.id];
          final roomToSave = Room(
            id: room.id,
            title: room.title,
            type: room.type,
            createdAt: room.createdAt,
            lastMessage: room.lastMessage,
            lastMessageAt: room.lastMessageAt,
            unreadCount: room.unreadCount,
            recentMessages: room.recentMessages,
            updatedAt: room.updatedAt,
            // Préserver createdBy existant si la nouvelle room n'en a pas
            createdBy: room.createdBy ?? existingRoom?.createdBy,
          );
          await _roomsBox.put(roomToSave.id, roomToSave);

          // Traiter les messages récents de la room
          if (room.recentMessages != null && room.recentMessages!.isNotEmpty) {
            for (final msgData in room.recentMessages!) {
              try {
                final message = Message.fromJson(msgData, _currentUserId, roomId: room.id);
                // Sauvegarder uniquement si le message n'existe pas déjà
                if (!_messagesBox.containsKey(message.id) && message.id.isNotEmpty) {
                  await _messagesBox.put(message.id, message);
                  debugPrint('📩 Nouveau message ajouté depuis sync: ${message.id} dans room ${room.id}');
                } else if (message.id.isEmpty) {
                  debugPrint('⚠️ Message avec ID vide ignoré');
                }
              } catch (e) {
                debugPrint('⚠️ Erreur lors du traitement d\'un message récent: $e');
              }
            }
          }
        }
        debugPrint('💾 Sync complète: ${rooms.length} rooms sauvegardées');
      } else {
        // Sync incrémentale : mettre à jour uniquement les changements
        for (final room in rooms) {
          // Préserver le createdBy existant si non fourni par l'API
          final existingRoom = _roomsBox.get(room.id);
          final roomToSave = Room(
            id: room.id,
            title: room.title,
            type: room.type,
            createdAt: room.createdAt,
            lastMessage: room.lastMessage,
            lastMessageAt: room.lastMessageAt,
            unreadCount: room.unreadCount,
            recentMessages: room.recentMessages,
            updatedAt: room.updatedAt,
            // Préserver createdBy existant si la nouvelle room n'en a pas
            createdBy: room.createdBy ?? existingRoom?.createdBy,
          );

          debugPrint('💾 Sauvegarde room ${roomToSave.title} (${roomToSave.id}): createdBy=${roomToSave.createdBy}');
          await _roomsBox.put(roomToSave.id, roomToSave);

          // Traiter les messages récents de la room
          if (room.recentMessages != null && room.recentMessages!.isNotEmpty) {
            for (final msgData in room.recentMessages!) {
              try {
                final message = Message.fromJson(msgData, _currentUserId, roomId: room.id);
                // Sauvegarder uniquement si le message n'existe pas déjà
                if (!_messagesBox.containsKey(message.id) && message.id.isNotEmpty) {
                  await _messagesBox.put(message.id, message);
                  debugPrint('📩 Nouveau message ajouté depuis sync: ${message.id} dans room ${room.id}');
                } else if (message.id.isEmpty) {
                  debugPrint('⚠️ Message avec ID vide ignoré');
                }
              } catch (e) {
                debugPrint('⚠️ Erreur lors du traitement d\'un message récent: $e');
              }
            }
          }
        }
        // Supprimer les rooms marquées comme supprimées
        for (final roomId in deletedRoomIds) {
          // Supprimer la room
          await _roomsBox.delete(roomId);

          // Supprimer tous les messages de cette room
          final messagesToDelete = _messagesBox.values
              .where((msg) => msg.roomId == roomId)
              .map((msg) => msg.id)
              .toList();

          for (final msgId in messagesToDelete) {
            await _messagesBox.delete(msgId);
          }

          debugPrint('🗑️ Room $roomId supprimée avec ${messagesToDelete.length} messages');
        }
        debugPrint('💾 Sync incrémentale: ${rooms.length} rooms mises à jour, ${deletedRoomIds.length} supprimées');
      }

      // Mettre à jour les stats globales
      final allRooms = _roomsBox.values.toList();
      final totalUnread = allRooms.fold<int>(0, (sum, room) => sum + room.unreadCount);
      ChatInfoService.instance.updateStats(
        totalRooms: allRooms.length,
        unreadMessages: totalUnread,
      );

      return allRooms
        ..sort((a, b) => (b.lastMessageAt ?? b.createdAt)
            .compareTo(a.lastMessageAt ?? a.createdAt));
    } catch (e) {
      debugPrint('❌ Erreur sync rooms: $e');
      // Fallback sur le cache local
      return _roomsBox.values.toList()
        ..sort((a, b) => (b.lastMessageAt ?? b.createdAt)
            .compareTo(a.lastMessageAt ?? a.createdAt));
    }
    */// Fin du code commenté
  }
  
  /// Créer une room avec vérification des permissions
  Future<Room?> createRoom({
    required String title,
    required List<int> participantIds,
    String? type,
    String? initialMessage,
  }) async {
    // Générer un ID temporaire pour la room
    final tempId = 'temp_room_${const Uuid().v4()}';
    final now = DateTime.now();
    
    // Créer la room locale immédiatement
    final tempRoom = Room(
      id: tempId,
      title: title,
      type: type ?? (_currentUserRole == 9 ? 'broadcast' : 'private'),
      createdAt: now,
      lastMessage: initialMessage,
      lastMessageAt: initialMessage != null ? now : null,
      unreadCount: 0,
      createdBy: _currentUserId,
      isSynced: false, // Room non synchronisée
    );
    
    // Sauvegarder immédiatement dans Hive
    await _roomsBox.put(tempId, tempRoom);
    debugPrint('💾 Room temporaire sauvée: $tempId');
    
    try {
      // Vérifier les permissions localement d'abord
      // L'API fera aussi une vérification
      
      final data = {
        'title': title,
        'type': type ?? (_currentUserRole == 9 ? 'broadcast' : 'private'),
        'participants': participantIds,
        // L'API récupère le rôle et l'entité depuis le token
      };
      
      // Ajouter le message initial s'il est fourni
      if (initialMessage != null && initialMessage.isNotEmpty) {
        data['initial_message'] = initialMessage;
      }
      
      // Utiliser ApiService qui gère automatiquement la queue offline
      final response = await ApiService.instance.post(
        '/chat/rooms', 
        data: data,
        tempId: tempId, // Passer le tempId pour le mapping après sync
      );
      
      // Vérifier si la room a été mise en queue (offline)
      if (response.data != null && response.data['queued'] == true) {
        debugPrint('📵 Room mise en file d\'attente pour synchronisation: $tempId');
        return tempRoom; // Retourner la room temporaire
      }
      
      // Si online et succès immédiat
      if (response.statusCode == 200 || response.statusCode == 201) {
        final realRoom = Room.fromJson(response.data);
        
        // Remplacer la room temporaire par la room réelle
        await _roomsBox.delete(tempId);
        await _roomsBox.put(realRoom.id, realRoom);
        debugPrint('✅ Room temporaire $tempId remplacée par ${realRoom.id}');
        
        return realRoom;
      }
      
      return tempRoom;
      
    } catch (e) {
      debugPrint('⚠️ Erreur création room: $e - La room sera synchronisée plus tard');
      // La room reste en local avec isSynced = false
      return tempRoom;
    }
  }
  
  /// Créer une conversation one-to-one
  Future<Room?> createPrivateRoom({
    required int recipientId,
    required String recipientName,
    required int recipientRole,
    int? recipientEntite,
    String? initialMessage,
  }) async {
    // Vérifier les permissions via la configuration
    if (!canCreateConversationWith(recipientRole, recipientEntite: recipientEntite)) {
      final messages = ChatConfigLoader.instance.getUIMessages();
      throw Exception(messages['no_permission'] ?? 'Permission refusée');
    }
    
    return createRoom(
      title: recipientName,
      participantIds: [recipientId],
      type: 'private',
      initialMessage: initialMessage,
    );
  }
  
  /// Créer une conversation de groupe (pour superadmin)
  Future<Room?> createGroupRoom({
    required String title,
    required List<int> adminIds,
    String? initialMessage,
  }) async {
    if (_currentUserRole != 9) {
      throw Exception('Seuls les superadmins peuvent créer des groupes');
    }
    
    return createRoom(
      title: title,
      participantIds: adminIds,
      type: 'broadcast',
      initialMessage: initialMessage,
    );
  }
  
  /// Obtenir les messages d'une room (marque automatiquement comme lu)
  Future<Map<String, dynamic>> getMessages(String roomId, {String? beforeMessageId, bool isInitialLoad = false}) async {
    try {
      final params = <String, dynamic>{
        'limit': 50,
      };
      
      if (beforeMessageId != null) {
        params['before'] = beforeMessageId;
      }
      
      final response = await _dio.get('/chat/rooms/$roomId/messages', queryParameters: params);
      
      // Gérer différents formats de réponse
      List<dynamic> messagesData;
      bool hasMore = false;
      int markedAsRead = 0;
      int unreadRemaining = 0;
      
      if (response.data is List) {
        // Si c'est directement une liste de messages
        messagesData = response.data as List;
      } else if (response.data is Map) {
        // Format avec métadonnées
        messagesData = response.data['messages'] ?? response.data['data'] ?? [];
        hasMore = response.data['has_more'] ?? false;
        markedAsRead = response.data['marked_as_read'] ?? 0;
        unreadRemaining = response.data['unread_count'] ?? 0;
        
        if (markedAsRead > 0) {
          debugPrint('✅ $markedAsRead messages marqués comme lus automatiquement');
        }
      } else {
        debugPrint('⚠️ Format inattendu pour les messages: ${response.data.runtimeType}');
        messagesData = [];
      }
      
      final messages = messagesData
          .map((json) => Message.fromJson(json, _currentUserId, roomId: roomId))
          .toList();
      
      debugPrint('📨 Messages reçus pour room $roomId: ${messages.length}');
      for (final msg in messages) {
        debugPrint('  - ${msg.id}: "${msg.content}" de ${msg.senderName} (${msg.senderId}) isMe: ${msg.isMe}');
      }
      
      // Sauvegarder dans Hive (en limitant à 100 messages par room)
      // Si c'est le chargement initial, on remplace tous les messages
      await _saveMessagesToCache(roomId, messages, replaceAll: isInitialLoad && beforeMessageId == null);
      
      // Mettre à jour le unreadCount de la room localement
      final room = _roomsBox.get(roomId);
      if (room != null && unreadRemaining == 0) {
        final updatedRoom = Room(
          id: room.id,
          title: room.title,
          type: room.type,
          createdAt: room.createdAt,
          lastMessage: room.lastMessage,
          lastMessageAt: room.lastMessageAt,
          unreadCount: 0, // Mis à 0 car tout est lu
          recentMessages: room.recentMessages,
          updatedAt: room.updatedAt,
        );
        await _roomsBox.put(roomId, updatedRoom);
        
        // Mettre à jour les stats globales
        ChatInfoService.instance.decrementUnread(markedAsRead);
      }
      
      return {
        'messages': messages,
        'has_more': hasMore,
        'marked_as_read': markedAsRead,
      };
    } catch (e) {
      debugPrint('Erreur getMessages: $e');
      // Fallback sur le cache local
      final cachedMessages = _messagesBox.values
          .where((m) => m.roomId == roomId)
          .toList()
        ..sort((a, b) => a.sentAt.compareTo(b.sentAt));
      
      return {
        'messages': cachedMessages,
        'has_more': false,
        'marked_as_read': 0,
      };
    }
  }
  
  /// Sauvegarder les messages dans le cache en limitant à 100 par room
  Future<void> _saveMessagesToCache(String roomId, List<Message> newMessages, {bool replaceAll = false}) async {
    // Ajouter les nouveaux messages (en évitant les doublons)
    int addedCount = 0;
    for (final message in newMessages) {
      // Vérifier si le message n'existe pas déjà
      if (!_messagesBox.containsKey(message.id) && message.id.isNotEmpty) {
        await _messagesBox.put(message.id, message);
        debugPrint('💾 Message sauvé: ${message.id} dans room ${message.roomId}');
        addedCount++;
      } else if (_messagesBox.containsKey(message.id)) {
        debugPrint('⚠️ Message ${message.id} existe déjà, ignoré pour éviter duplication');
      }
    }
    
    debugPrint('📊 Résumé: ${addedCount} nouveaux messages ajoutés sur ${newMessages.length} reçus');
    
    // Après l'ajout, récupérer TOUS les messages de la room pour le nettoyage
    final allRoomMessages = _messagesBox.values
        .where((m) => m.roomId == roomId)
        .toList()
      ..sort((a, b) => b.sentAt.compareTo(a.sentAt)); // Plus récent en premier
    
    // Si on dépasse 100 messages, supprimer les plus anciens
    if (allRoomMessages.length > 100) {
      final messagesToDelete = allRoomMessages.skip(100).toList();
      debugPrint('🗑️ Suppression de ${messagesToDelete.length} anciens messages');
      for (final message in messagesToDelete) {
        await _messagesBox.delete(message.id);
      }
    }
  }
  
  /// Supprimer une room (seulement pour le créateur)
  Future<bool> deleteRoom(String roomId) async {
    try {
      // Appeler l'API pour supprimer la room
      await _dio.delete('/chat/rooms/$roomId');
      
      // Supprimer la room localement
      await _roomsBox.delete(roomId);
      
      // Supprimer tous les messages de cette room
      final messagesToDelete = _messagesBox.values
          .where((msg) => msg.roomId == roomId)
          .map((msg) => msg.id)
          .toList();
      
      for (final msgId in messagesToDelete) {
        await _messagesBox.delete(msgId);
      }
      
      debugPrint('✅ Room $roomId supprimée avec succès');
      return true;
    } catch (e) {
      debugPrint('❌ Erreur suppression room: $e');
      throw Exception('Impossible de supprimer la conversation');
    }
  }
  
  /// Envoyer un message
  Future<Message?> sendMessage(String roomId, String content) async {
    // Générer un ID temporaire pour le message
    final tempId = 'temp_msg_${const Uuid().v4()}';
    final now = DateTime.now();
    
    // Créer le message local immédiatement (optimistic UI)
    final tempMessage = Message(
      id: tempId,
      roomId: roomId,
      content: content,
      senderId: _currentUserId,
      senderName: _currentUserName,
      sentAt: now,
      isMe: true,
      isRead: false,
      isSynced: false, // Message non synchronisé
    );
    
    // Sauvegarder immédiatement dans Hive pour affichage instantané
    await _messagesBox.put(tempId, tempMessage);
    debugPrint('💾 Message temporaire sauvé: $tempId');
    
    // Mettre à jour la room localement pour affichage immédiat
    final room = _roomsBox.get(roomId);
    if (room != null) {
      final updatedRoom = room.copyWith(
        lastMessage: content,
        lastMessageAt: now,
        unreadCount: 0,
        updatedAt: now,
      );
      await _roomsBox.put(roomId, updatedRoom);
    }
    
    try {
      // Utiliser ApiService qui gère automatiquement la queue offline
      final response = await ApiService.instance.post(
        '/chat/rooms/$roomId/messages',
        data: {
          'content': content,
          // L'API récupère le sender depuis le token
        },
        tempId: tempId, // Passer le tempId pour le mapping après sync
      );
      
      // Vérifier si le message a été mis en queue (offline)
      if (response.data != null && response.data['queued'] == true) {
        debugPrint('📵 Message mis en file d\'attente pour synchronisation: $tempId');
        return tempMessage; // Retourner le message temporaire
      }
      
      // Si online et succès immédiat
      if (response.statusCode == 200 || response.statusCode == 201) {
        // Récupérer le message complet depuis la réponse API
        final realMessage = Message.fromJson(
          response.data['message'] ?? response.data, 
          _currentUserId, 
          roomId: roomId
        );
        
        debugPrint('📨 Message envoyé avec ID réel: ${realMessage.id}');
        
        // Remplacer le message temporaire par le message réel
        await _messagesBox.delete(tempId);
        await _messagesBox.put(realMessage.id, realMessage);
        debugPrint('✅ Message temporaire $tempId remplacé par ${realMessage.id}');
        
        return realMessage;
      }
      
      // Cas par défaut : retourner le message temporaire
      return tempMessage;
      
    } catch (e) {
      debugPrint('⚠️ Erreur envoi message: $e - Le message sera synchronisé plus tard');
      // Le message reste en local avec isSynced = false
      return tempMessage;
    }
  }
  
  // La méthode markAsRead n'est plus nécessaire car l'API marque automatiquement
  // les messages comme lus lors de l'appel GET /api/chat/rooms/{roomId}/messages
  
  /// Charger le timestamp de dernière sync depuis Hive
  Future<void> _loadSyncTimestamp() async {
    try {
      // Utiliser une box générique pour stocker les métadonnées
      if (Hive.isBoxOpen('chat_metadata')) {
        final metaBox = Hive.box('chat_metadata');
        final timestamp = metaBox.get('last_sync_timestamp');
        if (timestamp != null) {
          _lastSyncTimestamp = DateTime.parse(timestamp);
          debugPrint('📅 Dernier timestamp de sync restauré: $_lastSyncTimestamp');
        }
      }
    } catch (e) {
      debugPrint('⚠️ Impossible de charger le timestamp de sync: $e');
    }
  }
  
  /// Sauvegarder le timestamp de dernière sync dans Hive
  Future<void> _saveSyncTimestamp() async {
    if (_lastSyncTimestamp == null) return;
    
    try {
      // Ouvrir ou créer la box de métadonnées si nécessaire
      Box metaBox;
      if (!Hive.isBoxOpen('chat_metadata')) {
        metaBox = await Hive.openBox('chat_metadata');
      } else {
        metaBox = Hive.box('chat_metadata');
      }
      
      await metaBox.put('last_sync_timestamp', _lastSyncTimestamp!.toIso8601String());
    } catch (e) {
      debugPrint('⚠️ Impossible de sauvegarder le timestamp de sync: $e');
    }
  }
  
  /// Synchronisation périodique avec vérification de connectivité
  void _startSync() {
    _syncTimer?.cancel();
    _syncTimer = Timer.periodic(_syncInterval, (_) async {
      // Vérifier la connectivité avant de synchroniser
      if (!connectivityService.isConnected) {
        debugPrint('📵 Pas de connexion - sync ignorée');
        return;
      }
      
      // Synchroniser les rooms (incrémentale)
      await getRooms();
    });
    
    // Pas de sync immédiate ici car déjà faite dans init()
    debugPrint('⏰ Timer de sync incrémentale démarré (toutes les 30 secondes)');
  }
  
  /// Mettre en pause les synchronisations (app en arrière-plan)
  void pauseSyncs() {
    _syncTimer?.cancel();
    debugPrint('⏸️ Timer de sync arrêté (app en arrière-plan)');
  }
  
  /// Reprendre les synchronisations (app au premier plan)
  void resumeSyncs() {
    if (_syncTimer == null || !_syncTimer!.isActive) {
      _startSync();
      debugPrint('▶️ Timer de sync redémarré (app au premier plan)');
      
      // Faire une sync immédiate au retour au premier plan
      // pour rattraper les messages manqués
      if (connectivityService.isConnected) {
        getRooms().then((_) {
          debugPrint('✅ Sync de rattrapage effectuée');
        }).catchError((e) {
          debugPrint('⚠️ Erreur sync de rattrapage: $e');
        });
      }
    }
  }
  
  /// Nettoyer les ressources
  void dispose() {
    _syncTimer?.cancel();
    _dio.close();
  }
  
  // Getters
  Box<Room> get roomsBox => _roomsBox;
  Box<Message> get messagesBox => _messagesBox;
  int get currentUserId => _currentUserId;
  
  /// Obtenir le rôle de l'utilisateur actuel
  int getUserRole() => _currentUserRole;
  int get currentUserRole => _currentUserRole;
  String get currentUserName => _currentUserName;
  
  /// Obtenir le label du rôle
  String getRoleLabel(int role) {
    switch (role) {
      case 1:
        return 'Membre';
      case 2:
        return 'Admin Amicale';
      case 9:
        return 'Super Admin';
      default:
        return 'Utilisateur';
    }
  }
  
  /// Obtenir la description des permissions
  String getPermissionsDescription() {
    switch (_currentUserRole) {
      case 1:
        return 'Vous pouvez discuter avec les membres de votre amicale';
      case 2:
        return 'Vous pouvez discuter avec les membres et les super admins';
      case 9:
        return 'Vous pouvez envoyer des messages aux administrateurs d\'amicale';
      default:
        return '';
    }
  }
}