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<CardColorVertical> _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}';
  }
}
