import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:image_picker/image_picker.dart';
import 'package:p_tits_pas/models/assistante_maternelle_model.dart';
import 'package:p_tits_pas/models/enfant_admin_model.dart';
import 'package:p_tits_pas/services/api/api_config.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/date_display_utils.dart';
import 'package:p_tits_pas/utils/enfant_status_utils.dart';
import 'package:p_tits_pas/utils/name_format_utils.dart';
import 'package:p_tits_pas/widgets/admin/common/admin_am_edit_modal.dart';
import 'package:p_tits_pas/widgets/admin/common/admin_am_photo_frame.dart';
import 'package:p_tits_pas/widgets/admin/common/admin_parent_edit_modal.dart';
import 'package:p_tits_pas/widgets/admin/common/admin_select_am_modal.dart';
import 'package:p_tits_pas/widgets/admin/common/admin_select_famille_modal.dart';
import 'package:p_tits_pas/widgets/admin/common/validation_detail_section.dart';
import 'package:p_tits_pas/widgets/admin/validation_modal_theme.dart';
import 'package:p_tits_pas/widgets/common/auth_network_image.dart';

/// Fiche enfant consultation / édition (#138) ou création (#132).
class AdminChildDetailModal extends StatefulWidget {
  final EnfantAdminModel? enfant;
  final VoidCallback? onSaved;
  final VoidCallback? onDeleted;
  final bool isCreating;

  const AdminChildDetailModal({
    super.key,
    required EnfantAdminModel this.enfant,
    this.onSaved,
    this.onDeleted,
  }) : isCreating = false;

  /// Création depuis l'onglet Enfants (#132).
  const AdminChildDetailModal.create({
    super.key,
    this.onSaved,
  })  : enfant = null,
        onDeleted = null,
        isCreating = true;

  @override
  State<AdminChildDetailModal> createState() => _AdminChildDetailModalState();
}

class _AdminChildDetailModalState extends State<AdminChildDetailModal> {
  late final TextEditingController _prenomCtrl;
  late final TextEditingController _nomCtrl;
  late final TextEditingController _birthCtrl;
  late final TextEditingController _dueCtrl;
  late String _status;
  late String? _gender;
  late bool _consentPhoto;
  late bool _isMultiple;
  bool _dirty = false;
  bool _saving = false;
  bool _deleting = false;
  bool _loadingAm = true;
  String? _currentUserRole;
  AssistanteMaternelleModel? _linkedAm;
  /// AM rattachée au chargement (pour sync différé au Sauvegarder).
  String? _baselineAmUserId;

  /// Famille choisie en mode création (#132).
  AdminFamilleFoyer? _selectedFamily;

  /// Liens parents locaux (édition) — mis à jour après rattachement foyer (#157).
  List<EnfantParentLink>? _localParentLinks;

  /// Photo locale (création) — upload multipart `photo`.
  Uint8List? _photoBytes;
  String? _photoFilename;

  static const double _modalWidth = 930;
  static const double _mainRowHeight = 380;
  static const double _placementHeight = 96;
  static const double _fieldHeight = 44;
  static const double _photoProGap = 24;
  static const double _proColumnMinWidth = 260;
  static const double _photoColumnMinWidth = 160;
  static const double _photoColumnMaxWidth = 280;
  static const List<int> _fieldsRowLayout = [2, 2, 1];

  bool get _isUnborn => _status == 'a_naitre';
  bool get _isScolarise => _status == 'scolarise';
  bool get _isSansGarde => _status == 'sans_garde';
  bool get _showsAmPlacement => !_isScolarise;

  List<String> get _availableGenders =>
      _isUnborn ? const ['H', 'F', 'Autre'] : const ['H', 'F'];

  TextEditingController get _activeDateCtrl =>
      _isUnborn ? _dueCtrl : _birthCtrl;

  String get _dateFieldLabel =>
      _isUnborn ? 'Date prévisionnelle' : 'Date de naissance';

  bool get _canDelete =>
      !widget.isCreating &&
      (_currentUserRole ?? '').toLowerCase() == 'super_admin';

  bool get _busy => _saving || _deleting;

  /// Création : tous les champs sauf photo / consentement ; édition : au moins une modif.
  bool get _canSubmit {
    if (_busy) return false;
    if (widget.isCreating) return _isCreateFormComplete;
    return _dirty;
  }

  bool get _isCreateFormComplete {
    if (_selectedFamily == null) return false;
    if (formatPersonNameCase(_prenomCtrl.text).isEmpty) return false;
    if (formatPersonNameCase(_nomCtrl.text).isEmpty) return false;
    if (_dateToIso(_activeDateCtrl.text) == null) return false;
    if (_gender == null || !_availableGenders.contains(_gender)) return false;
    return true;
  }

  @override
  void initState() {
    super.initState();
    final e = widget.enfant;
    _prenomCtrl = TextEditingController(text: e?.firstName ?? '');
    _nomCtrl = TextEditingController(text: e?.lastName ?? '');
    _birthCtrl = TextEditingController(
      text: formatIsoDateFrInput(e?.birthDate, ifEmpty: ''),
    );
    _dueCtrl = TextEditingController(
      text: formatIsoDateFrInput(e?.dueDate, ifEmpty: ''),
    );
    _status = normalizeEnfantStatus(e?.status);
    if (!enfantStatusValues.contains(_status)) {
      _status = 'sans_garde';
    }
    if (widget.isCreating) {
      _gender = null;
    } else {
      _gender = _normalizeGender(e?.gender, allowUnknown: _isUnborn);
    }
    _consentPhoto = e?.consentPhoto ?? false;
    _isMultiple = e?.isMultiple ?? false;
    for (final c in [_prenomCtrl, _nomCtrl]) {
      c.addListener(_onNameChanged);
    }
    for (final c in [_birthCtrl, _dueCtrl]) {
      c.addListener(_onDateChanged);
    }
    _loadCurrentUserRole();
    if (widget.isCreating) {
      _loadingAm = false;
      _dirty = true;
    } else {
      _prenomCtrl.addListener(_markDirty);
      _nomCtrl.addListener(_markDirty);
      _loadLinkedAm();
    }
  }

