import 'package:equatable/equatable.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:meta/meta.dart';

import '../../core/utils/app_logger.dart';
import '../../data/datasources/event_remote_data_source.dart';
import '../../data/models/event_model.dart';

// Déclaration des événements
@immutable
abstract class EventEvent extends Equatable {
  const EventEvent();

  @override
  List<Object?> get props => [];
}

class LoadEvents extends EventEvent {
  const LoadEvents(this.userId);

  final String userId;

  @override
  List<Object?> get props => [userId];
}

class AddEvent extends EventEvent {
  const AddEvent(this.event);

  final EventModel event;

  @override
  List<Object?> get props => [event];
}

class CloseEvent extends EventEvent {
  const CloseEvent(this.eventId);

  final String eventId;

  @override
  List<Object?> get props => [eventId];
}

class ReopenEvent extends EventEvent {
  const ReopenEvent(this.eventId);

  final String eventId;

  @override
  List<Object?> get props => [eventId];
}

// Déclaration des états
@immutable
abstract class EventState extends Equatable {
  const EventState();

  @override
  List<Object?> get props => [];
}

class EventInitial extends EventState {
  const EventInitial();

  @override
  List<Object?> get props => [];
}

class EventLoading extends EventState {
  const EventLoading();

  @override
  List<Object?> get props => [];
}

class EventLoaded extends EventState {
  const EventLoaded(this.events);

  final List<EventModel> events;

  @override
  List<Object?> get props => [events];
}

class EventError extends EventState {
  const EventError(this.message);

  final String message;

  @override
  List<Object?> get props => [message];
}

// Bloc pour la gestion des événements
class EventBloc extends Bloc<EventEvent, EventState> {

  EventBloc({required this.remoteDataSource}) : super(const EventInitial()) {
    on<LoadEvents>(_onLoadEvents);
    on<AddEvent>(_onAddEvent);
    on<CloseEvent>(_onCloseEvent);
    on<ReopenEvent>(_onReopenEvent);
    on<RemoveEvent>(_onRemoveEvent); // Ajout du gestionnaire pour RemoveEvent
  }
  final EventRemoteDataSource remoteDataSource;

  // Gestion du chargement des événements
  Future<void> _onLoadEvents(LoadEvents event, Emitter<EventState> emit) async {
    emit(const EventLoading());
    AppLogger.i('Début du chargement des événements pour l\'utilisateur ${event.userId}', tag: 'EventBloc');

    try {
      final events = await remoteDataSource.getEventsCreatedByUserAndFriends(event.userId);
      AppLogger.i('Événements chargés: ${events.length} éléments récupérés.', tag: 'EventBloc');
      emit(EventLoaded(events));
    } catch (e, stackTrace) {
      AppLogger.e('Erreur lors du chargement des événements', error: e, stackTrace: stackTrace, tag: 'EventBloc');
      emit(EventError('Erreur lors du chargement des événements.'));
    }
  }

  // Gestion de l'ajout d'un nouvel événement
  Future<void> _onAddEvent(AddEvent event, Emitter<EventState> emit) async {
    emit(const EventLoading());
    try {
      await remoteDataSource.createEvent(event.event);
      final events = await remoteDataSource.getAllEvents();
      emit(EventLoaded(events));
    } catch (e) {
      emit(EventError('Erreur lors de l\'ajout de l\'événement.'));
    }
  }

  // Gestion de la fermeture d'un événement
  Future<void> _onCloseEvent(CloseEvent event, Emitter<EventState> emit) async {
    final currentState = state; // Sauvegarder l'état actuel avant d'émettre EventLoading
    emit(const EventLoading()); // Affiche le chargement
    try {
      await remoteDataSource.closeEvent(event.eventId);

      // Mise à jour de l'événement spécifique dans l'état
      if (currentState is EventLoaded) {
        final updatedEvents = List<EventModel>.from((currentState as EventLoaded).events);
        try {
          final updatedEvent = updatedEvents.firstWhere((e) => e.id == event.eventId);
          updatedEvent.status = 'fermé';  // Modifier l'état de l'événement localement

          // Émettre un nouvel état avec l'événement mis à jour
          emit(EventLoaded(updatedEvents));
          AppLogger.i('Événement fermé et mis à jour localement.', tag: 'EventBloc');
        } catch (_) {
          // Événement non trouvé, restaurer l'état précédent
          emit(currentState);
        }
      }
    } catch (e, stackTrace) {
      AppLogger.e('Erreur lors de la fermeture de l\'événement', error: e, stackTrace: stackTrace, tag: 'EventBloc');
      emit(EventError('Erreur lors de la fermeture de l\'événement.'));
    }
  }

  Future<void> _onReopenEvent(ReopenEvent event, Emitter<EventState> emit) async {
    final currentState = state; // Sauvegarder l'état actuel avant d'émettre EventLoading
    emit(const EventLoading()); // Affiche le chargement
    try {
      // Appel au service backend pour réouvrir l'événement
      await remoteDataSource.reopenEvent(event.eventId);

      // Mise à jour de l'événement spécifique dans l'état
      if (currentState is EventLoaded) {
        final updatedEvents = List<EventModel>.from((currentState as EventLoaded).events);
        try {
          final updatedEvent = updatedEvents.firstWhere((e) => e.id == event.eventId);

          // Mise à jour du statut local de l'événement
          updatedEvent.status = 'ouvert';

          // Émettre un nouvel état avec l'événement mis à jour
          emit(EventLoaded(updatedEvents));
          AppLogger.i('Événement réouvert et mis à jour localement.', tag: 'EventBloc');
        } catch (_) {
          // Événement non trouvé, restaurer l'état précédent
          emit(currentState);
        }
      }
    } catch (e, stackTrace) {
      // En cas d'erreur, émettre un état d'erreur
      AppLogger.e('Erreur lors de la réouverture de l\'événement', error: e, stackTrace: stackTrace, tag: 'EventBloc');
      emit(EventError('Erreur lors de la réouverture de l\'événement.'));
    }
  }

  // Gestion de la suppression locale d'un événement
  Future<void> _onRemoveEvent(RemoveEvent event, Emitter<EventState> emit) async {
    final currentState = state; // Sauvegarder l'état actuel
    if (currentState is EventLoaded) {
      // Supprimer l'événement de la liste locale sans recharger tout
      final List<EventModel> updatedEvents = List.from((currentState as EventLoaded).events)
        ..removeWhere((e) => e.id == event.eventId);
      // Toujours émettre le nouvel état, même si la liste est identique
      // (car removeWhere peut ne rien faire si l'événement n'existe pas)
      emit(EventLoaded(updatedEvents));
    }
  }
}

class RemoveEvent extends EventEvent {
  const RemoveEvent(this.eventId);

  final String eventId;

  @override
  List<Object?> get props => [eventId];
}

