import 'package:p_tits_pas/models/am_registration_data.dart'; import 'package:p_tits_pas/models/card_assets.dart'; import 'package:p_tits_pas/models/dossier_unifie.dart'; import 'package:p_tits_pas/models/reprise_dossier.dart'; import 'package:p_tits_pas/models/user_registration_data.dart'; import 'package:p_tits_pas/services/api/api_config.dart'; /// Mapping GET reprise-dossier → modèles wizard. Ticket #112. class RepriseMapper { RepriseMapper._(); static const List _childCardColors = [ CardColorVertical.lavender, CardColorVertical.pink, CardColorVertical.peach, CardColorVertical.lime, CardColorVertical.red, CardColorVertical.green, CardColorVertical.blue, ]; static ParentData parentFromDossier(ParentDossier p) { return ParentData( firstName: p.prenom ?? '', lastName: p.nom ?? '', phone: p.telephone ?? '', email: p.email, address: p.adresse ?? '', postalCode: p.codePostal ?? '', city: p.ville ?? '', password: '', ); } static ChildData childFromEnfant(EnfantDossier e, int index) { final isUnborn = e.status == 'a_naitre'; final dob = isUnborn ? isoToDdMmYyyy(e.dueDate) : isoToDdMmYyyy(e.birthDate); final photo = e.photoUrl?.trim(); return ChildData( firstName: e.firstName ?? '', lastName: e.lastName ?? '', dob: dob, genre: e.gender ?? '', photoConsent: e.consentPhoto, multipleBirth: e.estMultiple, isUnbornChild: isUnborn, cardColor: _childCardColors[index % _childCardColors.length], repriseChildId: e.id, existingPhotoUrl: photo != null && photo.isNotEmpty ? ApiConfig.absoluteMediaUrl(photo) : null, ); } static void applyParentDossier(UserRegistrationData data, RepriseDossier dossier) { ParentDossier? titulaire; ParentDossier? coParent; if (dossier.parents.isNotEmpty) { for (final p in dossier.parents) { if (p.id == dossier.id) { titulaire = p; } else { coParent = p; } } titulaire ??= dossier.parents.first; if (coParent == null && dossier.parents.length > 1) { coParent = dossier.parents.firstWhere( (p) => p.id != titulaire!.id, orElse: () => dossier.parents.last, ); } } final p1 = titulaire != null ? parentFromDossier(titulaire) : ParentData( firstName: dossier.prenom ?? '', lastName: dossier.nom ?? '', phone: dossier.telephone ?? '', email: dossier.email, address: dossier.adresse ?? '', postalCode: dossier.codePostal ?? '', city: dossier.ville ?? '', password: '', ); final children = dossier.enfants .asMap() .entries .map((e) => childFromEnfant(e.value, e.key)) .toList(); data.resetForReprise( parent1Data: p1, parent2Data: coParent != null ? parentFromDossier(coParent) : null, childrenData: children, motivation: dossier.texteMotivation ?? '', ); } static DateTime? parseIsoDate(String? raw) { if (raw == null || raw.trim().isEmpty) return null; final s = raw.trim(); final iso = RegExp(r'^(\d{4})-(\d{2})-(\d{2})'); final isoMatch = iso.firstMatch(s); if (isoMatch != null) { return DateTime( int.parse(isoMatch.group(1)!), int.parse(isoMatch.group(2)!), int.parse(isoMatch.group(3)!), ); } try { return DateTime.parse(s); } catch (_) { final parts = s.split('/'); if (parts.length == 3) { final day = int.tryParse(parts[0]); final month = int.tryParse(parts[1]); final year = int.tryParse(parts[2]); if (day != null && month != null && year != null) { return DateTime(year, month, day); } } return null; } } static String? optionalDateString(dynamic value) { if (value == null) return null; if (value is String) { final s = value.trim(); return s.isEmpty || s == 'null' ? null : s; } if (value is DateTime) { return '${value.year.toString().padLeft(4, '0')}-' '${value.month.toString().padLeft(2, '0')}-' '${value.day.toString().padLeft(2, '0')}'; } if (value is num) { final ms = value.abs() > 9999999999 ? value.toInt() : value.toInt() * 1000; final dt = DateTime.fromMillisecondsSinceEpoch(ms, isUtc: true); return '${dt.year.toString().padLeft(4, '0')}-' '${dt.month.toString().padLeft(2, '0')}-' '${dt.day.toString().padLeft(2, '0')}'; } if (value is Map) { final y = value['year']; final m = value['month'] ?? value['monthValue']; final d = value['day'] ?? value['dayOfMonth']; if (y is num && m is num && d is num) { return '${y.toInt().toString().padLeft(4, '0')}-' '${m.toInt().toString().padLeft(2, '0')}-' '${d.toInt().toString().padLeft(2, '0')}'; } } final s = value.toString().trim(); return s.isEmpty || s == 'null' ? null : s; } static int? optionalInt(dynamic value) { if (value == null) return null; if (value is int) return value; if (value is num) return value.toInt(); if (value is String) { final s = value.trim(); if (s.isEmpty) return null; return int.tryParse(s); } return null; } static bool optionalBool(dynamic value) { if (value == true) return true; if (value is String && value.toLowerCase() == 'true') return true; return false; } static void applyAmDossier(AmRegistrationData data, RepriseDossier dossier) { final rawPhoto = dossier.photoUrl?.trim(); final hasPhoto = rawPhoto != null && rawPhoto.isNotEmpty; final displayPhoto = hasPhoto ? ApiConfig.absoluteMediaUrl(rawPhoto) : null; data.resetForReprise( firstName: dossier.prenom ?? '', lastName: dossier.nom ?? '', phone: dossier.telephone ?? '', email: dossier.email, streetAddress: dossier.adresse ?? '', postalCode: dossier.codePostal ?? '', city: dossier.ville ?? '', existingPhotoUrl: displayPhoto, consentementPhoto: dossier.consentementPhoto, dateOfBirth: parseIsoDate(dossier.dateNaissance), birthCity: dossier.lieuNaissanceVille ?? '', birthCountry: dossier.lieuNaissancePays ?? '', nir: dossier.nir ?? '', agrementNumber: dossier.numeroAgrement ?? '', agreementDate: parseIsoDate(dossier.dateAgrement), capacity: dossier.nbMaxEnfants, placesAvailable: dossier.placeDisponible, presentationText: dossier.biographie ?? '', ); } static String isoToDdMmYyyy(String? iso) { final dt = parseIsoDate(iso); if (dt == null) return ''; return '${dt.day.toString().padLeft(2, '0')}/' '${dt.month.toString().padLeft(2, '0')}/' '${dt.year}'; } }