  void _onNameChanged() => setState(() {});

  void _onDateChanged() {
    setState(() => _dirty = true);
  }

  /// Date prévisionnelle strictement avant aujourd’hui (statut à naître).
  bool get _dueDateInPast {
    if (!_isUnborn) return false;
    final iso = _dateToIso(_dueCtrl.text);
    if (iso == null) return false;
    try {
      final due = DateTime.parse(iso);
      final now = DateTime.now();
      final dueDay = DateTime(due.year, due.month, due.day);
      final today = DateTime(now.year, now.month, now.day);
      return dueDay.isBefore(today);
    } catch (_) {
      return false;
    }
  }

  Future<void> _loadLinkedAm() async {
    if (widget.isCreating) {
      setState(() => _loadingAm = false);
      return;
    }
    final enfantId = widget.enfant?.id;
    if (enfantId == null || enfantId.isEmpty) {
      setState(() => _loadingAm = false);
      return;
    }
    setState(() => _loadingAm = true);
    try {
      final am = await UserService.findAmForEnfant(enfantId);
      if (!mounted) return;
      setState(() {
        _linkedAm = am;
        _baselineAmUserId = am?.user.id;
        _loadingAm = false;
      });
    } catch (_) {
      if (!mounted) return;
      setState(() {
        _baselineAmUserId = null;
        _loadingAm = false;
      });
    }
  }

  Future<void> _loadCurrentUserRole() async {
    final cached = await AuthService.getCurrentUser();
    if (!mounted) return;
    if (cached != null) {
      setState(() => _currentUserRole = cached.role);
      return;
    }
    final refreshed = await AuthService.refreshCurrentUser();
    if (!mounted || refreshed == null) return;
    setState(() => _currentUserRole = refreshed.role);
  }

  @override
  void dispose() {
    for (final c in [_prenomCtrl, _nomCtrl, _birthCtrl, _dueCtrl]) {
      c.dispose();
    }
    super.dispose();
  }

  static String _normalizeGender(String? raw, {required bool allowUnknown}) {
    final g = (raw ?? '').trim();
    if (g == 'M') return 'H';
    if (g == 'F' || g == 'H') return g;
    if (g == 'Autre' && allowUnknown) return 'Autre';
    return 'H';
  }

  void _coerceGenderForStatus() {
    if (_gender != null && !_availableGenders.contains(_gender)) {
      _gender = null;
    }
  }

  void _markDirty() {
    if (!_dirty) setState(() => _dirty = true);
  }

  String? _dateToIso(String text) => parseFrDateToIso(text);

  String _headerTitle() {
    if (widget.isCreating) {
      final fn = _prenomCtrl.text.trim();
      final ln = _nomCtrl.text.trim();
      if (fn.isEmpty && ln.isEmpty) return 'Nouvel enfant';
      return '$fn $ln'.trim();
    }
    final fn = _prenomCtrl.text.trim();
    final ln = _nomCtrl.text.trim();
    if (fn.isEmpty && ln.isEmpty) {
      final fallback = widget.enfant?.fullName.trim() ?? '';
      return fallback.isNotEmpty ? fallback : 'Enfant';
    }
    return '$fn $ln'.trim();
  }

  List<EnfantParentLink> get _parentLinks =>
      (_localParentLinks ??
              widget.enfant?.parentLinks ??
              const <EnfantParentLink>[])
          .where((l) => l.parentId.trim().isNotEmpty)
          .toList();

  bool get _isOrphan => !widget.isCreating && _parentLinks.isEmpty;

