import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:p_tits_pas/models/assistante_maternelle_model.dart';
import 'package:p_tits_pas/models/parent_child_summary.dart';
import 'package:p_tits_pas/utils/am_vigilance.dart';
import 'package:p_tits_pas/utils/date_display_utils.dart';
import 'package:p_tits_pas/utils/nir_utils.dart';
import 'package:p_tits_pas/utils/phone_utils.dart';
import 'package:p_tits_pas/services/user_service.dart';
import 'package:p_tits_pas/widgets/admin/common/admin_am_children_capacity_grid.dart';
import 'package:p_tits_pas/widgets/admin/common/admin_am_photo_frame.dart';
import 'package:p_tits_pas/widgets/admin/common/admin_child_detail_modal.dart';
import 'package:p_tits_pas/widgets/admin/common/admin_select_enfant_modal.dart';
import 'package:p_tits_pas/widgets/admin/common/admin_status_capsule.dart';
import 'package:p_tits_pas/widgets/admin/common/validation_detail_section.dart';
import 'package:p_tits_pas/widgets/common/identity_block.dart';
import 'package:p_tits_pas/widgets/admin/validation_modal_theme.dart';

/// Fiche AM éditable (ticket #131) — identité | fiche pro (photo) | enfants.
class AdminAmEditModal extends StatefulWidget {
  final AssistanteMaternelleModel assistante;
  final VoidCallback? onSaved;

  const AdminAmEditModal({
    super.key,
    required this.assistante,
    this.onSaved,
  });

  @override
  State<AdminAmEditModal> createState() => _AdminAmEditModalState();
}

