import 'dart:io'; import '../data/models/expense.dart'; import '../data/models/balance.dart'; import '../repositories/count_repository.dart'; import 'error_service.dart'; class CountService { final CountRepository _countRepository; final ErrorService _errorService; CountService({ CountRepository? countRepository, ErrorService? errorService, }) : _countRepository = countRepository ?? CountRepository(), _errorService = errorService ?? ErrorService(); // Créer une dépense Future createExpense(Expense expense, {File? receiptImage}) async { try { final expenseId = await _countRepository.createExpense(expense); if (receiptImage != null) { final receiptUrl = await _countRepository.uploadReceipt( expense.groupId, expenseId, receiptImage, ); final updatedExpense = expense.copyWith( id: expenseId, receiptUrl: receiptUrl, ); await _countRepository.updateExpense(expense.groupId, updatedExpense); } return expenseId; } catch (e) { _errorService.logError('count_service.dart', 'Erreur lors de la création de la dépense: $e'); rethrow; } } // Mettre à jour une dépense Future updateExpense(Expense expense, {File? newReceiptImage}) async { try { if (newReceiptImage != null) { // Supprimer l'ancien reçu si existe if (expense.receiptUrl != null) { await _countRepository.deleteReceipt(expense.receiptUrl!); } // Uploader le nouveau final receiptUrl = await _countRepository.uploadReceipt( expense.groupId, expense.id, newReceiptImage, ); expense = expense.copyWith(receiptUrl: receiptUrl); } await _countRepository.updateExpense(expense.groupId, expense); } catch (e) { _errorService.logError('count_service.dart', 'Erreur lors de la mise à jour de la dépense: $e'); rethrow; } } // Supprimer une dépense Future deleteExpense(String groupId, String expenseId) async { try { await _countRepository.deleteExpense(groupId, expenseId); } catch (e) { _errorService.logError('count_service.dart', 'Erreur lors de la suppression de la dépense: $e'); rethrow; } } // Archiver une dépense Future archiveExpense(String groupId, String expenseId) async { try { await _countRepository.archiveExpense(groupId, expenseId); } catch (e) { _errorService.logError('count_service.dart', 'Erreur lors de l\'archivage de la dépense: $e'); rethrow; } } // Marquer une split comme payée Future markSplitAsPaid(String groupId, String expenseId, String userId) async { try { await _countRepository.markSplitAsPaid( groupId: groupId, expenseId: expenseId, userId: userId, ); } catch (e) { _errorService.logError('count_service.dart', 'Erreur lors du marquage du paiement: $e'); rethrow; } } // Stream des dépenses Stream> getExpensesStream(String groupId, {bool includeArchived = false}) { try { return _countRepository.getExpensesStream(groupId, includeArchived: includeArchived); } catch (e) { _errorService.logError('count_service.dart', 'Erreur lors de la récupération des dépenses: $e'); rethrow; } } // Calculer les balances List calculateBalances(List expenses, List memberIds, Map memberNames) { final balances = {}; // Initialiser les balances for (final memberId in memberIds) { balances[memberId] = Balance( userId: memberId, userName: memberNames[memberId] ?? 'Unknown', totalPaid: 0, totalOwed: 0, ); } // Calculer pour chaque dépense for (final expense in expenses) { if (expense.isArchived) continue; // Ajouter au total payé final payer = balances[expense.paidById]; if (payer != null) { balances[expense.paidById] = Balance( userId: payer.userId, userName: payer.userName, totalPaid: payer.totalPaid + expense.amountInEur, totalOwed: payer.totalOwed, ); } // Ajouter au total dû pour chaque split for (final split in expense.splits) { if (!split.isPaid) { final debtor = balances[split.userId]; if (debtor != null) { balances[split.userId] = Balance( userId: debtor.userId, userName: debtor.userName, totalPaid: debtor.totalPaid, totalOwed: debtor.totalOwed + split.amount, ); } } } } return balances.values.toList(); } // Calculer les remboursements optimisés List calculateOptimizedSettlements(List balances) { final settlements = []; // Créer des copies mutables final creditors = balances.where((b) => b.shouldReceive).map((b) => {'userId': b.userId, 'userName': b.userName, 'amount': b.balance} ).toList(); final debtors = balances.where((b) => b.shouldPay).map((b) => {'userId': b.userId, 'userName': b.userName, 'amount': b.absoluteBalance} ).toList(); // Trier par montant décroissant creditors.sort((a, b) => (b['amount'] as double).compareTo(a['amount'] as double)); debtors.sort((a, b) => (b['amount'] as double).compareTo(a['amount'] as double)); int i = 0, j = 0; while (i < creditors.length && j < debtors.length) { final creditor = creditors[i]; final debtor = debtors[j]; final creditorAmount = creditor['amount'] as double; final debtorAmount = debtor['amount'] as double; final settleAmount = creditorAmount < debtorAmount ? creditorAmount : debtorAmount; settlements.add(Settlement( fromUserId: debtor['userId'] as String, fromUserName: debtor['userName'] as String, toUserId: creditor['userId'] as String, toUserName: creditor['userName'] as String, amount: settleAmount, )); creditor['amount'] = creditorAmount - settleAmount; debtor['amount'] = debtorAmount - settleAmount; if (creditor['amount'] == 0) i++; if (debtor['amount'] == 0) j++; } return settlements; } // Convertir un montant en EUR Future convertToEur(double amount, ExpenseCurrency currency) async { try { return await _countRepository.convertToEur(amount, currency); } catch (e) { _errorService.logError('count_service.dart', 'Erreur lors de la conversion: $e'); rethrow; } } // Obtenir les taux de change Future> getExchangeRates() async { try { return await _countRepository.getExchangeRates(); } catch (e) { _errorService.logError('count_service.dart', 'Erreur lors de la récupération des taux: $e'); rethrow; } } }