  Future<void> _openParent(EnfantParentLink link) async {
    if (_busy) return;
    final id = link.parentId.trim();
    if (id.isEmpty) return;

    try {
      final parent = await UserService.getParent(id);
      if (!mounted) return;
      await showDialog<void>(
        context: context,
        builder: (ctx) => AdminParentEditModal(
          parent: parent,
          onSaved: () => widget.onSaved?.call(),
        ),
      );
    } catch (e) {
      if (!mounted) return;
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text(e.toString().replaceFirst('Exception: ', ''))),
      );
    }
  }

  Widget? _parentsSubtitle() {
    if (widget.isCreating) {
      final family = _selectedFamily;
      if (family == null) return null;
      return Text(
        family.parentNames.isNotEmpty
            ? 'Famille : ${family.parentNames.join(', ')}'
            : family.displayTitle,
        style: const TextStyle(fontSize: 13, color: Colors.black54),
      );
    }

    final links = _parentLinks;
    if (links.isEmpty) return null;

    return Wrap(
      crossAxisAlignment: WrapCrossAlignment.center,
      children: [
        const Text(
          'Responsables : ',
          style: TextStyle(fontSize: 13, color: Colors.black54),
        ),
        for (var i = 0; i < links.length; i++) ...[
          if (i > 0)
            const Text(
              ', ',
              style: TextStyle(fontSize: 13, color: Colors.black54),
            ),
          _parentNameLink(links[i]),
        ],
      ],
    );
  }

  Widget _parentNameLink(EnfantParentLink link) {
    final name = (link.parentName ?? '').trim();
    final label = name.isNotEmpty ? name : 'Parent rattaché';
    return InkWell(
      onTap: _busy ? null : () => _openParent(link),
      borderRadius: BorderRadius.circular(4),
      child: Padding(
        padding: const EdgeInsets.symmetric(horizontal: 2, vertical: 2),
        child: Text(
          label,
          style: TextStyle(
            fontSize: 13,
            fontWeight: FontWeight.w600,
            color: ValidationModalTheme.primaryActionBackground,
            decoration: TextDecoration.underline,
            decorationColor: ValidationModalTheme.primaryActionBackground
                .withValues(alpha: 0.5),
          ),
        ),
      ),
    );
  }

  Future<void> _save() async {
    if (!_dirty) return;

    if (widget.isCreating) {
      await _saveCreate();
      return;
    }

    final enfantId = widget.enfant?.id;
    if (enfantId == null || enfantId.isEmpty) return;

    setState(() => _saving = true);
    try {
      await _syncAmPlacement();

      await UserService.updateEnfant(
        enfantId: enfantId,
        body: {
          'first_name': formatPersonNameCase(_prenomCtrl.text),
          'last_name': formatPersonNameCase(_nomCtrl.text),
          'status': _status,
          'gender': _gender,
          if (_isUnborn)
            if (_dateToIso(_dueCtrl.text) != null)
              'due_date': _dateToIso(_dueCtrl.text)
          else if (_dateToIso(_birthCtrl.text) != null)
            'birth_date': _dateToIso(_birthCtrl.text),
          'consent_photo': _consentPhoto,
          'is_multiple': _isMultiple,
        },
      );
      if (!mounted) return;
      setState(() {
        _dirty = false;
        _saving = false;
        _baselineAmUserId = _linkedAm?.user.id;
      });
      widget.onSaved?.call();
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(content: Text('Fiche enfant enregistrée')),
      );
    } catch (e) {
      if (!mounted) return;
      setState(() => _saving = false);
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text(e.toString().replaceFirst('Exception: ', ''))),
      );
    }
  }

  Future<void> _saveCreate() async {
    final family = _selectedFamily;
    if (family == null) {
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(
          content: Text('Choisissez une famille / un dossier avant d\'enregistrer'),
        ),
      );
      return;
    }
    final prenom = formatPersonNameCase(_prenomCtrl.text);
    final nom = formatPersonNameCase(_nomCtrl.text);
    if (prenom.isEmpty || nom.isEmpty) {
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(content: Text('Prénom et nom sont obligatoires')),
      );
      return;
    }
    if (!_isUnborn && _dateToIso(_birthCtrl.text) == null) {
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(content: Text('Date de naissance invalide ou manquante')),
      );
      return;
    }
    final hasPhoto = _photoBytes != null && _photoBytes!.isNotEmpty;
    if (hasPhoto && !_consentPhoto) {
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(
          content: Text(
            'Activez le consentement photo pour enregistrer une photo',
          ),
        ),
      );
      return;
    }

    setState(() => _saving = true);
    try {
      await UserService.createEnfant(
        parentUserId: family.pivotParentUserId,
        photoBytes: hasPhoto ? _photoBytes : null,
        photoFilename: _photoFilename,
        body: {
          'first_name': prenom,
          'last_name': nom,
          'status': _status,
          'gender': _gender,
          if (_isUnborn) ...{
            if (_dateToIso(_dueCtrl.text) != null)
              'due_date': _dateToIso(_dueCtrl.text),
          } else ...{
            if (_dateToIso(_birthCtrl.text) != null)
              'birth_date': _dateToIso(_birthCtrl.text),
          },
          'consent_photo': _consentPhoto,
          'is_multiple': _isMultiple,
        },
      );
      if (!mounted) return;
      setState(() {
        _dirty = false;
        _saving = false;
      });
      widget.onSaved?.call();
      Navigator.of(context).pop();
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(content: Text('Enfant créé')),
      );
    } catch (e) {
      if (!mounted) return;
      setState(() => _saving = false);
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text(e.toString().replaceFirst('Exception: ', ''))),
      );
    }
  }

  /// Applique rattachement / détachement AM (différé jusqu'au Sauvegarder).
  Future<void> _syncAmPlacement() async {
    final enfantId = widget.enfant?.id;
    if (enfantId == null || enfantId.isEmpty) return;

    final baselineId = _baselineAmUserId;
    final currentId = _linkedAm?.user.id;

    if (baselineId != null && baselineId != currentId) {
      await UserService.detachEnfantFromAm(
        amUserId: baselineId,
        enfantId: enfantId,
      );
    }
    if (currentId != null && currentId != baselineId) {
      await UserService.attachEnfantToAm(
        amUserId: currentId,
        enfantId: enfantId,
      );
    }
  }

  Future<void> _delete() async {
    if (!_canDelete || _deleting) return;

    final name = _headerTitle();
    final confirmed = await showDialog<bool>(
      context: context,
      builder: (ctx) => AlertDialog(
        title: const Text('Supprimer l\'enfant'),
        content: Text(
          'Supprimer définitivement la fiche de $name ?\n'
          'Cette action est irréversible.',
        ),
        actions: [
          TextButton(
            onPressed: () => Navigator.pop(ctx, false),
            child: const Text('Annuler'),
          ),
          ElevatedButton(
            onPressed: () => Navigator.pop(ctx, true),
            style: ElevatedButton.styleFrom(
              backgroundColor: Colors.red.shade700,
              foregroundColor: Colors.white,
            ),
            child: const Text('Supprimer'),
          ),
        ],
      ),
    );
    if (confirmed != true || !mounted) return;

    setState(() => _deleting = true);
    try {
      final id = widget.enfant?.id;
      if (id == null || id.isEmpty) return;
      await UserService.deleteEnfant(id);
      if (!mounted) return;
      widget.onDeleted?.call();
      widget.onSaved?.call();
      Navigator.of(context).pop();
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(content: Text('Fiche enfant supprimée')),
      );
    } catch (e) {
      if (!mounted) return;
      setState(() => _deleting = false);
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text(e.toString().replaceFirst('Exception: ', ''))),
      );
    }
  }

  Future<void> _openLinkedAm() async {
    final am = _linkedAm;
    if (am == null) return;
    await showDialog<void>(
      context: context,
      builder: (ctx) => AdminAmEditModal(
        assistante: am,
        onSaved: () async {
          await _reloadPlacementFromServer();
          widget.onSaved?.call();
        },
      ),
    );
  }

  /// Recharge AM + statut après une modale externe (ex. fiche AM).
  Future<void> _reloadPlacementFromServer() async {
    final id = widget.enfant?.id;
    if (id == null || id.isEmpty) return;
    try {
      final results = await Future.wait([
        UserService.findAmForEnfant(id),
        UserService.getEnfant(id),
      ]);
      if (!mounted) return;
      final am = results[0] as AssistanteMaternelleModel?;
      final enfant = results[1] as EnfantAdminModel;
      setState(() {
        _linkedAm = am;
        _baselineAmUserId = am?.user.id;
        _status = normalizeEnfantStatus(enfant.status);
        if (!enfantStatusValues.contains(_status)) {
          _status = 'sans_garde';
        }
        _localParentLinks = enfant.parentLinks;
        _coerceGenderForStatus();
      });
    } catch (_) {
      if (!mounted) return;
      await _loadLinkedAm();
    }
  }

  Future<void> _attachAm() async {
    if (_linkedAm != null && !_isSansGarde) {
      if (!mounted) return;
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(
          content: Text(
            'Détachez l\'assistante actuelle avant d\'en choisir une autre',
          ),
        ),
      );
      return;
    }

    if (!mounted) return;
    final selected = await AdminSelectAmModal.show(
      context,
      excludeIds: {
        if (_linkedAm != null) _linkedAm!.user.id,
      },
      title: 'Choisir une assistante maternelle',
    );
    if (selected == null || !mounted) return;

    setState(() {
      _linkedAm = selected;
      if (_status == 'sans_garde') {
        _status = 'garde';
      }
      _dirty = true;
    });
  }

  Future<void> _detachAm() async {
    final am = _linkedAm;
    if (am == null) return;

    final confirmed = await showDialog<bool>(
      context: context,
      builder: (ctx) => AlertDialog(
        title: const Text('Détacher l\'assistante'),
        content: Text(
          'Retirer ${am.user.fullName} de la garde de cet enfant ?\n'
          '(Effectif après Sauvegarder.)',
        ),
        actions: [
          TextButton(
            onPressed: () => Navigator.pop(ctx, false),
            child: const Text('Annuler'),
          ),
          ElevatedButton(
            onPressed: () => Navigator.pop(ctx, true),
            style: ValidationModalTheme.primaryElevatedStyle,
            child: const Text('Détacher'),
          ),
        ],
      ),
    );
    if (confirmed != true || !mounted) return;

    setState(() {
      _linkedAm = null;
      if (_status != 'a_naitre' && _status != 'scolarise') {
        _status = 'sans_garde';
      }
      _dirty = true;
    });
  }

  /// Passe en « Sans garde » : cadre vide local (détachement au Sauvegarder).
  void _applySansGardeStatus() {
    if (_linkedAm == null) return;
    setState(() {
      _linkedAm = null;
      _dirty = true;
    });
  }

  /// Conserve la date saisie en basculant naissance ↔ prévisionnelle.
  void _preserveDateOnStatusChange(String from, String to) {
    final becomingUnborn = to == 'a_naitre' && from != 'a_naitre';
    final leavingUnborn = from == 'a_naitre' && to != 'a_naitre';
    if (becomingUnborn) {
      if (_dueCtrl.text.trim().isEmpty &&
          _birthCtrl.text.trim().isNotEmpty) {
        _dueCtrl.text = _birthCtrl.text;
      }
    } else if (leavingUnborn) {
      if (_birthCtrl.text.trim().isEmpty &&
          _dueCtrl.text.trim().isNotEmpty) {
        _birthCtrl.text = _dueCtrl.text;
      }
    }
  }

  InputDecoration _inputDecoration({String? hint, bool error = false}) {
    final base = ValidationFieldDecoration.input(hint: hint).copyWith(
      isDense: false,
      contentPadding: const EdgeInsets.symmetric(horizontal: 12, vertical: 14),
    );
    if (!error) return base;
    final border = OutlineInputBorder(
      borderRadius: BorderRadius.circular(6),
      borderSide: BorderSide(color: Colors.red.shade400),
    );
    return base.copyWith(
      fillColor: Colors.red.shade50,
      enabledBorder: border,
      focusedBorder: border,
      border: border,
    );
  }

  Widget _dropdownField({
    Key? key,
    required String? value,
    required List<MapEntry<String, String>> items,
    required ValueChanged<String> onChanged,
    String? hint,
  }) {
    final safeValue =
        value != null && items.any((e) => e.key == value) ? value : null;
    return SizedBox(
      height: _fieldHeight,
      child: DropdownButtonFormField<String>(
        key: key,
        value: safeValue,
        hint: hint != null
            ? Text(hint, style: TextStyle(color: Colors.grey.shade600))
            : null,
        isExpanded: true,
        decoration: _inputDecoration(),
        items: items
            .map((e) => DropdownMenuItem(value: e.key, child: Text(e.value)))
            .toList(),
        onChanged: _busy
            ? null
            : (v) {
                if (v != null) onChanged(v);
              },
      ),
    );
  }

  Widget _textField(
    TextEditingController controller, {
    String? hint,
    Key? key,
    TextInputType? keyboardType,
    List<TextInputFormatter>? inputFormatters,
    bool error = false,
    Widget? suffixIcon,
  }) {
    return SizedBox(
      height: _fieldHeight,
      child: TextField(
        key: key,
        controller: controller,
        keyboardType: keyboardType,
        inputFormatters: inputFormatters,
        textAlignVertical: TextAlignVertical.center,
        style: TextStyle(
          color: error ? Colors.red.shade800 : Colors.black87,
          fontSize: 14,
        ),
        decoration: _inputDecoration(
          hint: hint,
          error: error,
        ).copyWith(suffixIcon: suffixIcon),
      ),
    );
  }

  Widget _dateField() {
    final past = _dueDateInPast;
    return _textField(
      _activeDateCtrl,
      hint: 'jj / mm / aaaa',
      key: ValueKey(_status),
      keyboardType: TextInputType.number,
      inputFormatters: const [FrenchDateInputFormatter()],
      error: past,
      suffixIcon: past
          ? Tooltip(
              message:
                  'Date prévisionnelle antérieure à aujourd’hui',
              child: Icon(
                Icons.info_outline,
                size: 20,
                color: Colors.red.shade700,
              ),
            )
          : null,
    );
  }

  Widget _fieldsGrid() {
    return ValidationEditableSection(
      rowLayout: _fieldsRowLayout,
      fields: [
        ValidationLabeledField(
          label: 'Prénom',
          field: _textField(
            _prenomCtrl,
            inputFormatters: const [PersonNameInputFormatter()],
          ),
        ),
        ValidationLabeledField(
          label: 'Nom',
          field: _textField(
            _nomCtrl,
            inputFormatters: const [PersonNameInputFormatter()],
          ),
        ),
        ValidationLabeledField(
          label: _dateFieldLabel,
          field: _dateField(),
        ),
        ValidationLabeledField(
          label: 'Statut',
          field: _dropdownField(
            value: _status,
            items: enfantStatusValues
                .map(
                  (s) => MapEntry(
                    s,
                    enfantStatusLabel(s, gender: _gender),
                  ),
                )
                .toList(),
            onChanged: (v) {
              setState(() {
                _preserveDateOnStatusChange(_status, v);
                _status = v;
                _coerceGenderForStatus();
                _dirty = true;
              });
              if (v == 'sans_garde') {
                _applySansGardeStatus();
              }
            },
          ),
        ),
        ValidationLabeledField(
          label: 'Genre',
          field: _dropdownField(
            key: ValueKey('genre-$_status'),
            value: _gender,
            hint: 'Veuillez sélectionner le genre',
            items: _availableGenders
                .map((g) => MapEntry(g, _genderLabel(g)))
                .toList(),
            onChanged: (v) => setState(() {
              _gender = v;
              _dirty = true;
            }),
          ),
        ),
      ],
    );
  }

  Widget _consentPhotoSwitch() {
    return SwitchListTile(
      contentPadding: EdgeInsets.zero,
      dense: true,
      visualDensity: VisualDensity.compact,
      materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
      title: const Text(
        'Consentement photo',
        style: TextStyle(fontSize: 13),
      ),
      value: _consentPhoto,
      onChanged: _busy
          ? null
          : (v) => setState(() {
                _consentPhoto = v;
                _dirty = true;
              }),
    );
  }

  Future<void> _pickPhoto() async {
    if (_busy || !widget.isCreating) return;
    try {
      final picked = await ImagePicker().pickImage(
        source: ImageSource.gallery,
        imageQuality: 75,
        maxWidth: 1200,
        maxHeight: 1200,
      );
      if (picked == null) return;
      final bytes = await picked.readAsBytes();
      if (bytes.isEmpty) return;
      final name = picked.name.trim();
      if (!mounted) return;
      setState(() {
        _photoBytes = bytes;
        _photoFilename = name.isNotEmpty ? name : 'photo.jpg';
        _consentPhoto = true;
        _dirty = true;
      });
    } catch (_) {
      if (!mounted) return;
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(content: Text('Impossible de charger la photo')),
      );
    }
  }

  void _clearPhoto() {
    if (_busy || !widget.isCreating) return;
    setState(() {
      _photoBytes = null;
      _photoFilename = null;
      _dirty = true;
    });
  }

  Widget _mainRow() {
    return LayoutBuilder(
      builder: (context, c) {
        final maxRowW = c.maxWidth;
        final maxRowH = c.maxHeight;
        final idealPhotoW =
            maxRowH * AdminAmPhotoFrame.idPhotoAspectRatio + 16;
        final maxPhotoW = (maxRowW - _photoProGap - _proColumnMinWidth)
            .clamp(0.0, double.infinity);
        var photoW = idealPhotoW.clamp(_photoColumnMinWidth, _photoColumnMaxWidth);
        if (photoW > maxPhotoW) photoW = maxPhotoW;

        return Row(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            SizedBox(
              width: photoW,
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.stretch,
                children: [
                  Expanded(
                    child: AdminAmPhotoFrame(
                      photoUrl: widget.isCreating
                          ? null
                          : widget.enfant?.photoUrl,
                      imageBytes: widget.isCreating ? _photoBytes : null,
                      onTap: widget.isCreating && !_busy ? _pickPhoto : null,
                      onClear: widget.isCreating &&
                              !_busy &&
                              _photoBytes != null &&
                              _photoBytes!.isNotEmpty
                          ? _clearPhoto
                          : null,
                      emptyLabel: widget.isCreating
                          ? 'Cliquer pour ajouter'
                          : 'Aucune photo',
                    ),
                  ),
                  const SizedBox(height: 8),
                  _consentPhotoSwitch(),
                ],
              ),
            ),
            const SizedBox(width: _photoProGap),
            Expanded(
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.stretch,
                children: [
                  _fieldsGrid(),
                  Expanded(
                    child: Padding(
                      padding: const EdgeInsets.only(top: 16),
                      child: Align(
                        alignment: Alignment.bottomCenter,
                        child: SingleChildScrollView(
                          child: _placementBlock(),
                        ),
                      ),
                    ),
                  ),
                ],
              ),
            ),
          ],
        );
      },
    );
  }

  Widget _scolariseCard() {
    return Container(
      height: _placementHeight,
      width: double.infinity,
      decoration: BoxDecoration(
        gradient: LinearGradient(
          colors: [
            const Color(0xFFE8F4FD),
            const Color(0xFFDCEEFB),
          ],
          begin: Alignment.topLeft,
          end: Alignment.bottomRight,
        ),
        borderRadius: BorderRadius.circular(10),
        border: Border.all(color: const Color(0xFF90CAF9)),
      ),
      padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12),
      child: Row(
        children: [
          Container(
            width: 56,
            height: 56,
            decoration: BoxDecoration(
              color: Colors.white.withValues(alpha: 0.85),
              borderRadius: BorderRadius.circular(12),
            ),
            child: Icon(
              Icons.school_rounded,
              size: 32,
              color: Colors.blue.shade700,
            ),
          ),
          const SizedBox(width: 16),
          Expanded(
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Text(
                  enfantStatusLabel('scolarise', gender: _gender),
                  style: TextStyle(
                    fontSize: 16,
                    fontWeight: FontWeight.w700,
                    color: Colors.blue.shade900,
                  ),
                ),
                const SizedBox(height: 4),
                Text(
                  'Enfant scolarisé — pas de garde chez une assistante maternelle',
                  style: TextStyle(
                    fontSize: 13,
                    color: Colors.blue.shade800.withValues(alpha: 0.85),
                  ),
                ),
              ],
            ),
          ),
          Icon(Icons.auto_stories_outlined, size: 28, color: Colors.blue.shade400),
        ],
      ),
    );
  }

  Widget _emptyAmSlot() {
    return Material(
      color: Colors.transparent,
      child: InkWell(
        onTap: _busy ? null : _attachAm,
        borderRadius: BorderRadius.circular(10),
        child: Container(
          height: _placementHeight,
          width: double.infinity,
          decoration: BoxDecoration(
            color: Colors.grey.shade50,
            borderRadius: BorderRadius.circular(10),
            border: Border.all(color: Colors.grey.shade300),
          ),
          padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12),
          child: Row(
            children: [
              Container(
                width: 56,
                height: 56,
                decoration: BoxDecoration(
                  color: Colors.white,
                  borderRadius: BorderRadius.circular(12),
                  border: Border.all(color: Colors.grey.shade200),
                ),
                child: Icon(
                  Icons.face_outlined,
                  size: 30,
                  color: Colors.grey.shade400,
                ),
              ),
              const SizedBox(width: 16),
              Expanded(
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(
                      'Aucune assistante maternelle',
                      style: TextStyle(
                        fontSize: 15,
                        fontWeight: FontWeight.w700,
                        color: Colors.grey.shade800,
                      ),
                    ),
                    const SizedBox(height: 4),
                    Text(
                      'Cliquer pour choisir une assistante',
                      style: TextStyle(
                        fontSize: 13,
                        color: Colors.grey.shade600,
                      ),
                    ),
                  ],
                ),
              ),
              Icon(Icons.add_circle_outline, color: Colors.grey.shade500),
            ],
          ),
        ),
      ),
    );
  }

  Widget _linkedAmCard() {
    final am = _linkedAm!;
    final zone = (am.residenceCity ?? '').trim();
    final agrement = (am.approvalNumber ?? '').trim();
    final subtitle = [
      if (zone.isNotEmpty) 'Zone : $zone',
      if (agrement.isNotEmpty) 'Agrément : $agrement',
    ].join('  ·  ');

    return Material(
      color: Colors.transparent,
      child: InkWell(
        onTap: _busy ? null : _openLinkedAm,
        borderRadius: BorderRadius.circular(10),
        child: Container(
          height: _placementHeight,
          width: double.infinity,
          decoration: BoxDecoration(
            color: const Color(0xFFF7F3FC),
            borderRadius: BorderRadius.circular(10),
            border: Border.all(color: const Color(0xFFD4C4EF)),
          ),
          padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
          child: Row(
            children: [
              _amAvatar(am.user.photoUrl),
              const SizedBox(width: 16),
              Expanded(
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(
                      am.user.fullName,
                      maxLines: 1,
                      overflow: TextOverflow.ellipsis,
                      style: const TextStyle(
                        fontSize: 15,
                        fontWeight: FontWeight.w700,
                        color: Color(0xFF4A2F7A),
                      ),
                    ),
                    if (subtitle.isNotEmpty) ...[
                      const SizedBox(height: 4),
                      Text(
                        subtitle,
                        maxLines: 1,
                        overflow: TextOverflow.ellipsis,
                        style: TextStyle(
                          fontSize: 13,
                          color: Colors.grey.shade700,
                        ),
                      ),
                    ],
                  ],
                ),
              ),
              IconButton(
                icon: const Icon(Icons.open_in_new, size: 20),
                tooltip: 'Ouvrir la fiche AM',
                onPressed: _busy ? null : _openLinkedAm,
              ),
              IconButton(
                icon: Icon(Icons.link_off, size: 20, color: Colors.orange.shade800),
                tooltip: 'Détacher',
                onPressed: _busy ? null : _detachAm,
              ),
            ],
          ),
        ),
      ),
    );
  }

  Widget _amAvatar(String? photoUrl) {
    const size = 56.0;
    const bg = Color(0xFFEDE5FA);
    const iconColor = Color(0xFF6B3FA0);
    final url = ApiConfig.absoluteMediaUrl(photoUrl);

    if (url.isEmpty) {
      return Container(
        width: size,
        height: size,
        decoration: BoxDecoration(
          color: bg,
          borderRadius: BorderRadius.circular(12),
        ),
        child: const Icon(Icons.face, size: 30, color: iconColor),
      );
    }

    return ClipRRect(
      borderRadius: BorderRadius.circular(12),
      child: AuthNetworkImage(
        url: url,
        width: size,
        height: size,
        fit: BoxFit.cover,
        errorBuilder: (_, __, ___) => Container(
          width: size,
          height: size,
          color: bg,
          child: const Icon(Icons.face, size: 30, color: iconColor),
        ),
      ),
    );
  }

  String get _placementTitle {
    if (widget.isCreating) return 'Sélection du dossier de la famille';
    return _isScolarise ? 'Scolarisation' : 'Assistante maternelle';
  }

  Widget _placementBlock() {
    return Column(
      mainAxisSize: MainAxisSize.min,
      crossAxisAlignment: CrossAxisAlignment.stretch,
      children: [
        if (_isOrphan) ...[
          Text(
            'Sélection du dossier de la famille',
            style: TextStyle(
              fontSize: 14,
              fontWeight: FontWeight.w600,
              color: Colors.red.shade800,
            ),
          ),
          const SizedBox(height: 4),
          Text(
            'Aucun responsable rattaché — choisissez un foyer',
            style: TextStyle(fontSize: 12, color: Colors.red.shade700),
          ),
          const SizedBox(height: 8),
          _familyPlacementSection(),
          const SizedBox(height: 16),
        ],
        Text(
          _placementTitle,
          style: TextStyle(
            fontSize: 14,
            fontWeight: FontWeight.w600,
            color: Colors.grey.shade800,
          ),
        ),
        const SizedBox(height: 8),
        if (widget.isCreating) _familyPlacementSection() else _placementSection(),
      ],
    );
  }

  Future<void> _pickFamily() async {
    if (_busy) return;
    final selected = await AdminSelectFamilleModal.show(
      context,
      title: 'Choisir une famille',
    );
    if (selected == null || !mounted) return;

    if (widget.isCreating) {
      setState(() {
        _selectedFamily = selected;
        _dirty = true;
      });
      return;
    }

    // Édition orphelin (#157) : rattache immédiatement au foyer.
    final enfantId = widget.enfant?.id;
    if (enfantId == null || enfantId.isEmpty) return;

    setState(() => _saving = true);
    try {
      for (final parentId in selected.parentUserIds) {
        await UserService.attachEnfantToParent(
          parentUserId: parentId,
          enfantId: enfantId,
        );
      }
      final refreshed = await UserService.getEnfant(enfantId);
      if (!mounted) return;
      setState(() {
        _localParentLinks = refreshed.parentLinks;
        _selectedFamily = selected;
        _saving = false;
      });
      widget.onSaved?.call();
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(content: Text('Enfant rattaché au foyer')),
      );
    } catch (e) {
      if (!mounted) return;
      setState(() => _saving = false);
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text(e.toString().replaceFirst('Exception: ', ''))),
      );
    }
  }

  Widget _familyPlacementSection() {
    final family = _selectedFamily;
    if (family == null) {
      return Material(
        color: Colors.transparent,
        child: InkWell(
          onTap: _busy ? null : _pickFamily,
          borderRadius: BorderRadius.circular(10),
          child: Container(
            height: _placementHeight,
            width: double.infinity,
            decoration: BoxDecoration(
              color: Colors.grey.shade50,
              borderRadius: BorderRadius.circular(10),
              border: Border.all(color: Colors.grey.shade300),
            ),
            padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12),
            child: Row(
              children: [
                Container(
                  width: 56,
                  height: 56,
                  decoration: BoxDecoration(
                    color: Colors.white,
                    borderRadius: BorderRadius.circular(12),
                    border: Border.all(color: Colors.grey.shade200),
                  ),
                  child: Icon(
                    Icons.family_restroom,
                    size: 30,
                    color: Colors.grey.shade400,
                  ),
                ),
                const SizedBox(width: 16),
                Expanded(
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      Text(
                        'Aucune famille sélectionnée',
                        style: TextStyle(
                          fontSize: 15,
                          fontWeight: FontWeight.w700,
                          color: Colors.grey.shade800,
                        ),
                      ),
                      const SizedBox(height: 4),
                      Text(
                        'Cliquer pour choisir un dossier / foyer',
                        style: TextStyle(
                          fontSize: 13,
                          color: Colors.grey.shade600,
                        ),
                      ),
                    ],
                  ),
                ),
                Icon(Icons.add_circle_outline, color: Colors.grey.shade500),
              ],
            ),
          ),
        ),
      );
    }

    return Material(
      color: Colors.transparent,
      child: InkWell(
        onTap: _busy ? null : _pickFamily,
        borderRadius: BorderRadius.circular(10),
        child: Container(
          height: _placementHeight,
          width: double.infinity,
          decoration: BoxDecoration(
            color: const Color(0xFFF8F5FC),
            borderRadius: BorderRadius.circular(10),
            border: Border.all(color: const Color(0xFFD8CCE8)),
          ),
          padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12),
          child: Row(
            children: [
              Container(
                width: 56,
                height: 56,
                decoration: BoxDecoration(
                  color: const Color(0xFFEDE5FA),
                  borderRadius: BorderRadius.circular(12),
                ),
                child: const Icon(
                  Icons.family_restroom,
                  size: 30,
                  color: Color(0xFF6B3FA0),
                ),
              ),
              const SizedBox(width: 16),
              Expanded(
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(
                      family.displayTitle,
                      style: const TextStyle(
                        fontSize: 15,
                        fontWeight: FontWeight.w700,
                      ),
                      maxLines: 1,
                      overflow: TextOverflow.ellipsis,
                    ),
                    if (family.parentNames.isNotEmpty) ...[
                      const SizedBox(height: 4),
                      Text(
                        family.parentNames.join(', '),
                        style: const TextStyle(
                          fontSize: 13,
                          color: Colors.black54,
                        ),
                        maxLines: 1,
                        overflow: TextOverflow.ellipsis,
                      ),
                    ],
                  ],
                ),
              ),
              IconButton(
                icon: Icon(Icons.swap_horiz, color: Colors.grey.shade700),
                tooltip: 'Changer de famille',
                onPressed: _busy ? null : _pickFamily,
              ),
            ],
          ),
        ),
      ),
    );
  }

  Widget _placementSection() {
    if (!_showsAmPlacement) return _scolariseCard();

    if (_loadingAm) {
      return SizedBox(
        height: _placementHeight,
        width: double.infinity,
        child: Center(
          child: SizedBox(
            width: 24,
            height: 24,
            child: CircularProgressIndicator(
              strokeWidth: 2,
              color: Colors.grey.shade600,
            ),
          ),
        ),
      );
    }

    // Sans garde : toujours le cadre vide (comme après détachement AM).
    if (_isSansGarde) return _emptyAmSlot();
    if (_linkedAm != null) return _linkedAmCard();
    return _emptyAmSlot();
  }

  Widget _buildFooter() {
    return Row(
      children: [
        if (_canDelete)
          OutlinedButton(
            onPressed: _busy ? null : _delete,
            style: OutlinedButton.styleFrom(
              foregroundColor: Colors.red.shade700,
            ),
            child: _deleting
                ? const SizedBox(
                    width: 16,
                    height: 16,
                    child: CircularProgressIndicator(strokeWidth: 2),
                  )
                : const Text('Supprimer'),
          ),
        const Spacer(),
        TextButton(
          onPressed: _busy ? null : () => Navigator.of(context).pop(),
          child: const Text('Fermer'),
        ),
        const SizedBox(width: 12),
        ElevatedButton(
          style: ValidationModalTheme.primaryElevatedStyle,
          onPressed: !_canSubmit || _busy ? null : _save,
          child: _saving
              ? const SizedBox(
                  width: 18,
                  height: 18,
                  child: CircularProgressIndicator(
                    strokeWidth: 2,
                    color: Colors.white,
                  ),
                )
              : Text(
                  widget.isCreating
                      ? 'Créer'
                      : (_dirty ? 'Sauvegarder' : 'Aucune modification'),
                ),
        ),
      ],
    );
  }

  String _genderLabel(String gender) {
    switch (gender) {
      case 'H':
        return 'Garçon';
      case 'F':
        return 'Fille';
      case 'Autre':
        return 'Inconnu';
      default:
        return gender;
    }
  }

  @override
  Widget build(BuildContext context) {
    return Dialog(
      shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
      child: ConstrainedBox(
        constraints: const BoxConstraints(maxWidth: _modalWidth),
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            Padding(
              padding: const EdgeInsets.fromLTRB(18, 16, 4, 0),
              child: Row(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Expanded(
                    child: Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: [
                        Text(
                          _headerTitle(),
                          style: const TextStyle(
                            fontSize: 18,
                            fontWeight: FontWeight.w700,
                          ),
                        ),
                        if (_parentsSubtitle() != null) ...[
                          const SizedBox(height: 4),
                          _parentsSubtitle()!,
                        ],
                      ],
                    ),
                  ),
                  IconButton(
                    padding: EdgeInsets.zero,
                    constraints: const BoxConstraints(
                      minWidth: 40,
                      minHeight: 40,
                    ),
                    icon: const Icon(Icons.close),
                    onPressed: _busy ? null : () => Navigator.of(context).pop(),
                    tooltip: 'Fermer',
                  ),
                ],
              ),
            ),
            const Divider(height: 1),
            Padding(
              padding: const EdgeInsets.fromLTRB(20, 12, 20, 12),
              child: Column(
                mainAxisSize: MainAxisSize.min,
                crossAxisAlignment: CrossAxisAlignment.stretch,
                children: [
                  SizedBox(height: _mainRowHeight, child: _mainRow()),
                  const SizedBox(height: 12),
                  _buildFooter(),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }
}
