import 'package:flutter/material.dart'; import 'package:p_tits_pas/models/dossier_list_item.dart'; import 'package:p_tits_pas/utils/enfant_status_utils.dart'; import 'package:p_tits_pas/models/enfant_admin_model.dart'; import 'package:p_tits_pas/services/auth_service.dart'; import 'package:p_tits_pas/services/user_service.dart'; import 'package:p_tits_pas/utils/staff_deletion_rights.dart'; import 'package:p_tits_pas/widgets/admin/common/admin_child_detail_modal.dart'; import 'package:p_tits_pas/widgets/admin/common/admin_enfant_user_card.dart'; import 'package:p_tits_pas/widgets/admin/common/suppression_confirm_dialog.dart'; import 'package:p_tits_pas/widgets/admin/common/user_list.dart'; /// Onglet liste globale des enfants (doc 28 §6.2, ticket #137). class EnfantManagementWidget extends StatefulWidget { final String searchQuery; final String? statusFilter; const EnfantManagementWidget({ super.key, required this.searchQuery, this.statusFilter, }); @override State createState() => _EnfantManagementWidgetState(); } class _EnfantManagementWidgetState extends State { bool _isLoading = false; String? _error; List _enfants = []; bool _canDelete = false; @override void initState() { super.initState(); _loadRights(); _loadEnfants(); } Future _loadRights() async { final user = await AuthService.getCurrentUser(); if (!mounted) return; setState(() => _canDelete = canDeleteMetier(user?.role)); } Future _loadEnfants() async { setState(() { _isLoading = true; _error = null; }); try { final list = await UserService.getEnfants(); if (!mounted) return; setState(() { _enfants = list; _isLoading = false; }); } catch (e) { if (!mounted) return; setState(() { _error = e.toString(); _isLoading = false; }); } } Future _openEnfant(EnfantAdminModel enfant) async { await showDialog( context: context, builder: (ctx) => AdminChildDetailModal( enfant: enfant, onSaved: _loadEnfants, onDeleted: _loadEnfants, ), ); } Future<({String? numero, String famille, bool isLast, String? amLabel})> _resolveContext( EnfantAdminModel enfant, ) async { String? amLabel; try { final am = await UserService.findAmForEnfant(enfant.id); if (am != null) { final label = formatDossierPersonLabel( nom: am.user.nom, prenom: am.user.prenom, email: am.user.email, ); if (label.isNotEmpty) amLabel = label; } } catch (_) {} final parentId = enfant.parentLinks .map((l) => l.parentId.trim()) .firstWhere((id) => id.isNotEmpty, orElse: () => ''); if (parentId.isEmpty) { return (numero: null, famille: '', isLast: true, amLabel: amLabel); } try { final parent = await UserService.getParent(parentId); final num = (parent.user.numeroDossier ?? '').trim(); final famille = parent.user.fullName.isNotEmpty ? parent.user.fullName : parent.user.email; if (num.isEmpty) { return ( numero: null, famille: famille, isLast: true, amLabel: amLabel, ); } final dossier = await UserService.getDossier(num); if (!dossier.isFamily) { return ( numero: num, famille: famille, isLast: true, amLabel: amLabel, ); } final n = dossier.asFamily.enfants.length; final names = dossier.asFamily.parents .map((p) => formatDossierPersonLabel( nom: p.nom, prenom: p.prenom, email: p.email, )) .where((s) => s.isNotEmpty) .join(' - '); return ( numero: num, famille: names.isNotEmpty ? names : famille, isLast: n <= 1, amLabel: amLabel, ); } catch (_) { return (numero: null, famille: '', isLast: false, amLabel: amLabel); } } Future _confirmDelete(EnfantAdminModel enfant) async { final ctx = await _resolveContext(enfant); if (!mounted) return; bool deleteDossier = false; if (ctx.isLast && (ctx.numero ?? '').isNotEmpty) { final choice = await showDernierEnfantSuppressionDialog( context, enfantName: enfant.fullName, familleLabel: ctx.famille, numeroDossier: ctx.numero!, amLabel: ctx.amLabel, ); if (choice == null || !mounted) return; deleteDossier = choice == DernierEnfantSuppressionChoice.dossierAussi; } else { final confirmed = await showSuppressionConfirmDialog( context, title: 'Supprimer l\'enfant', subtitle: (ctx.numero ?? '').isEmpty ? null : 'Dossier ${ctx.numero}', people: [SuppressionPersonLine.enfant(enfant.fullName)], footnotes: enfantSuppressionFootnotes( numeroDossier: ctx.numero, familleLabel: ctx.famille, amLabel: ctx.amLabel, ), ); if (!confirmed || !mounted) return; } try { final result = await UserService.deleteEnfant( enfant.id, deleteDossier: deleteDossier, ); if (!mounted) return; final msg = (result['message'] ?? 'Enfant supprimé.').toString(); ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(msg))); await _loadEnfants(); } catch (e) { if (!mounted) return; ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text( e is Exception ? e.toString().replaceFirst('Exception: ', '') : 'Erreur suppression', ), ), ); } } @override Widget build(BuildContext context) { final query = widget.searchQuery.toLowerCase(); final filtered = _enfants.where((e) { final matchesName = e.fullName.toLowerCase().contains(query); final matchesStatus = widget.statusFilter == null || normalizeEnfantStatus(e.status) == normalizeEnfantStatus(widget.statusFilter); return matchesName && matchesStatus; }).toList() ..sort((a, b) { // Orphelins (#157) en tête, puis ordre alphabétique. final ao = a.hasNoResponsable ? 0 : 1; final bo = b.hasNoResponsable ? 0 : 1; if (ao != bo) return ao.compareTo(bo); return a.fullName.toLowerCase().compareTo(b.fullName.toLowerCase()); }); return UserList( isLoading: _isLoading, error: _error, isEmpty: filtered.isEmpty, emptyMessage: 'Aucun enfant trouvé.', itemCount: filtered.length, itemBuilder: (context, index) { final enfant = filtered[index]; return AdminEnfantUserCard.fromEnfant( enfant, onCardTap: () => _openEnfant(enfant), actions: [ IconButton( icon: const Icon(Icons.visibility_outlined), tooltip: 'Voir / modifier', onPressed: () => _openEnfant(enfant), ), if (_canDelete) suppressionIconButton( onPressed: () => _confirmDelete(enfant), ), ], ); }, ); } }