import 'dart:async';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../repositories/expense_repository.dart';
import '../../services/expense_service.dart';
import '../../services/error_service.dart';
import 'expense_event.dart';
import 'expense_state.dart';


class ExpenseBloc extends Bloc<ExpenseEvent, ExpenseState> {
  final ExpenseRepository _expenseRepository;
  final ExpenseService _expenseService;
  final ErrorService _errorService;
  StreamSubscription? _expensesSubscription;

  ExpenseBloc({
    required ExpenseRepository expenseRepository,
    ExpenseService? expenseService,
    ErrorService? errorService,
  }) : _expenseRepository = expenseRepository,
       _expenseService = expenseService ?? ExpenseService(expenseRepository: expenseRepository),
       _errorService = errorService ?? ErrorService(),
       super(ExpenseInitial()) {
    
    on<LoadExpensesByGroup>(_onLoadExpensesByGroup);
    on<ExpensesUpdated>(_onExpensesUpdated);
    on<CreateExpense>(_onCreateExpense);
    on<UpdateExpense>(_onUpdateExpense);
    on<DeleteExpense>(_onDeleteExpense);
    on<MarkSplitAsPaid>(_onMarkSplitAsPaid);
    on<ArchiveExpense>(_onArchiveExpense);
  }

  Future<void> _onLoadExpensesByGroup(
    LoadExpensesByGroup event,
    Emitter<ExpenseState> emit,
  ) async {
    try {
      emit(ExpenseLoading());
      
      await _expensesSubscription?.cancel();
      
      _expensesSubscription = _expenseRepository
          .getExpensesStream(event.groupId)
          .listen(
            (expenses) => add(ExpensesUpdated(expenses)),
            onError: (error) => add(ExpensesUpdated([], error: error.toString())),
          );
    } catch (e) {
      _errorService.logError('ExpenseBloc', 'Erreur chargement expenses: $e');
      emit(ExpenseError(e.toString()));
    }
  }

  Future<void> _onExpensesUpdated(
    ExpensesUpdated event,
    Emitter<ExpenseState> emit,
  ) async {
    if (event.error != null) {
      emit(ExpenseError(event.error!));
    } else {
      emit(ExpensesLoaded(expenses: event.expenses));
    }
  }

  Future<void> _onCreateExpense(
    CreateExpense event,
    Emitter<ExpenseState> emit,
  ) async {
    try {
      await _expenseService.createExpenseWithValidation(event.expense, event.receiptImage);
      emit(const ExpenseOperationSuccess('Dépense créée avec succès'));
    } catch (e) {
      _errorService.logError('ExpenseBloc', 'Erreur création expense: $e');
      emit(ExpenseError(e.toString()));
    }
  }

  Future<void> _onUpdateExpense(
    UpdateExpense event,
    Emitter<ExpenseState> emit,
  ) async {
    try {
      await _expenseService.updateExpenseWithValidation(event.expense, event.newReceiptImage);
      emit(const ExpenseOperationSuccess('Dépense modifiée avec succès'));
    } catch (e) {
      _errorService.logError('ExpenseBloc', 'Erreur mise à jour expense: $e');
      emit(ExpenseError(e.toString()));
    }
  }

  Future<void> _onDeleteExpense(
    DeleteExpense event,
    Emitter<ExpenseState> emit,
  ) async {
    try {
      await _expenseRepository.deleteExpense(event.expenseId);
      emit(const ExpenseOperationSuccess('Dépense supprimée avec succès'));
    } catch (e) {
      _errorService.logError('ExpenseBloc', 'Erreur suppression expense: $e');
      emit(ExpenseError(e.toString()));
    }
  }

  Future<void> _onMarkSplitAsPaid(
    MarkSplitAsPaid event,
    Emitter<ExpenseState> emit,
  ) async {
    try {
      await _expenseRepository.markSplitAsPaid(event.expenseId, event.userId);
      emit(const ExpenseOperationSuccess('Paiement marqué comme effectué'));
    } catch (e) {
      _errorService.logError('ExpenseBloc', 'Erreur mark split paid: $e');
      emit(ExpenseError(e.toString()));
    }
  }

  Future<void> _onArchiveExpense(
    ArchiveExpense event,
    Emitter<ExpenseState> emit,
  ) async {
    try {
      await _expenseRepository.archiveExpense(event.expenseId);
      emit(const ExpenseOperationSuccess('Dépense archivée avec succès'));
    } catch (e) {
      _errorService.logError('ExpenseBloc', 'Erreur archivage expense: $e');
      emit(ExpenseError(e.toString()));
    }
  }

  @override
  Future<void> close() {
    _expensesSubscription?.cancel();
    return super.close();
  }
}