class _AdminAmEditModalState extends State<AdminAmEditModal>
    with SingleTickerProviderStateMixin {
  late final TabController _tabCtrl;
  late final TextEditingController _nomCtrl;
  late final TextEditingController _prenomCtrl;
  late final TextEditingController _emailCtrl;
  late final TextEditingController _telCtrl;
  late final TextEditingController _adresseCtrl;
  late final TextEditingController _villeCtrl;
  late final TextEditingController _cpCtrl;
  late final TextEditingController _agrementCtrl;
  late final TextEditingController _nirCtrl;
  late final TextEditingController _dateNaissanceCtrl;
  late final TextEditingController _lieuNaissanceVilleCtrl;
  late final TextEditingController _lieuNaissancePaysCtrl;
  late final TextEditingController _dateAgrementCtrl;
  late final TextEditingController _capaciteCtrl;

  late String _statut;
  late bool _disponible;
  late int? _placesAvailable;
  late List<ParentChildSummary> _children;
  late Set<String> _baselineChildIds;

  /// Enfants ajoutés localement qui étaient déjà chez une autre AM
  /// (enfantId → amUserId d'origine). Au save : détacher puis rattacher.
  final Map<String, String> _transferFromAmIds = {};

  bool _saving = false;
  bool _dirty = false;

  static const double _modalWidth = 930;
  static const double _photoProGap = 24;
  static const double _proColumnMinWidth = 260;
  static const double _photoColumnMinWidth = 160;
  static const double _proTabHeight = 300;
  static const List<int> _photoProRowLayout = [2, 2, 2];

  /// Hauteur onglet enfants : champs + titre + grille 2×2 (+ alerte places si besoin).
  double _childrenTabHeight() {
    const capacityFields = 72.0;
    const titleSection = 40.0;
    const inconsistencyExtra = 46.0;
    var h = capacityFields +
        titleSection +
        AdminAmChildrenCapacityGrid.fixedHeight;
    if (_placesInconsistent()) h += inconsistencyExtra;
    return h + 4;
  }

  double _tabViewHeight(int index) {
    switch (index) {
      case 1:
        return _proTabHeight;
      case 2:
        return _childrenTabHeight();
      default:
        return 292;
    }
  }

  @override
  void initState() {
    super.initState();
    _tabCtrl = TabController(length: 3, vsync: this);
    final u = widget.assistante.user;
    final am = widget.assistante;

    _nomCtrl = TextEditingController(text: u.nom ?? '');
    _prenomCtrl = TextEditingController(text: u.prenom ?? '');
    _emailCtrl = TextEditingController(text: u.email);
    _telCtrl = TextEditingController(
      text: formatPhoneForDisplay(u.telephone ?? ''),
    );
    _adresseCtrl = TextEditingController(text: u.adresse ?? '');
    _villeCtrl = TextEditingController(text: u.ville ?? '');
    _cpCtrl = TextEditingController(text: u.codePostal ?? '');
    _agrementCtrl = TextEditingController(text: am.approvalNumber ?? '');
    _nirCtrl = TextEditingController(text: _formatNirDisplay());
    _dateNaissanceCtrl = TextEditingController(
      text: formatIsoDateFr(u.dateNaissance, ifEmpty: ''),
    );
    _lieuNaissanceVilleCtrl = TextEditingController(
      text: u.lieuNaissanceVille ?? '',
    );
    _lieuNaissancePaysCtrl = TextEditingController(
      text: u.lieuNaissancePays ?? '',
    );
    _dateAgrementCtrl = TextEditingController(
      text: formatIsoDateFr(am.agreementDate, ifEmpty: ''),
    );
    _capaciteCtrl = TextEditingController(
      text: am.maxChildren?.toString() ?? '',
    );
    _statut = u.statut ?? 'en_attente';
    _disponible = am.available ?? true;
    _placesAvailable = am.placesAvailable;
    _children = List.of(am.children);
    _baselineChildIds = _children.map((c) => c.id).toSet();

    for (final c in [
      _nomCtrl,
      _prenomCtrl,
      _emailCtrl,
      _telCtrl,
      _adresseCtrl,
      _villeCtrl,
      _cpCtrl,
      _agrementCtrl,
      _nirCtrl,
      _dateNaissanceCtrl,
      _lieuNaissanceVilleCtrl,
      _lieuNaissancePaysCtrl,
      _dateAgrementCtrl,
      _capaciteCtrl,
    ]) {
      c.addListener(_markDirty);
    }
    _capaciteCtrl.addListener(_onCapacityChanged);
    _nomCtrl.addListener(_onNameFieldChanged);
    _prenomCtrl.addListener(_onNameFieldChanged);
    _tabCtrl.addListener(_onTabChanged);
    _fetchChildrenFromServer();
  }

  bool _childrenChanged() {
    final current = _children.map((c) => c.id).toSet();
    return current.length != _baselineChildIds.length ||
        !current.containsAll(_baselineChildIds);
  }

  void _syncPlacesAfterChildrenChange() {
    final expected = _computedPlacesAvailable();
    if (expected != null) _placesAvailable = expected;
  }

  void _onTabChanged() {
    if (!_tabCtrl.indexIsChanging) setState(() {});
  }

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

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

  @override
  void dispose() {
    _tabCtrl.dispose();
    for (final c in [
      _nomCtrl,
      _prenomCtrl,
      _emailCtrl,
      _telCtrl,
      _adresseCtrl,
      _villeCtrl,
      _cpCtrl,
      _agrementCtrl,
      _nirCtrl,
      _dateNaissanceCtrl,
      _lieuNaissanceVilleCtrl,
      _lieuNaissancePaysCtrl,
      _dateAgrementCtrl,
      _capaciteCtrl,
    ]) {
      c.dispose();
    }
    super.dispose();
  }

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

  String _headerTitle() {
    final fn = _prenomCtrl.text.trim();
    final ln = _nomCtrl.text.trim();
    if (fn.isEmpty && ln.isEmpty) {
      final fallback = widget.assistante.user.fullName.trim();
      return fallback.isNotEmpty ? fallback : 'Assistante maternelle';
    }
    return '$fn $ln'.trim();
  }

  String? _headerSubtitle() {
    final parts = <String>[];
    final zone = (widget.assistante.residenceCity ?? '').trim();
    if (zone.isNotEmpty) parts.add('Zone : $zone');
    final agrement = _agrementCtrl.text.trim();
    if (agrement.isNotEmpty) parts.add('Agrément : $agrement');
    final dossier = widget.assistante.user.numeroDossier?.trim();
    if (dossier != null && dossier.isNotEmpty) {
      parts.add('Dossier $dossier');
    }
    if (parts.isEmpty) return null;
    return parts.join(' · ');
  }

  String _formatNirDisplay() {
    final raw = widget.assistante.nir?.trim() ?? '';
    if (raw.isEmpty) return '';
    final digits = nirToRaw(raw).toUpperCase();
    return digits.length == 15 ? formatNir(digits) : raw;
  }

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

  int? _capaciteMax() => _parseIntField(_capaciteCtrl);

  /// True si plus aucune place d'accueil (enfants ≥ capacité max).
  bool get _capacityFull {
    final max = _capaciteMax();
    if (max == null) return false;
    return _children.length >= max;
  }

  int? _computedPlacesAvailable() => amExpectedPlacesAvailable(
        maxChildren: _capaciteMax(),
        childrenCount: _children.length,
      );

  bool _placesInconsistent() => amHasPlacesInconsistency(
        maxChildren: _capaciteMax(),
        placesAvailable: _placesAvailable,
        childrenCount: _children.length,
      );

  String _placesDisplayValue() {
    if (_placesAvailable != null) return _placesAvailable.toString();
    return '–';
  }

  void _applyPlacesCorrection() {
    final expected = _computedPlacesAvailable();
    if (expected == null) return;
    setState(() {
      _placesAvailable = expected;
      _dirty = true;
    });
  }

  String? _placesInconsistencyMessage() {
    if (!_placesInconsistent()) return null;
    final stored = _placesAvailable;
    final expected = _computedPlacesAvailable();
    final storedLabel = stored?.toString() ?? 'non renseigné';
    final expectedLabel = expected?.toString() ?? '–';
    return 'Incohérence : l\'AM déclare $storedLabel place(s) disponible(s), '
        'le calcul (capacité ${_capaciteMax() ?? '–'} − ${_children.length} '
        'enfant(s) rattaché(s)) donne $expectedLabel.';
  }

  int? _parseIntField(TextEditingController c) {
    final t = c.text.trim();
    if (t.isEmpty) return null;
    return int.tryParse(t);
  }

  Future<void> _save() async {
    if (!_dirty) return;
    final confirmed = await showDialog<bool>(
      context: context,
      builder: (ctx) => AlertDialog(
        title: const Text('Confirmer'),
        content: const Text(
          'Enregistrer les modifications de la fiche assistante maternelle ?',
        ),
        actions: [
          TextButton(
            onPressed: () => Navigator.pop(ctx, false),
            child: const Text('Annuler'),
          ),
          ElevatedButton(
            onPressed: () => Navigator.pop(ctx, true),
            child: const Text('Sauvegarder'),
          ),
        ],
      ),
    );
    if (confirmed != true || !mounted) return;

    setState(() => _saving = true);
    try {
      if (_childrenChanged()) _syncPlacesAfterChildrenChange();

      final currentIds = _children.map((c) => c.id).toSet();
      for (final id in _baselineChildIds.difference(currentIds)) {
        await UserService.detachEnfantFromAm(
          amUserId: widget.assistante.user.id,
          enfantId: id,
        );
      }
      for (final id in currentIds.difference(_baselineChildIds)) {
        // Transfert : détacher l'ancienne AM sans recalculer ses places
        // (le ! de vigilance apparaît côté liste AM).
        final previousAmId = _transferFromAmIds[id] ??
            (await UserService.findAmForEnfant(id))?.user.id;
        if (previousAmId != null &&
            previousAmId != widget.assistante.user.id) {
          await UserService.detachEnfantFromAm(
            amUserId: previousAmId,
            enfantId: id,
          );
        }
        await UserService.attachEnfantToAm(
          amUserId: widget.assistante.user.id,
          enfantId: id,
        );
      }

      await UserService.updateAmFiche(
        amUserId: widget.assistante.user.id,
        body: {
          'nom': _nomCtrl.text.trim(),
          'prenom': _prenomCtrl.text.trim(),
          'email': _emailCtrl.text.trim(),
          'telephone': normalizePhone(_telCtrl.text),
          'adresse': _adresseCtrl.text.trim(),
          'ville': _villeCtrl.text.trim(),
          'code_postal': _cpCtrl.text.trim(),
          'statut': _statut,
          'approval_number': _agrementCtrl.text.trim(),
          'nir': nirToRaw(_nirCtrl.text),
          if (_frDateToIso(_dateNaissanceCtrl.text) != null)
            'date_naissance': _frDateToIso(_dateNaissanceCtrl.text),
          'lieu_naissance_ville': _lieuNaissanceVilleCtrl.text.trim(),
          'lieu_naissance_pays': _lieuNaissancePaysCtrl.text.trim(),
          if (_frDateToIso(_dateAgrementCtrl.text) != null)
            'agreement_date': _frDateToIso(_dateAgrementCtrl.text),
          if (_capaciteMax() != null) 'max_children': _capaciteMax(),
          if (_placesAvailable != null) 'places_available': _placesAvailable,
          'available': _disponible,
        },
      );
      if (!mounted) return;
      setState(() {
        _dirty = false;
        _saving = false;
        _baselineChildIds = currentIds;
        _transferFromAmIds.clear();
      });
      widget.onSaved?.call();
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(content: Text('Fiche assistante maternelle enregistrée')),
      );
    } catch (e) {
      if (!mounted) return;
      setState(() => _saving = false);
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text(e.toString().replaceFirst('Exception: ', ''))),
      );
    }
  }

  Future<void> _fetchChildrenFromServer() async {
    try {
      final refreshed =
          await UserService.getAssistanteMaternelle(widget.assistante.user.id);
      final all = await UserService.getEnfants();
      final byId = {for (final e in all) e.id: e};

      final kids = refreshed.children.map((c) {
        final full = byId[c.id];
        if (full != null) return ParentChildSummary.fromEnfant(full);
        return c;
      }).toList();

      if (!mounted) return;
      setState(() {
        _children = kids;
        _baselineChildIds = kids.map((c) => c.id).toSet();
        _transferFromAmIds.clear();
      });
    } catch (_) {}
  }

  Future<void> _refreshChildrenDetails() async {
    try {
      final all = await UserService.getEnfants();
      final byId = {for (final e in all) e.id: e};

      if (!mounted) return;
      setState(() {
        _children = _children.map((c) {
          final full = byId[c.id];
          if (full != null) return ParentChildSummary.fromEnfant(full);
          return c;
        }).toList();
      });
    } catch (_) {}
  }

  Future<void> _openChild(ParentChildSummary child) async {
    try {
      final enfant = await UserService.getEnfant(child.id);
      if (!mounted) return;
      await showDialog<void>(
        context: context,
        builder: (ctx) => AdminChildDetailModal(
          enfant: enfant,
          onSaved: _refreshChildrenDetails,
        ),
      );
    } catch (e) {
      if (!mounted) return;
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text(e.toString().replaceFirst('Exception: ', ''))),
      );
    }
  }

  Future<void> _detachChild(ParentChildSummary child) async {
    final confirmed = await showDialog<bool>(
      context: context,
      builder: (ctx) => AlertDialog(
        title: const Text('Détacher l\'enfant'),
        content: Text(
          'Retirer ${child.fullName} de la fiche de cette assistante ?',
        ),
        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(() {
      _children = _children.where((c) => c.id != child.id).toList();
      _transferFromAmIds.remove(child.id);
      _syncPlacesAfterChildrenChange();
      _dirty = true;
    });
  }

  Future<void> _attachChild() async {
    if (_capacityFull || !mounted) return;
    final selected = await AdminSelectEnfantModal.show(
      context,
      excludeIds: _children.map((c) => c.id).toSet(),
      title: 'Rattacher un enfant',
      showSansGardeFilter: true,
    );
    if (selected == null || !mounted) return;

    AssistanteMaternelleModel? previousAm;
    try {
      previousAm = await UserService.findAmForEnfant(selected.id);
    } catch (_) {
      previousAm = null;
    }
    if (!mounted) return;

    final previousAmId = previousAm?.user.id;
    final isTransfer = previousAmId != null &&
        previousAmId != widget.assistante.user.id;

    if (isTransfer) {
      final amName = previousAm!.user.fullName.trim().isNotEmpty
          ? previousAm.user.fullName.trim()
          : 'une autre assistante maternelle';
      final gardeLabel =
          (selected.gender ?? '').trim().toUpperCase() == 'F'
              ? 'déjà gardée'
              : 'déjà gardé';
      final confirmed = await showDialog<bool>(
        context: context,
        builder: (ctx) => AlertDialog(
          title: const Text('Changer d\'affectation'),
          content: Text(
            '${selected.fullName} est $gardeLabel par $amName.\n\n'
            'Confirmer le transfert vers cette assistante ? '
            'L\'enfant sera détaché de $amName.',
          ),
          actions: [
            TextButton(
              onPressed: () => Navigator.pop(ctx, false),
              child: const Text('Annuler'),
            ),
            ElevatedButton(
              onPressed: () => Navigator.pop(ctx, true),
              style: ValidationModalTheme.primaryElevatedStyle,
              child: const Text('Confirmer'),
            ),
          ],
        ),
      );
      if (confirmed != true || !mounted) return;
    }

    setState(() {
      _children = [
        ..._children,
        ParentChildSummary.fromEnfant(selected),
      ];
      if (isTransfer) {
        _transferFromAmIds[selected.id] = previousAmId!;
      }
      _syncPlacesAfterChildrenChange();
      _dirty = true;
    });
  }


  Widget _identityTab() {
    return SingleChildScrollView(
      child: IdentityBlock.editable(
        title: 'Identité et coordonnées',
        nomController: _nomCtrl,
        prenomController: _prenomCtrl,
        telephoneController: _telCtrl,
        emailController: _emailCtrl,
        adresseController: _adresseCtrl,
        codePostalController: _cpCtrl,
        villeController: _villeCtrl,
      ),
    );
  }

  Widget _proFieldsGrid() {
    return ValidationFormGrid(
      title: 'Dossier professionnel',
      rowLayout: _photoProRowLayout,
      fields: [
        ValidationLabeledField(
          label: 'NIR',
          field: ValidationEditableField(
            controller: _nirCtrl,
            hintText: '15 chiffres',
            inputFormatters: [
              FilteringTextInputFormatter.allow(RegExp(r'[\d\s]')),
            ],
          ),
        ),
        ValidationLabeledField(
          label: 'Date de naissance',
          field: ValidationEditableField(
            controller: _dateNaissanceCtrl,
            hintText: 'jj/mm/aaaa',
          ),
        ),
        ValidationLabeledField(
          label: 'Ville de naissance',
          field: ValidationEditableField(
            controller: _lieuNaissanceVilleCtrl,
          ),
        ),
        ValidationLabeledField(
          label: 'Pays de naissance',
          field: ValidationEditableField(
            controller: _lieuNaissancePaysCtrl,
          ),
        ),
        ValidationLabeledField(
          label: 'N° Agrément',
          field: ValidationEditableField(
            controller: _agrementCtrl,
          ),
        ),
        ValidationLabeledField(
          label: 'Date d\'agrément',
          field: ValidationEditableField(
            controller: _dateAgrementCtrl,
            hintText: 'jj/mm/aaaa',
          ),
        ),
      ],
    );
  }

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

        return Row(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            SizedBox(
              width: photoW,
              child: AdminAmPhotoFrame(
                photoUrl: widget.assistante.user.photoUrl,
              ),
            ),
            const SizedBox(width: _photoProGap),
            Expanded(
              child: SingleChildScrollView(
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.stretch,
                  children: [
                    _proFieldsGrid(),
                    SwitchListTile(
                      contentPadding: EdgeInsets.zero,
                      dense: true,
                      visualDensity: VisualDensity.compact,
                      materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
                      title: const Text(
                        'Disponible pour accueillir',
                        style: TextStyle(fontSize: 13),
                      ),
                      value: _disponible,
                      onChanged: (v) => setState(() {
                        _disponible = v;
                        _dirty = true;
                      }),
                    ),
                  ],
                ),
              ),
            ),
          ],
        );
      },
    );
  }

  Widget _childrenCapacityFields() {
    final inconsistent = _placesInconsistent();
    return Column(
      crossAxisAlignment: CrossAxisAlignment.stretch,
      children: [
        ValidationEditableSection(
          rowLayout: const [2],
          fields: [
            ValidationLabeledField(
              label: 'Capacité max (enfants)',
              field: ValidationEditableField(
                controller: _capaciteCtrl,
                keyboardType: TextInputType.number,
                inputFormatters: [FilteringTextInputFormatter.digitsOnly],
              ),
            ),
            ValidationLabeledField(
              label: 'Places disponibles',
              field: ValidationReadOnlyField(
                value: _placesDisplayValue(),
                error: inconsistent,
              ),
            ),
          ],
        ),
        if (inconsistent) ...[
          const SizedBox(height: 6),
          Wrap(
            crossAxisAlignment: WrapCrossAlignment.center,
            spacing: 6,
            runSpacing: 4,
            children: [
              Text(
                _placesInconsistencyMessage()!,
                style: TextStyle(
                  fontSize: 12,
                  color: Colors.red.shade700,
                  height: 1.3,
                ),
              ),
              OutlinedButton(
                onPressed: _saving ? null : _applyPlacesCorrection,
                style: OutlinedButton.styleFrom(
                  foregroundColor: Colors.red.shade800,
                  disabledForegroundColor: Colors.red.shade300,
                  side: BorderSide(color: Colors.red.shade400),
                  padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
                  minimumSize: const Size(0, 28),
                  tapTargetSize: MaterialTapTargetSize.shrinkWrap,
                  visualDensity: VisualDensity.compact,
                  textStyle: const TextStyle(
                    fontSize: 12,
                    fontWeight: FontWeight.w600,
                  ),
                ),
                child: const Text('Mettre à jour'),
              ),
            ],
          ),
        ],
      ],
    );
  }

  Widget _childrenTab() {
    final capacity = (_capaciteMax() ?? 4).clamp(1, 4);
    return Column(
      crossAxisAlignment: CrossAxisAlignment.stretch,
      children: [
        _childrenCapacityFields(),
        const SizedBox(height: 10),
        Text(
          'Enfants accueillis : ${_children.length}',
          style: const TextStyle(
            fontSize: 15,
            fontWeight: FontWeight.w600,
            color: Colors.black87,
          ),
        ),
        const SizedBox(height: 8),
        AdminAmChildrenCapacityGrid(
          children: _children,
          capacity: capacity,
          onOpen: _openChild,
          onDetach: _detachChild,
          onAttachEmpty: _capacityFull ? null : _attachChild,
        ),
      ],
    );
  }

  Widget _buildFooter() {
    final isChildrenTab = _tabCtrl.index == 2;
    final canAttachChild = !_saving && !_capacityFull;
    return Row(
      children: [
        TextButton(
          onPressed: _saving ? null : () => Navigator.of(context).pop(),
          child: const Text('Fermer'),
        ),
        const Spacer(),
        if (isChildrenTab)
          Tooltip(
            message: _capacityFull
                ? 'Capacité maximale atteinte'
                : 'Rattacher un enfant',
            child: TextButton.icon(
              onPressed: canAttachChild ? _attachChild : null,
              icon: const Icon(Icons.link, size: 18),
              label: const Text('Rattacher un enfant'),
            ),
          ),
        if (isChildrenTab) const SizedBox(width: 12),
        ElevatedButton(
          style: ValidationModalTheme.primaryElevatedStyle,
          onPressed: !_dirty || _saving ? null : _save,
          child: _saving
              ? const SizedBox(
                  width: 18,
                  height: 18,
                  child: CircularProgressIndicator(
                    strokeWidth: 2,
                    color: Colors.white,
                  ),
                )
              : Text(_dirty ? 'Sauvegarder' : 'Aucune modification'),
        ),
      ],
    );
  }

  @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 (_headerSubtitle() != null) ...[
                          const SizedBox(height: 4),
                          Text(
                            _headerSubtitle()!,
                            style: const TextStyle(
                              fontSize: 13,
                              color: Colors.black54,
                            ),
                          ),
                        ],
                      ],
                    ),
                  ),
                  const SizedBox(width: 12),
                  SizedBox(
                    width: 160,
                    child: AdminStatusCapsule(
                      statut: _statut,
                      onChanged: (v) => setState(() {
                        _statut = v;
                        _dirty = true;
                      }),
                    ),
                  ),
                  IconButton(
                    padding: EdgeInsets.zero,
                    constraints: const BoxConstraints(
                      minWidth: 40,
                      minHeight: 40,
                    ),
                    icon: const Icon(Icons.close),
                    onPressed: () => Navigator.of(context).pop(),
                    tooltip: 'Fermer',
                  ),
                ],
              ),
            ),
            TabBar(
              controller: _tabCtrl,
              onTap: (_) => setState(() {}),
              labelColor: ValidationModalTheme.primaryActionBackground,
              unselectedLabelColor: Colors.black54,
              indicatorColor: ValidationModalTheme.primaryActionBackground,
              tabs: const [
                Tab(text: 'Identité'),
                Tab(text: 'Fiche professionnelle'),
                Tab(text: 'Enfants accueillis'),
              ],
            ),
            const Divider(height: 1),
            Padding(
              padding: const EdgeInsets.fromLTRB(20, 12, 20, 0),
              child: SizedBox(
                height: _tabViewHeight(_tabCtrl.index),
                child: TabBarView(
                  controller: _tabCtrl,
                  children: [
                    _identityTab(),
                    _proTab(),
                    _childrenTab(),
                  ],
                ),
              ),
            ),
            Padding(
              padding: const EdgeInsets.fromLTRB(20, 12, 20, 12),
              child: _buildFooter(),
            ),
          ],
        ),
      ),
    );
  }
}
