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

import '../../../../core/utils/logger.dart';
import '../../data/repositories/network_repository.dart';
import 'network_event.dart';
import 'network_state.dart';

@injectable
class NetworkBloc extends Bloc<NetworkEvent, NetworkState> {
  final NetworkRepository _repository;

  NetworkBloc(this._repository) : super(NetworkInitial()) {
    on<LoadNetworkRequested>(_onLoadNetworkRequested);
    on<SearchNetworkRequested>(_onSearchNetworkRequested);
    on<ToggleFollowRequested>(_onToggleFollowRequested);
  }

  Future<void> _onToggleFollowRequested(ToggleFollowRequested event, Emitter<NetworkState> emit) async {
    if (state is! NetworkLoaded) return;
    final current = state as NetworkLoaded;
    NetworkItem? item;
    for (final i in current.items) {
      if (i.id == event.itemId) {
        item = i;
        break;
      }
    }
    if (item == null) return;
    // Seuls les membres (type Member) sont persistés côté backend ; Organisation reste local.
    if (item.type != 'Member') {
      final items = current.items.map((i) {
        if (i.id == event.itemId) return i.copyWith(isConnected: !i.isConnected);
        return i;
      }).toList();
      emit(NetworkLoaded(items: items, currentQuery: current.currentQuery));
      return;
    }
    try {
      final bool newFollowing = item.isConnected
          ? await _repository.unfollow(event.itemId)
          : await _repository.follow(event.itemId);
      final items = current.items.map((i) {
        if (i.id == event.itemId) return i.copyWith(isConnected: newFollowing);
        return i;
      }).toList();
      emit(NetworkLoaded(items: items, currentQuery: current.currentQuery));
    } catch (e, st) {
      AppLogger.error('NetworkBloc: toggle follow échoué', error: e, stackTrace: st);
      emit(const NetworkError('Impossible de mettre à jour le suivi. Réessayez.'));
    }
  }

  Future<void> _onLoadNetworkRequested(LoadNetworkRequested event, Emitter<NetworkState> emit) async {
    emit(NetworkLoading());
    try {
      final followedIds = await _repository.getFollowedIds();
      final items = await _repository.search('', followedIds: followedIds.toSet());
      emit(NetworkLoaded(items: items, currentQuery: ''));
    } catch (e, st) {
      AppLogger.error('NetworkBloc: chargement réseau échoué', error: e, stackTrace: st);
      emit(NetworkError('Erreur chargement réseau : $e'));
    }
  }

  Future<void> _onSearchNetworkRequested(SearchNetworkRequested event, Emitter<NetworkState> emit) async {
    emit(NetworkLoading());
    try {
      if (event.query.trim().isEmpty) {
        final followedIds = await _repository.getFollowedIds();
        final items = await _repository.search('', followedIds: followedIds.toSet());
        emit(NetworkLoaded(items: items, currentQuery: ''));
        return;
      }
      final followedIds = await _repository.getFollowedIds();
      final items = await _repository.search(event.query, followedIds: followedIds.toSet());
      emit(NetworkLoaded(items: items, currentQuery: event.query));
    } catch (e, st) {
      AppLogger.error('NetworkBloc: recherche réseau échouée', error: e, stackTrace: st);
      emit(NetworkError('Erreur de recherche : $e'));
    }
  }
}
