/// BLoC de gestion de la messagerie v4
library messaging_bloc;

import 'dart:async';

import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:injectable/injectable.dart';

import '../../../../core/utils/logger.dart';
import '../../../../core/websocket/websocket_service.dart';
import '../../domain/repositories/messaging_repository.dart';
import 'messaging_event.dart';
import 'messaging_state.dart';

@injectable
class MessagingBloc extends Bloc<MessagingEvent, MessagingState> {
  final MessagingRepository _repository;
  final WebSocketService _webSocketService;

  StreamSubscription<WebSocketEvent>? _wsSubscription;
  String? _currentConversationId;

  MessagingBloc({
    required MessagingRepository repository,
    required WebSocketService webSocketService,
  })  : _repository = repository,
        _webSocketService = webSocketService,
        super(MessagingInitial()) {
    on<LoadMesConversations>(_onLoadMesConversations);
    on<OpenConversation>(_onOpenConversation);
    on<DemarrerConversationDirecte>(_onDemarrerConversationDirecte);
    on<DemarrerConversationRole>(_onDemarrerConversationRole);
    on<ArchiverConversation>(_onArchiverConversation);
    on<EnvoyerMessageTexte>(_onEnvoyerMessageTexte);
    on<LoadMessages>(_onLoadMessages);
    on<MarquerLu>(_onMarquerLu);
    on<SupprimerMessage>(_onSupprimerMessage);
    on<NouveauMessageWebSocket>(_onNouveauMessageWebSocket);

    _listenWebSocket();
  }

  void _listenWebSocket() {
    _wsSubscription = _webSocketService.eventStream.listen((event) {
      if (event is ChatMessageEvent && event.conversationId != null) {
        AppLogger.info('MessagingBloc: NOUVEAU_MESSAGE WS pour conv ${event.conversationId}');
        add(NouveauMessageWebSocket(event.conversationId!));
      }
    });
  }

  Future<void> _onLoadMesConversations(
    LoadMesConversations event,
    Emitter<MessagingState> emit,
  ) async {
    emit(MessagingLoading());
    try {
      final conversations = await _repository.getMesConversations();
      emit(MesConversationsLoaded(conversations));
    } catch (e) {
      emit(MessagingError(e.toString().replaceFirst('Exception: ', '')));
    }
  }

  Future<void> _onOpenConversation(
    OpenConversation event,
    Emitter<MessagingState> emit,
  ) async {
    emit(MessagingLoading());
    try {
      _currentConversationId = event.conversationId;
      final conversation = await _repository.getConversation(event.conversationId);
      emit(ConversationOuverte(conversation));
      // Marquer comme lu en arrière-plan (non-bloquant)
      _repository.marquerLu(event.conversationId);
    } catch (e) {
      emit(MessagingError(e.toString().replaceFirst('Exception: ', '')));
    }
  }

  Future<void> _onDemarrerConversationDirecte(
    DemarrerConversationDirecte event,
    Emitter<MessagingState> emit,
  ) async {
    emit(MessagingLoading());
    try {
      final conversation = await _repository.demarrerConversationDirecte(
        destinataireId: event.destinataireId,
        organisationId: event.organisationId,
        premierMessage: event.premierMessage,
      );
      emit(ConversationCreee(conversation));
    } catch (e) {
      emit(MessagingError(e.toString().replaceFirst('Exception: ', '')));
    }
  }

  Future<void> _onDemarrerConversationRole(
    DemarrerConversationRole event,
    Emitter<MessagingState> emit,
  ) async {
    emit(MessagingLoading());
    try {
      final conversation = await _repository.demarrerConversationRole(
        roleCible: event.roleCible,
        organisationId: event.organisationId,
        premierMessage: event.premierMessage,
      );
      emit(ConversationCreee(conversation));
    } catch (e) {
      emit(MessagingError(e.toString().replaceFirst('Exception: ', '')));
    }
  }

  Future<void> _onArchiverConversation(
    ArchiverConversation event,
    Emitter<MessagingState> emit,
  ) async {
    try {
      await _repository.archiverConversation(event.conversationId);
      emit(const MessagingActionOk('archiver'));
      add(const LoadMesConversations());
    } catch (e) {
      emit(MessagingError(e.toString().replaceFirst('Exception: ', '')));
    }
  }

  Future<void> _onEnvoyerMessageTexte(
    EnvoyerMessageTexte event,
    Emitter<MessagingState> emit,
  ) async {
    try {
      final message = await _repository.envoyerMessage(
        event.conversationId,
        typeMessage: 'TEXTE',
        contenu: event.contenu,
        messageParentId: event.messageParentId,
      );
      emit(MessageEnvoye(message: message, conversationId: event.conversationId));
      // Recharger les messages après envoi
      add(LoadMessages(conversationId: event.conversationId));
    } catch (e) {
      emit(MessagingError(e.toString().replaceFirst('Exception: ', '')));
    }
  }

  Future<void> _onLoadMessages(
    LoadMessages event,
    Emitter<MessagingState> emit,
  ) async {
    try {
      final messages = await _repository.getMessages(event.conversationId, page: event.page);
      emit(MessagesLoaded(
        conversationId: event.conversationId,
        messages: messages,
        hasMore: messages.length >= 20,
      ));
    } catch (e) {
      emit(MessagingError(e.toString().replaceFirst('Exception: ', '')));
    }
  }

  Future<void> _onMarquerLu(
    MarquerLu event,
    Emitter<MessagingState> emit,
  ) async {
    await _repository.marquerLu(event.conversationId);
  }

  Future<void> _onSupprimerMessage(
    SupprimerMessage event,
    Emitter<MessagingState> emit,
  ) async {
    try {
      await _repository.supprimerMessage(event.conversationId, event.messageId);
      emit(const MessagingActionOk('supprimer-message'));
      add(LoadMessages(conversationId: event.conversationId));
    } catch (e) {
      emit(MessagingError(e.toString().replaceFirst('Exception: ', '')));
    }
  }

  Future<void> _onNouveauMessageWebSocket(
    NouveauMessageWebSocket event,
    Emitter<MessagingState> emit,
  ) async {
    // Si la conversation est actuellement ouverte, recharger les messages
    if (_currentConversationId == event.conversationId) {
      add(LoadMessages(conversationId: event.conversationId));
    } else {
      // Sinon, rafraîchir la liste pour mettre à jour le badge non-lus
      add(const LoadMesConversations());
    }
  }

  @override
  Future<void> close() {
    _wsSubscription?.cancel();
    _currentConversationId = null;
    return super.close();
  }
}
