import 'dart:async';
import 'package:flutter/material.dart';
import 'package:get_it/get_it.dart';
import '../../../../shared/design_system/unionflow_design_system.dart';
import '../../../../shared/design_system/components/uf_app_bar.dart';
import '../../../../core/constants/app_constants.dart';
import '../../../../features/organizations/domain/repositories/organization_repository.dart';


/// Annuaire des Membres — Design UnionFlow v2
///
/// Fonctionnalités :
/// - Identité violet #7616E8
/// - Header KPI 4 métriques (Total, % Actifs, En attente, Cotisations)
/// - Recherche inline collapsible + filtres chips
/// - Scroll infini (append pages au fur et à mesure)
/// - Mode grille / liste toggle
/// - Swipe gauche → Reset MDP  |  Swipe droit → Affecter org
/// - Long press → sélection multiple (Exporter, Affecter org)
/// - Navigation page complète au lieu d'une bottom sheet
class MembersPageWithDataAndPagination extends StatefulWidget {
  final List<Map<String, dynamic>> members;
  final int totalCount;
  final int currentPage;
  final int totalPages;
  final Function(int page, String? recherche) onPageChanged;
  final VoidCallback onRefresh;
  final void Function(String? query)? onSearch;
  final VoidCallback? onAddMember;
  /// null = SUPER_ADMIN (vue globale, affiche l'organisation sur chaque carte)
  final String? organisationId;
  final void Function(String memberId)? onActivateMember;
  final void Function(String memberId)? onResetPassword;
  final void Function(String memberId, String organisationId)? onAffecterOrganisation;
  final void Function(String memberId, String organisationId, String action, String? motif)? onLifecycleAction;
  /// Suppression définitive du compte (SuperAdmin uniquement — backend @RolesAllowed ADMIN/SUPER_ADMIN).
  final void Function(String memberId)? onDeleteAccount;

  const MembersPageWithDataAndPagination({
    super.key,
    required this.members,
    required this.totalCount,
    required this.currentPage,
    required this.totalPages,
    required this.onPageChanged,
    required this.onRefresh,
    this.onSearch,
    this.onAddMember,
    this.organisationId,
    this.onActivateMember,
    this.onResetPassword,
    this.onAffecterOrganisation,
    this.onLifecycleAction,
    this.onDeleteAccount,
  });

  @override
  State<MembersPageWithDataAndPagination> createState() => _MembersPageState();
}

class _MembersPageState extends State<MembersPageWithDataAndPagination> {
  final TextEditingController _searchController = TextEditingController();
  final ScrollController _scrollController = ScrollController();
  String _searchQuery = '';
  String _filterStatus = 'Tous';
  String _filterRole = 'Tous';
  Timer? _searchDebounce;

  bool _isGridView = false;
  bool _isSelectionMode = false;
  final Set<String> _selectedIds = {};
  bool _isLoadingMore = false;

  List<Map<String, dynamic>> _accumulatedMembers = [];
  List<Map<String, String>> _organisationsPicker = [];

  bool get _isSuperAdmin => widget.organisationId == null;

  @override
  void initState() {
    super.initState();
    _accumulatedMembers = List.from(widget.members);
    _scrollController.addListener(_onScroll);
  }

  @override
  void didUpdateWidget(covariant MembersPageWithDataAndPagination old) {
    super.didUpdateWidget(old);
    if (old.members != widget.members) {
      setState(() {
        if (widget.currentPage == 0) {
          _accumulatedMembers = List.from(widget.members);
        } else {
          // Append page suivante (dédoublonnage par id)
          final existingIds = _accumulatedMembers.map((m) => m['id'] as String? ?? '').toSet();
          final newItems = widget.members.where((m) => !existingIds.contains(m['id'] as String? ?? '')).toList();
          _accumulatedMembers.addAll(newItems);
        }
        _isLoadingMore = false;
      });
    }
  }

  @override
  void dispose() {
    _searchDebounce?.cancel();
    _searchController.dispose();
    _scrollController.dispose();
    super.dispose();
  }

  void _onScroll() {
    final pos = _scrollController.position;
    if (pos.pixels >= pos.maxScrollExtent - 200) {
      if (!_isLoadingMore && widget.currentPage < widget.totalPages - 1) {
        setState(() => _isLoadingMore = true);
        widget.onPageChanged(widget.currentPage + 1, _searchQuery.isEmpty ? null : _searchQuery);
      }
    }
  }

  void _clearSearch() {
    _searchDebounce?.cancel();
    _searchController.clear();
    setState(() => _searchQuery = '');
    widget.onSearch?.call(null);
  }

  void _toggleSelection(String id) {
    setState(() {
      if (_selectedIds.contains(id)) {
        _selectedIds.remove(id);
        if (_selectedIds.isEmpty) _isSelectionMode = false;
      } else {
        _selectedIds.add(id);
      }
    });
  }

  void _exitSelectionMode() {
    setState(() {
      _isSelectionMode = false;
      _selectedIds.clear();
    });
  }

  static const _roleFilterMapping = {
    'Admin': 'Administrateur Org',
    'Modérateur': 'Modérateur',
    'Membre Actif': 'Membre Actif',
    'Membre Simple': 'Membre Simple',
  };

  List<Map<String, dynamic>> get _filteredMembers {
    return _accumulatedMembers.where((m) {
      final matchesSearch = _searchQuery.isEmpty ||
          (m['name'] as String? ?? '').toLowerCase().contains(_searchQuery.toLowerCase()) ||
          (m['email'] as String? ?? '').toLowerCase().contains(_searchQuery.toLowerCase()) ||
          (m['numeroMembre'] as String? ?? '').toLowerCase().contains(_searchQuery.toLowerCase());
      final matchesStatus = _filterStatus == 'Tous' || m['status'] == _filterStatus;
      final matchesRole = _filterRole == 'Tous' ||
          (m['role'] as String? ?? '') == _roleFilterMapping[_filterRole];
      return matchesSearch && matchesStatus && matchesRole;
    }).toList();
  }

  // ═══════════════════════════════════════════════════════════════════════════
  // Build
  // ═══════════════════════════════════════════════════════════════════════════

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Theme.of(context).scaffoldBackgroundColor,
      appBar: _isSelectionMode ? _buildSelectionAppBar() : _buildMainAppBar(),
      body: Column(
        children: [
          _buildKpiHeader(context),
          _buildSearchAndFilters(context),
          Expanded(child: _buildContent(context)),
        ],
      ),
    );
  }

  // ─── AppBar principale ────────────────────────────────────────────────────

  PreferredSizeWidget _buildMainAppBar() {
    return UFAppBar(
      title: 'Annuaire Membres',
      moduleGradient: ModuleColors.membresGradient,
      actions: [
        IconButton(
          icon: Icon(_isGridView ? Icons.view_list_outlined : Icons.grid_view_outlined),
          onPressed: () => setState(() => _isGridView = !_isGridView),
          tooltip: _isGridView ? 'Vue liste' : 'Vue grille',
        ),
        if (widget.onAddMember != null)
          IconButton(
            icon: const Icon(Icons.person_add_outlined),
            onPressed: widget.onAddMember,
            tooltip: 'Ajouter un membre',
          ),
        IconButton(
          icon: const Icon(Icons.refresh),
          onPressed: () {
            setState(() => _accumulatedMembers.clear());
            widget.onRefresh();
          },
          tooltip: 'Rafraîchir',
        ),
        const SizedBox(width: 4),
      ],
    );
  }

  // ─── AppBar sélection multiple ────────────────────────────────────────────

  PreferredSizeWidget _buildSelectionAppBar() {
    return AppBar(
      backgroundColor: ModuleColors.membres,
      foregroundColor: AppColors.onPrimary,
      elevation: 0,
      iconTheme: const IconThemeData(color: AppColors.onPrimary),
      actionsIconTheme: const IconThemeData(color: AppColors.onPrimary),
      leading: IconButton(
        icon: const Icon(Icons.close),
        onPressed: _exitSelectionMode,
      ),
      title: Text(
        '${_selectedIds.length} sélectionné(s)',
        style: const TextStyle(color: AppColors.onPrimary, fontWeight: FontWeight.w600),
      ),
      actions: [
        if (_selectedIds.isNotEmpty && widget.onAffecterOrganisation != null && _isSuperAdmin)
          IconButton(
            icon: const Icon(Icons.business_outlined),
            tooltip: 'Affecter à une organisation',
            onPressed: _showBulkAffecterDialog,
          ),
        if (_selectedIds.isNotEmpty)
          IconButton(
            icon: const Icon(Icons.download_outlined),
            tooltip: 'Exporter la sélection',
            onPressed: _bulkExporter,
          ),
        const SizedBox(width: 4),
      ],
    );
  }

  // ─── Header KPI ────────────────────────────────────────────────────────────

  Widget _buildKpiHeader(BuildContext context) {
    final total = widget.totalCount;
    final displayed = _accumulatedMembers.length;
    final activeCount = _accumulatedMembers.where((m) => m['status'] == 'Actif').length;
    final pendingCount = _accumulatedMembers.where((m) => m['status'] == 'En attente').length;
    final cotisOkCount = _accumulatedMembers.where((m) => m['cotisationAJour'] == true).length;
    final activePercent = displayed > 0 ? activeCount / displayed : 0.0;
    final cotisPercent = displayed > 0 ? cotisOkCount / displayed : 0.0;

    return Container(
      padding: const EdgeInsets.fromLTRB(12, 8, 12, 10),
      decoration: BoxDecoration(
        color: Theme.of(context).colorScheme.surface,
        border: Border(bottom: BorderSide(color: Theme.of(context).colorScheme.outlineVariant, width: 1)),
      ),
      child: Row(
        children: [
          _kpiTile(context, 'Total', total.toString(), ModuleColors.membres, Icons.people_outline),
          _kpiSeparator(context),
          _kpiTileProgress(context, 'Actifs', '${(activePercent * 100).toStringAsFixed(0)}%', AppColors.success, activePercent),
          _kpiSeparator(context),
          _kpiTile(context, 'Attente', pendingCount.toString(), AppColors.warning, Icons.schedule_outlined),
          _kpiSeparator(context),
          _kpiTileProgress(
            context,
            'Cotisations',
            '${(cotisPercent * 100).toStringAsFixed(0)}%',
            cotisPercent >= 0.7 ? AppColors.success : AppColors.error,
            cotisPercent,
          ),
        ],
      ),
    );
  }

  Widget _kpiTile(BuildContext context, String label, String value, Color color, IconData icon) {
    return Expanded(
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          Icon(icon, size: 14, color: color),
          const SizedBox(height: 1),
          Text(value, style: TextStyle(fontSize: 17, fontWeight: FontWeight.w800, color: color)),
          Text(label, style: TextStyle(fontSize: 9, fontWeight: FontWeight.w600, color: color.withOpacity(0.75)), textAlign: TextAlign.center),
        ],
      ),
    );
  }

  Widget _kpiTileProgress(BuildContext context, String label, String value, Color color, double progress) {
    return Expanded(
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          Text(value, style: TextStyle(fontSize: 17, fontWeight: FontWeight.w800, color: color)),
          const SizedBox(height: 3),
          ClipRRect(
            borderRadius: BorderRadius.circular(2),
            child: LinearProgressIndicator(
              value: progress,
              backgroundColor: color.withOpacity(0.15),
              valueColor: AlwaysStoppedAnimation<Color>(color),
              minHeight: 4,
            ),
          ),
          const SizedBox(height: 2),
          Text(label, style: TextStyle(fontSize: 9, fontWeight: FontWeight.w600, color: color.withOpacity(0.75)), textAlign: TextAlign.center),
        ],
      ),
    );
  }

  Widget _kpiSeparator(BuildContext context) =>
      Container(width: 1, height: 42, color: Theme.of(context).colorScheme.outlineVariant);

  // ─── Recherche + Filtres (toujours visibles) ────────────────────────────

  Widget _buildSearchAndFilters(BuildContext context) {
    final hasFilter = _filterStatus != 'Tous' || _filterRole != 'Tous' || _searchQuery.isNotEmpty;
    return Container(
      padding: const EdgeInsets.fromLTRB(12, 8, 12, 10),
      decoration: BoxDecoration(
        color: Theme.of(context).colorScheme.surface,
        border: Border(bottom: BorderSide(color: Theme.of(context).colorScheme.outlineVariant, width: 1)),
      ),
      child: Column(
        mainAxisSize: MainAxisSize.min,
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          // Barre de recherche
          TextField(
            controller: _searchController,
            onChanged: (v) {
              setState(() => _searchQuery = v);
              _searchDebounce?.cancel();
              _searchDebounce = Timer(AppConstants.searchDebounce, () {
                widget.onSearch?.call(v.isEmpty ? null : v);
              });
            },
            style: TextStyle(fontSize: 14, color: Theme.of(context).colorScheme.onSurface),
            decoration: InputDecoration(
              hintText: 'Nom, email, numéro membre...',
              hintStyle: TextStyle(fontSize: 13, color: Theme.of(context).colorScheme.onSurfaceVariant),
              prefixIcon: Icon(Icons.search, size: 20, color: ModuleColors.membres),
              suffixIcon: _searchQuery.isNotEmpty
                  ? IconButton(icon: const Icon(Icons.clear, size: 18), onPressed: _clearSearch)
                  : null,
              contentPadding: const EdgeInsets.symmetric(vertical: 10, horizontal: 14),
              border: OutlineInputBorder(borderRadius: BorderRadius.circular(12), borderSide: BorderSide(color: Theme.of(context).colorScheme.outline)),
              enabledBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(12), borderSide: BorderSide(color: Theme.of(context).colorScheme.outline)),
              focusedBorder: const OutlineInputBorder(borderRadius: BorderRadius.all(Radius.circular(12)), borderSide: BorderSide(color: ModuleColors.membres, width: 1.5)),
              filled: true,
              fillColor: Theme.of(context).colorScheme.surfaceContainerHighest,
            ),
          ),
          const SizedBox(height: 8),

          // Chips statut
          SingleChildScrollView(
            scrollDirection: Axis.horizontal,
            child: Row(
              children: ['Tous', 'Actif', 'Inactif', 'En attente', 'Suspendu']
                  .map((f) => Padding(
                        padding: const EdgeInsets.only(right: 8),
                        child: _buildFilterChip(context, f, isStatus: true),
                      ))
                  .toList(),
            ),
          ),
          const SizedBox(height: 6),

          // Chips rôle
          SingleChildScrollView(
            scrollDirection: Axis.horizontal,
            child: Row(
              children: [
                Padding(
                  padding: const EdgeInsets.only(right: 6),
                  child: Icon(Icons.badge_outlined, size: 14, color: Theme.of(context).colorScheme.onSurfaceVariant),
                ),
                ...['Tous', 'Admin', 'Modérateur', 'Membre Actif', 'Membre Simple']
                    .map((f) => Padding(
                          padding: const EdgeInsets.only(right: 8),
                          child: _buildFilterChip(context, f, isStatus: false),
                        ))
                    .toList(),
              ],
            ),
          ),

          // Lien réinitialiser
          if (hasFilter)
            Padding(
              padding: const EdgeInsets.only(top: 6),
              child: GestureDetector(
                onTap: () {
                  setState(() {
                    _filterStatus = 'Tous';
                    _filterRole = 'Tous';
                    _searchQuery = '';
                    _searchController.clear();
                  });
                  widget.onSearch?.call(null);
                },
                child: Row(
                  mainAxisSize: MainAxisSize.min,
                  children: [
                    Icon(Icons.filter_list_off, size: 13, color: ModuleColors.membres),
                    const SizedBox(width: 4),
                    Text('Réinitialiser les filtres',
                        style: TextStyle(fontSize: 11, fontWeight: FontWeight.w600, color: ModuleColors.membres)),
                  ],
                ),
              ),
            ),
        ],
      ),
    );
  }

  Widget _buildFilterChip(BuildContext context, String label, {bool isStatus = true}) {
    final isSelected = isStatus ? _filterStatus == label : _filterRole == label;
    final accentColor = isStatus ? ModuleColors.membres : ModuleColors.organisationsDark;
    return GestureDetector(
      onTap: () => setState(() {
        if (isStatus) {
          _filterStatus = label;
        } else {
          _filterRole = label;
        }
      }),
      child: AnimatedContainer(
        duration: const Duration(milliseconds: 150),
        padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
        decoration: BoxDecoration(
          color: isSelected ? accentColor : Colors.transparent,
          borderRadius: BorderRadius.circular(20),
          border: Border.all(color: isSelected ? accentColor : Theme.of(context).colorScheme.outline, width: 1),
        ),
        child: Text(
          label,
          style: TextStyle(
            fontSize: 12,
            fontWeight: FontWeight.w600,
            color: isSelected ? AppColors.onPrimary : Theme.of(context).colorScheme.onSurfaceVariant,
          ),
        ),
      ),
    );
  }

  // ─── Contenu principal ────────────────────────────────────────────────────

  Widget _buildContent(BuildContext context) {
    final filtered = _filteredMembers;

    return RefreshIndicator(
      onRefresh: () async {
        setState(() => _accumulatedMembers.clear());
        widget.onRefresh();
      },
      color: ModuleColors.membres,
      child: filtered.isEmpty
          ? SingleChildScrollView(
              physics: const AlwaysScrollableScrollPhysics(),
              child: _buildEmptyState(context),
            )
          : _isGridView
              ? _buildGridView(context, filtered)
              : _buildListView(context, filtered),
    );
  }

  Widget _buildListView(BuildContext context, List<Map<String, dynamic>> members) {
    return ListView.separated(
      controller: _scrollController,
      padding: const EdgeInsets.fromLTRB(12, 12, 12, 80),
      itemCount: members.length + (_isLoadingMore ? 1 : 0),
      separatorBuilder: (_, __) => const SizedBox(height: 8),
      itemBuilder: (context, i) {
        if (i == members.length) {
          return const Center(
            child: Padding(
              padding: EdgeInsets.all(16),
              child: CircularProgressIndicator(color: ModuleColors.membres),
            ),
          );
        }
        return _buildSwipeableCard(context, members[i]);
      },
    );
  }

  Widget _buildGridView(BuildContext context, List<Map<String, dynamic>> members) {
    return GridView.builder(
      controller: _scrollController,
      padding: const EdgeInsets.fromLTRB(12, 12, 12, 80),
      gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
        crossAxisCount: 2,
        childAspectRatio: 0.82,
        crossAxisSpacing: 10,
        mainAxisSpacing: 10,
      ),
      itemCount: members.length + (_isLoadingMore ? 1 : 0),
      itemBuilder: (context, i) {
        if (i == members.length) {
          return const Center(child: CircularProgressIndicator(color: ModuleColors.membres));
        }
        return _buildGridCard(context, members[i]);
      },
    );
  }

  // ─── Carte liste avec swipe ────────────────────────────────────────────────

  /// Détermine l'action swipe gauche pour l'orgAdmin selon le statut du membre.
  /// Retourne null si aucune action n'est disponible (rôle admin, statut final, etc.).
  _SwipeAction? _getLeftSwipeAction(Map<String, dynamic> member) {
    // SuperAdmin : affecter org (géré séparément)
    if (_isSuperAdmin) return null;

    // Pas de lifecycle disponible
    if (widget.onLifecycleAction == null) return null;

    // Pas d'action sur un admin/superadmin
    final roleCode = (member['roleCode'] as String? ?? '').toUpperCase();
    if (roleCode == 'ORGADMIN' || roleCode == 'SUPERADMIN' ||
        roleCode == 'ADMIN_ORGANISATION' || roleCode == 'SUPER_ADMIN') {
      return null;
    }

    final statut = (member['statutMembre'] as String? ??
            member['status'] as String? ?? '')
        .toUpperCase();

    switch (statut) {
      case 'EN_ATTENTE_VALIDATION':
      case 'EN_ATTENTE':
      case 'INVITE':
        return const _SwipeAction(
          action: 'activer',
          icon: Icons.check_circle_outline,
          label: 'Activer',
          color: AppColors.success,
        );
      case 'ACTIF':
        return const _SwipeAction(
          action: 'suspendre',
          icon: Icons.pause_circle_outline,
          label: 'Suspendre',
          color: AppColors.warning,
        );
      case 'SUSPENDU':
        return const _SwipeAction(
          action: 'activer',
          icon: Icons.play_circle_outline,
          label: 'Réactiver',
          color: AppColors.info,
        );
      default:
        // RADIE, ARCHIVE, etc. → pas d'action rapide
        return null;
    }
  }

  Widget _buildSwipeableCard(BuildContext context, Map<String, dynamic> member) {
    final id = member['id'] as String? ?? '';
    if (_isSelectionMode) {
      return _buildListCard(context, member, isSelected: _selectedIds.contains(id));
    }

    // Swipe droite → Reset MDP (tous rôles admin si callback fourni)
    final canSwipeRight = widget.onResetPassword != null;

    // Swipe gauche → SuperAdmin: affecter org | OrgAdmin: lifecycle selon statut
    final bool canSwipeLeftSuperAdmin =
        _isSuperAdmin && widget.onAffecterOrganisation != null;
    final _SwipeAction? leftAction = _getLeftSwipeAction(member);
    final bool canSwipeLeft = canSwipeLeftSuperAdmin || leftAction != null;

    if (!canSwipeRight && !canSwipeLeft) {
      return _buildListCard(context, member);
    }

    // Background droite (Reset MDP) — toujours warning/orange
    final rightBg = _swipeActionBackground(
      isLeft: true,
      icon: Icons.lock_reset_outlined,
      label: 'Reset\nMDP',
      color: AppColors.warning,
    );

    // Background gauche — contextuel selon rôle
    Widget leftBg;
    if (canSwipeLeftSuperAdmin) {
      leftBg = _swipeActionBackground(
        isLeft: false,
        icon: Icons.business_outlined,
        label: 'Affecter\nOrg',
        color: ModuleColors.membres,
      );
    } else if (leftAction != null) {
      leftBg = _swipeActionBackground(
        isLeft: false,
        icon: leftAction.icon,
        label: leftAction.label,
        color: leftAction.color,
      );
    } else {
      leftBg = const SizedBox.shrink();
    }

    return Dismissible(
      key: Key('swipe_$id'),
      direction: canSwipeRight && canSwipeLeft
          ? DismissDirection.horizontal
          : canSwipeRight
              ? DismissDirection.startToEnd
              : DismissDirection.endToStart,
      confirmDismiss: (dir) async {
        if (dir == DismissDirection.startToEnd && canSwipeRight) {
          widget.onResetPassword!(id);
        } else if (dir == DismissDirection.endToStart) {
          if (canSwipeLeftSuperAdmin) {
            _showAffecterOrganisationDialog(context, member);
          } else if (leftAction != null) {
            final orgId = member['organisationId'] as String? ?? '';
            if (orgId.isNotEmpty) {
              widget.onLifecycleAction!(id, orgId, leftAction.action, null);
            }
          }
        }
        return false; // la carte ne disparaît pas
      },
      background: canSwipeRight ? rightBg : const SizedBox.shrink(),
      secondaryBackground: canSwipeLeft ? leftBg : const SizedBox.shrink(),
      child: _buildListCard(context, member),
    );
  }

  Widget _swipeActionBackground({
    required bool isLeft,
    required IconData icon,
    required String label,
    required Color color,
  }) {
    return Container(
      margin: const EdgeInsets.symmetric(vertical: 1),
      decoration: BoxDecoration(
        color: color.withOpacity(0.13),
        borderRadius: BorderRadius.circular(12),
      ),
      alignment: isLeft ? Alignment.centerLeft : Alignment.centerRight,
      padding: const EdgeInsets.symmetric(horizontal: 20),
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Icon(icon, color: color, size: 22),
          const SizedBox(height: 4),
          Text(
            label,
            style: TextStyle(
                fontSize: 10, fontWeight: FontWeight.w700, color: color),
            textAlign: TextAlign.center,
          ),
        ],
      ),
    );
  }

  // ─── Carte liste ──────────────────────────────────────────────────────────

  Widget _buildListCard(BuildContext context, Map<String, dynamic> member, {bool isSelected = false}) {
    final id = member['id'] as String? ?? '';
    final status = member['status'] as String? ?? '?';
    final orgName = member['organisationNom'] as String?;
    final numero = member['numeroMembre'] as String?;
    final cotisAJour = member['cotisationAJour'] as bool? ?? false;
    final statutKyc = member['statutKyc'] as String?;

    return GestureDetector(
      onTap: () {
        if (_isSelectionMode) {
          _toggleSelection(id);
        } else {
          _navigateToDetail(context, member);
        }
      },
      onLongPress: () {
        if (!_isSelectionMode) {
          setState(() {
            _isSelectionMode = true;
            _selectedIds.add(id);
          });
        }
      },
      child: AnimatedContainer(
        duration: const Duration(milliseconds: 150),
        padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
        decoration: BoxDecoration(
          color: isSelected ? ModuleColors.membres.withOpacity(0.08) : Theme.of(context).colorScheme.surface,
          borderRadius: BorderRadius.circular(12),
          border: Border.all(
            color: isSelected ? ModuleColors.membres : Theme.of(context).colorScheme.outlineVariant,
            width: isSelected ? 1.5 : 1,
          ),
        ),
        child: Row(
          children: [
            // Checkbox ou Avatar
            if (_isSelectionMode)
              Container(
                width: 36,
                height: 36,
                decoration: BoxDecoration(
                  shape: BoxShape.circle,
                  color: isSelected ? ModuleColors.membres : Colors.transparent,
                  border: Border.all(color: isSelected ? ModuleColors.membres : Theme.of(context).colorScheme.outline, width: 2),
                ),
                child: isSelected ? const Icon(Icons.check, size: 18, color: AppColors.onPrimary) : null,
              )
            else
              _buildAvatarWidget(member, 36),
            const SizedBox(width: 12),
            // Infos
            Expanded(
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Row(
                    children: [
                      Expanded(
                        child: Text(
                          member['name'] as String? ?? 'Inconnu',
                          style: TextStyle(fontSize: 14, fontWeight: FontWeight.w600, color: Theme.of(context).colorScheme.onSurface),
                          overflow: TextOverflow.ellipsis,
                        ),
                      ),
                      if (numero != null && numero.isNotEmpty) ...[
                        const SizedBox(width: 6),
                        Text(
                          numero,
                          style: TextStyle(fontSize: 10, fontWeight: FontWeight.w500, color: Theme.of(context).colorScheme.onSurfaceVariant),
                        ),
                      ],
                    ],
                  ),
                  const SizedBox(height: 2),
                  Text(
                    member['role'] as String? ?? 'Membre',
                    style: TextStyle(fontSize: 12, color: Theme.of(context).colorScheme.onSurfaceVariant),
                  ),
                  if (_isSuperAdmin && orgName != null && orgName.isNotEmpty) ...[
                    const SizedBox(height: 3),
                    Row(
                      children: [
                        const Icon(Icons.business_outlined, size: 11, color: ModuleColors.membres),
                        const SizedBox(width: 4),
                        Expanded(
                          child: Text(
                            orgName,
                            style: const TextStyle(fontSize: 11, color: ModuleColors.membres, fontWeight: FontWeight.w500),
                            overflow: TextOverflow.ellipsis,
                          ),
                        ),
                      ],
                    ),
                  ],
                  // Indicateurs KYC + Cotisation
                  const SizedBox(height: 5),
                  Row(
                    children: [
                      _miniIndicator(
                        cotisAJour ? Icons.payments_outlined : Icons.money_off_outlined,
                        cotisAJour ? AppColors.success : AppColors.error,
                        cotisAJour ? 'Cotis. OK' : 'Cotis. NOK',
                      ),
                      if (statutKyc != null) ...[
                        const SizedBox(width: 5),
                        _kycMiniIndicator(statutKyc),
                      ],
                    ],
                  ),
                ],
              ),
            ),
            const SizedBox(width: 8),
            _statusBadge(status),
          ],
        ),
      ),
    );
  }

  Widget _miniIndicator(IconData icon, Color color, String label) {
    return Container(
      padding: const EdgeInsets.symmetric(horizontal: 5, vertical: 2),
      decoration: BoxDecoration(
        color: color.withOpacity(0.1),
        borderRadius: BorderRadius.circular(6),
        border: Border.all(color: color.withOpacity(0.3), width: 0.5),
      ),
      child: Row(
        mainAxisSize: MainAxisSize.min,
        children: [
          Icon(icon, size: 10, color: color),
          const SizedBox(width: 3),
          Text(label, style: TextStyle(fontSize: 9, fontWeight: FontWeight.w600, color: color)),
        ],
      ),
    );
  }

  Widget _kycMiniIndicator(String statutKyc) {
    final (Color color, IconData icon) = switch (statutKyc) {
      'VERIFIE' => (AppColors.success, Icons.verified_user_outlined),
      'EN_COURS' => (AppColors.warning, Icons.pending_outlined),
      'REJETE'  => (AppColors.error, Icons.gpp_bad_outlined),
      _          => (AppColors.textTertiary, Icons.help_outline),
    };
    return _miniIndicator(icon, color, 'KYC');
  }

  // ─── Carte grille ─────────────────────────────────────────────────────────

  Widget _buildGridCard(BuildContext context, Map<String, dynamic> member) {
    final id = member['id'] as String? ?? '';
    final status = member['status'] as String? ?? '?';
    final cotisAJour = member['cotisationAJour'] as bool? ?? false;
    final statutKyc = member['statutKyc'] as String?;
    final isSelected = _selectedIds.contains(id);

    return GestureDetector(
      onTap: () => _isSelectionMode ? _toggleSelection(id) : _navigateToDetail(context, member),
      onLongPress: () {
        if (!_isSelectionMode) {
          setState(() { _isSelectionMode = true; _selectedIds.add(id); });
        }
      },
      child: AnimatedContainer(
        duration: const Duration(milliseconds: 150),
        decoration: BoxDecoration(
          color: isSelected ? ModuleColors.membres.withOpacity(0.08) : Theme.of(context).colorScheme.surface,
          borderRadius: BorderRadius.circular(14),
          border: Border.all(
            color: isSelected ? ModuleColors.membres : Theme.of(context).colorScheme.outlineVariant,
            width: isSelected ? 1.5 : 1,
          ),
        ),
        child: Padding(
          padding: const EdgeInsets.all(12),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Stack(
                children: [
                  _buildAvatarWidget(member, 48),
                  if (isSelected)
                    Positioned(
                      right: 0,
                      bottom: 0,
                      child: Container(
                        width: 18,
                        height: 18,
                        decoration: const BoxDecoration(color: ModuleColors.membres, shape: BoxShape.circle),
                        child: const Icon(Icons.check, size: 12, color: AppColors.onPrimary),
                      ),
                    ),
                ],
              ),
              const SizedBox(height: 8),
              Text(
                member['name'] as String? ?? 'Inconnu',
                style: TextStyle(fontSize: 12, fontWeight: FontWeight.w600, color: Theme.of(context).colorScheme.onSurface),
                textAlign: TextAlign.center,
                maxLines: 2,
                overflow: TextOverflow.ellipsis,
              ),
              const SizedBox(height: 5),
              _statusBadge(status),
              const SizedBox(height: 6),
              Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  Icon(cotisAJour ? Icons.payments_outlined : Icons.money_off_outlined, size: 14, color: cotisAJour ? AppColors.success : AppColors.error),
                  if (statutKyc != null) ...[
                    const SizedBox(width: 6),
                    Icon(
                      switch (statutKyc) {
                        'VERIFIE' => Icons.verified_user_outlined,
                        'EN_COURS' => Icons.pending_outlined,
                        _ => Icons.gpp_bad_outlined,
                      },
                      size: 14,
                      color: switch (statutKyc) {
                        'VERIFIE' => AppColors.success,
                        'EN_COURS' => AppColors.warning,
                        _ => AppColors.error,
                      },
                    ),
                  ],
                ],
              ),
            ],
          ),
        ),
      ),
    );
  }

  // ─── Avatar violet ────────────────────────────────────────────────────────

  Widget _buildAvatarWidget(Map<String, dynamic> member, double size) {
    return Container(
      width: size,
      height: size,
      decoration: const BoxDecoration(
        gradient: LinearGradient(colors: [ModuleColors.membresDark, ModuleColors.membres], begin: Alignment.topLeft, end: Alignment.bottomRight),
        shape: BoxShape.circle,
      ),
      alignment: Alignment.center,
      child: Text(
        member['initiales'] as String? ?? '??',
        style: TextStyle(color: AppColors.onPrimary, fontWeight: FontWeight.w700, fontSize: size * 0.36),
      ),
    );
  }

  // ─── Badge statut ─────────────────────────────────────────────────────────

  Widget _statusBadge(String status) {
    final (Color color, IconData icon) = switch (status) {
      'Actif'      => (AppColors.success, Icons.check_circle_outline),
      'Inactif'    => (AppColors.error, Icons.cancel_outlined),
      'En attente' => (AppColors.warning, Icons.schedule_outlined),
      'Suspendu'   => (AppColors.textTertiary, Icons.block_outlined),
      _            => (AppColors.textTertiary, Icons.help_outline),
    };
    return Container(
      padding: const EdgeInsets.symmetric(horizontal: 7, vertical: 3),
      decoration: BoxDecoration(
        color: color.withOpacity(0.1),
        borderRadius: BorderRadius.circular(10),
        border: Border.all(color: color.withOpacity(0.3), width: 1),
      ),
      child: Row(
        mainAxisSize: MainAxisSize.min,
        children: [
          Icon(icon, size: 10, color: color),
          const SizedBox(width: 3),
          Text(status, style: TextStyle(fontSize: 10, fontWeight: FontWeight.w600, color: color)),
        ],
      ),
    );
  }

  // ─── Empty state enrichi ──────────────────────────────────────────────────

  Widget _buildEmptyState(BuildContext context) {
    final hasFilters = _filterStatus != 'Tous' || _filterRole != 'Tous' || _searchQuery.isNotEmpty;
    return Center(
      child: Padding(
        padding: const EdgeInsets.all(40),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Container(
              padding: const EdgeInsets.all(20),
              decoration: BoxDecoration(color: ModuleColors.membres.withOpacity(0.08), shape: BoxShape.circle),
              child: Icon(
                hasFilters ? Icons.filter_list_off : Icons.people_outline,
                size: 44,
                color: ModuleColors.membres,
              ),
            ),
            const SizedBox(height: 20),
            Text(
              hasFilters ? 'Aucun résultat' : 'Aucun membre',
              style: TextStyle(fontSize: 16, fontWeight: FontWeight.w700, color: Theme.of(context).colorScheme.onSurface),
            ),
            const SizedBox(height: 8),
            Text(
              hasFilters
                  ? 'Aucun membre ne correspond à votre recherche ou filtre.'
                  : 'Aucun membre enregistré pour le moment.',
              textAlign: TextAlign.center,
              style: TextStyle(fontSize: 13, height: 1.5, color: Theme.of(context).colorScheme.onSurfaceVariant),
            ),
            const SizedBox(height: 24),
            if (hasFilters)
              FilledButton.icon(
                onPressed: () {
                  setState(() { _filterStatus = 'Tous'; _filterRole = 'Tous'; _searchQuery = ''; _searchController.clear(); });
                  widget.onSearch?.call(null);
                },
                icon: const Icon(Icons.filter_list_off, size: 18),
                label: const Text('Effacer les filtres'),
                style: FilledButton.styleFrom(backgroundColor: ModuleColors.membres),
              )
            else if (widget.onAddMember != null)
              FilledButton.icon(
                onPressed: widget.onAddMember,
                icon: const Icon(Icons.person_add_outlined, size: 18),
                label: const Text('Ajouter un membre'),
                style: FilledButton.styleFrom(backgroundColor: ModuleColors.membres),
              ),
          ],
        ),
      ),
    );
  }

  // ─── Navigation vers page de détail ──────────────────────────────────────

  void _navigateToDetail(BuildContext context, Map<String, dynamic> member) {
    Navigator.of(context).push(MaterialPageRoute(
      builder: (_) => MemberDetailPage(
        member: member,
        isSuperAdmin: _isSuperAdmin,
        onActivateMember: widget.onActivateMember,
        onResetPassword: widget.onResetPassword,
        onAffecterOrganisation: widget.onAffecterOrganisation,
        onLifecycleAction: widget.onLifecycleAction,
        onDeleteAccount: widget.onDeleteAccount,
        organisationsPicker: _organisationsPicker,
        onOrganisationsLoaded: (orgs) => setState(() => _organisationsPicker = orgs),
      ),
    ));
  }

  // ─── Bulk actions ─────────────────────────────────────────────────────────

  Future<void> _showBulkAffecterDialog() async {
    await _loadOrganisationsPicker();
    if (!mounted) return;
    String? selectedOrgId;
    await showDialog<void>(
      context: context,
      builder: (ctx) => StatefulBuilder(
        builder: (ctx, set) => AlertDialog(
          title: Text('Affecter ${_selectedIds.length} membre(s)'),
          content: _organisationsPicker.isEmpty
              ? const Text('Aucune organisation disponible.')
              : DropdownButtonFormField<String>(
                  decoration: const InputDecoration(labelText: 'Organisation'),
                  items: _organisationsPicker
                      .map((o) => DropdownMenuItem(value: o['id'], child: Text(o['nom']!)))
                      .toList(),
                  onChanged: (v) => set(() => selectedOrgId = v),
                ),
          actions: [
            TextButton(onPressed: () => Navigator.pop(ctx), child: const Text('Annuler')),
            ElevatedButton(
              style: ElevatedButton.styleFrom(backgroundColor: ModuleColors.membres, foregroundColor: AppColors.onPrimary),
              onPressed: selectedOrgId == null
                  ? null
                  : () {
                      Navigator.pop(ctx);
                      for (final id in _selectedIds) {
                        widget.onAffecterOrganisation!(id, selectedOrgId!);
                      }
                      _exitSelectionMode();
                    },
              child: const Text('Confirmer'),
            ),
          ],
        ),
      ),
    );
  }

  void _bulkExporter() {
    final count = _selectedIds.length;
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(
        content: Text('Export de $count membre(s) — fonctionnalité à venir'),
        backgroundColor: ModuleColors.membres,
        duration: const Duration(seconds: 3),
      ),
    );
    _exitSelectionMode();
  }

  Future<void> _showAffecterOrganisationDialog(BuildContext ctx, Map<String, dynamic> member) async {
    await _loadOrganisationsPicker();
    if (!mounted) return;
    String? selectedOrgId;
    await showDialog<void>(
      context: ctx,
      builder: (dialogCtx) => StatefulBuilder(
        builder: (dialogCtx, set) => AlertDialog(
          title: const Text('Affecter à une organisation'),
          content: _organisationsPicker.isEmpty
              ? const Text('Aucune organisation disponible.')
              : DropdownButtonFormField<String>(
                  decoration: const InputDecoration(labelText: 'Organisation'),
                  items: _organisationsPicker
                      .map((o) => DropdownMenuItem(value: o['id'], child: Text(o['nom']!)))
                      .toList(),
                  onChanged: (v) => set(() => selectedOrgId = v),
                ),
          actions: [
            TextButton(onPressed: () => Navigator.pop(dialogCtx), child: const Text('Annuler')),
            ElevatedButton(
              style: ElevatedButton.styleFrom(backgroundColor: ModuleColors.membres, foregroundColor: AppColors.onPrimary),
              onPressed: selectedOrgId == null
                  ? null
                  : () {
                      Navigator.pop(dialogCtx);
                      widget.onAffecterOrganisation!(member['id'] as String, selectedOrgId!);
                    },
              child: const Text('Confirmer'),
            ),
          ],
        ),
      ),
    );
  }

  Future<void> _loadOrganisationsPicker() async {
    if (_organisationsPicker.isNotEmpty) return;
    try {
      final repo = GetIt.instance<IOrganizationRepository>();
      final orgs = await repo.getOrganizations(page: 0, size: 100);
      if (mounted) {
        setState(() {
          _organisationsPicker = orgs
              .where((o) => o.id != null && o.id!.isNotEmpty)
              .map((o) => {'id': o.id!, 'nom': o.nomAffichage})
              .toList();
        });
      }
    } catch (_) {}
  }
}

// ═══════════════════════════════════════════════════════════════════════════════
// Page de détail membre (navigation complète)
// ═══════════════════════════════════════════════════════════════════════════════

class MemberDetailPage extends StatefulWidget {
  final Map<String, dynamic> member;
  final bool isSuperAdmin;
  final void Function(String memberId)? onActivateMember;
  final void Function(String memberId)? onResetPassword;
  final void Function(String memberId, String organisationId)? onAffecterOrganisation;
  final void Function(String memberId, String organisationId, String action, String? motif)? onLifecycleAction;
  final void Function(String memberId)? onDeleteAccount;
  final List<Map<String, String>> organisationsPicker;
  final void Function(List<Map<String, String>> orgs) onOrganisationsLoaded;

  const MemberDetailPage({
    super.key,
    required this.member,
    required this.isSuperAdmin,
    this.onActivateMember,
    this.onResetPassword,
    this.onAffecterOrganisation,
    this.onLifecycleAction,
    this.onDeleteAccount,
    required this.organisationsPicker,
    required this.onOrganisationsLoaded,
  });

  @override
  State<MemberDetailPage> createState() => _MemberDetailPageState();
}

class _MemberDetailPageState extends State<MemberDetailPage> {
  late List<Map<String, String>> _orgs;

  @override
  void initState() {
    super.initState();
    _orgs = List.from(widget.organisationsPicker);
  }

  @override
  Widget build(BuildContext context) {
    final m = widget.member;
    final name = m['name'] as String? ?? '';
    final role = m['role'] as String? ?? 'Membre';
    final status = m['status'] as String? ?? '?';
    final numero = m['numeroMembre'] as String?;
    final email = m['email'] as String? ?? '—';
    final phone = m['phone'] as String? ?? '';
    final orgNom = m['organisationNom'] as String?;
    final dateAdhesion = m['joinDate'];
    final profession = m['department'] as String? ?? '';
    final nationalite = m['nationalite'] as String? ?? '';
    final location = (m['location'] as String? ?? '').trim();
    final cotisAJour = m['cotisationAJour'] as bool? ?? false;
    final statutKyc = m['statutKyc'] as String?;
    final membreBureau = m['membreBureau'] as bool? ?? false;
    final responsable = m['responsable'] as bool? ?? false;
    final fonctionBureau = m['fonctionBureau'] as String?;
    final eventsCount = m['eventsAttended'] as int? ?? 0;

    return Scaffold(
      backgroundColor: Theme.of(context).scaffoldBackgroundColor,
      body: CustomScrollView(
        slivers: [
          // ── Hero AppBar violet ───────────────────────────────────────────
          SliverAppBar(
            expandedHeight: 210,
            pinned: true,
            backgroundColor: ModuleColors.membres,
            foregroundColor: AppColors.onPrimary,
            iconTheme: const IconThemeData(color: Colors.white),
            actionsIconTheme: const IconThemeData(color: Colors.white),
            actions: [
              if (widget.onResetPassword != null)
                IconButton(
                  icon: const Icon(Icons.lock_reset_outlined),
                  tooltip: 'Réinitialiser le mot de passe',
                  onPressed: () {
                    Navigator.pop(context);
                    widget.onResetPassword!(m['id'] as String);
                  },
                ),
              const SizedBox(width: 4),
            ],
            flexibleSpace: FlexibleSpaceBar(
              background: Container(
                decoration: const BoxDecoration(
                  gradient: LinearGradient(
                    colors: [ModuleColors.membresDark, ModuleColors.membres],
                    begin: Alignment.topLeft,
                    end: Alignment.bottomRight,
                  ),
                ),
                child: SafeArea(
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: [
                      const SizedBox(height: 32),
                      Container(
                        width: 74,
                        height: 74,
                        decoration: BoxDecoration(
                          shape: BoxShape.circle,
                          border: Border.all(color: Colors.white.withOpacity(0.45), width: 2.5),
                          gradient: const LinearGradient(
                            colors: [ModuleColors.membresDark, ModuleColors.membres],
                            begin: Alignment.topLeft,
                            end: Alignment.bottomRight,
                          ),
                        ),
                        alignment: Alignment.center,
                        child: Text(
                          m['initiales'] as String? ?? '??',
                          style: const TextStyle(color: Colors.white, fontWeight: FontWeight.w900, fontSize: 28),
                        ),
                      ),
                      const SizedBox(height: 10),
                      Text(name, style: const TextStyle(color: Colors.white, fontSize: 18, fontWeight: FontWeight.w700)),
                      const SizedBox(height: 4),
                      Row(
                        mainAxisAlignment: MainAxisAlignment.center,
                        children: [
                          Text(role, style: TextStyle(color: Colors.white.withOpacity(0.85), fontSize: 13)),
                          if (numero != null && numero.isNotEmpty) ...[
                            Text(' · ', style: TextStyle(color: Colors.white.withOpacity(0.5))),
                            Text(numero, style: TextStyle(color: Colors.white.withOpacity(0.75), fontSize: 12)),
                          ],
                        ],
                      ),
                    ],
                  ),
                ),
              ),
            ),
          ),
          // ── Contenu ──────────────────────────────────────────────────────
          SliverToBoxAdapter(
            child: Padding(
              padding: const EdgeInsets.fromLTRB(16, 16, 16, 40),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  // Badges statut / cotisation / KYC
                  Wrap(
                    spacing: 8,
                    runSpacing: 6,
                    children: [
                      _detailStatusBadge(context, status),
                      _badgeChip(
                        context,
                        cotisAJour ? Icons.payments_outlined : Icons.money_off_outlined,
                        cotisAJour ? AppColors.success : AppColors.error,
                        cotisAJour ? 'Cotisation OK' : 'Cotisation en retard',
                      ),
                      if (statutKyc != null) _kycBadge(context, statutKyc),
                      if (membreBureau) _badgeChip(context, Icons.star_outline, AppColors.warningUI, fonctionBureau ?? 'Bureau'),
                      if (responsable) _badgeChip(context, Icons.manage_accounts_outlined, ModuleColors.membres, 'Responsable'),
                    ],
                  ),
                  const SizedBox(height: 20),

                  // Contact
                  _sectionCard(context, 'Contact', [
                    _detailRow(context, Icons.email_outlined, 'Email', email),
                    if (phone.isNotEmpty) _detailRow(context, Icons.phone_outlined, 'Téléphone', phone),
                  ]),
                  const SizedBox(height: 12),

                  // Organisation
                  if (orgNom != null || dateAdhesion != null || eventsCount > 0)
                    _sectionCard(context, 'Organisation', [
                      if (orgNom != null) _detailRow(context, Icons.business_outlined, 'Organisation', orgNom),
                      if (dateAdhesion != null) _detailRow(context, Icons.calendar_today_outlined, 'Adhésion', _fmt(dateAdhesion)),
                      if (eventsCount > 0) _detailRow(context, Icons.event_outlined, 'Événements participés', eventsCount.toString()),
                    ]),
                  if (orgNom != null || dateAdhesion != null || eventsCount > 0) const SizedBox(height: 12),

                  // Profil
                  if (profession.isNotEmpty || nationalite.isNotEmpty || (location != ',' && location.isNotEmpty))
                    _sectionCard(context, 'Profil', [
                      if (profession.isNotEmpty) _detailRow(context, Icons.work_outline, 'Profession', profession),
                      if (nationalite.isNotEmpty) _detailRow(context, Icons.flag_outlined, 'Nationalité', nationalite),
                      if (location.isNotEmpty && location != ',') _detailRow(context, Icons.location_on_outlined, 'Localisation', location),
                    ]),
                  if (profession.isNotEmpty || nationalite.isNotEmpty || (location != ',' && location.isNotEmpty)) const SizedBox(height: 20),

                  // Actions
                  _sectionLabel(context, 'Actions'),
                  const SizedBox(height: 10),
                  if (status == 'En attente' && widget.onActivateMember != null)
                    _actionBtn(context, 'Activer le membre', Icons.check_circle_outline, AppColors.success, () {
                      Navigator.pop(context);
                      widget.onActivateMember!(m['id'] as String);
                    }),
                  if (widget.onResetPassword != null)
                    _actionBtn(context, 'Réinitialiser le mot de passe', Icons.lock_reset_outlined, AppColors.warning, () {
                      Navigator.pop(context);
                      widget.onResetPassword!(m['id'] as String);
                    }, outlined: true),
                  if (widget.isSuperAdmin &&
                      widget.onAffecterOrganisation != null &&
                      (m['organisationId'] == null || (m['organisationId'] as String).isEmpty))
                    _actionBtn(context, 'Affecter à une organisation', Icons.business_outlined, ModuleColors.membres, () => _showAffecterDialog(context), outlined: true),
                  if (widget.onLifecycleAction != null)
                    ..._lifecycleButtons(context, m),
                  // Suppression définitive — SuperAdmin uniquement, ET membre encore actif
                  if (widget.isSuperAdmin &&
                      widget.onDeleteAccount != null &&
                      (m['actif'] as bool? ?? true)) ...[
                    const SizedBox(height: 12),
                    const Divider(height: 1),
                    const SizedBox(height: 12),
                    _actionBtn(
                      context,
                      'Supprimer ce compte',
                      Icons.delete_forever_outlined,
                      AppColors.error,
                      () => _confirmDeleteAccount(context, m),
                      outlined: true,
                    ),
                  ],
                  // Bannière "Compte désactivé" si le membre a été désactivé
                  if ((m['actif'] as bool? ?? true) == false) ...[
                    const SizedBox(height: 12),
                    Container(
                      width: double.infinity,
                      padding: const EdgeInsets.all(12),
                      decoration: BoxDecoration(
                        color: AppColors.error.withOpacity(
                            Theme.of(context).brightness == Brightness.dark ? 0.15 : 0.08),
                        borderRadius: BorderRadius.circular(10),
                        border: Border.all(color: AppColors.error.withOpacity(0.3)),
                      ),
                      child: Row(
                        children: [
                          const Icon(Icons.block_outlined, color: AppColors.error, size: 18),
                          const SizedBox(width: 10),
                          Expanded(
                            child: Column(
                              crossAxisAlignment: CrossAxisAlignment.start,
                              children: [
                                const Text(
                                  'Compte désactivé',
                                  style: TextStyle(
                                      fontSize: 13,
                                      fontWeight: FontWeight.w700,
                                      color: AppColors.error),
                                ),
                                Text(
                                  'Ce compte a été supprimé et ne peut plus se connecter.',
                                  style: TextStyle(
                                      fontSize: 11,
                                      color: Theme.of(context).brightness == Brightness.dark
                                          ? AppColors.textSecondaryDark
                                          : AppColors.textSecondary),
                                ),
                              ],
                            ),
                          ),
                        ],
                      ),
                    ),
                  ],
                ],
              ),
            ),
          ),
        ],
      ),
    );
  }

  // ── Helpers UI ─────────────────────────────────────────────────────────────

  Widget _sectionCard(BuildContext context, String label, List<Widget> children) {
    if (children.isEmpty) return const SizedBox.shrink();
    return Container(
      decoration: BoxDecoration(
        color: Theme.of(context).colorScheme.surface,
        borderRadius: BorderRadius.circular(14),
        border: Border.all(color: Theme.of(context).colorScheme.outlineVariant, width: 1),
      ),
      padding: const EdgeInsets.fromLTRB(16, 12, 16, 4),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          _sectionLabel(context, label),
          const SizedBox(height: 10),
          ...children,
        ],
      ),
    );
  }

  Widget _sectionLabel(BuildContext context, String text) {
    return Text(
      text.toUpperCase(),
      style: const TextStyle(fontSize: 11, fontWeight: FontWeight.w700, color: ModuleColors.membres, letterSpacing: 0.8),
    );
  }

  Widget _detailRow(BuildContext context, IconData icon, String label, String value) {
    return Padding(
      padding: const EdgeInsets.only(bottom: 10),
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Icon(icon, size: 16, color: ModuleColors.membres),
          const SizedBox(width: 10),
          Expanded(
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text(label, style: TextStyle(fontSize: 11, color: Theme.of(context).colorScheme.onSurfaceVariant)),
                const SizedBox(height: 2),
                Text(value, style: TextStyle(fontSize: 14, color: Theme.of(context).colorScheme.onSurface, fontWeight: FontWeight.w500)),
              ],
            ),
          ),
        ],
      ),
    );
  }

  Widget _badgeChip(BuildContext context, IconData icon, Color color, String label) {
    return Container(
      padding: const EdgeInsets.symmetric(horizontal: 9, vertical: 5),
      decoration: BoxDecoration(
        color: color.withOpacity(0.1),
        borderRadius: BorderRadius.circular(10),
        border: Border.all(color: color.withOpacity(0.35), width: 1),
      ),
      child: Row(
        mainAxisSize: MainAxisSize.min,
        children: [
          Icon(icon, size: 12, color: color),
          const SizedBox(width: 5),
          Text(label, style: TextStyle(fontSize: 11, fontWeight: FontWeight.w600, color: color)),
        ],
      ),
    );
  }

  Widget _kycBadge(BuildContext context, String statutKyc) {
    final (Color color, IconData icon, String label) = switch (statutKyc) {
      'VERIFIE' => (AppColors.success, Icons.verified_user_outlined, 'KYC Vérifié'),
      'EN_COURS' => (AppColors.warning, Icons.pending_outlined, 'KYC En cours'),
      'REJETE'  => (AppColors.error, Icons.gpp_bad_outlined, 'KYC Rejeté'),
      _          => (AppColors.textTertiary, Icons.help_outline, 'KYC Inconnu'),
    };
    return _badgeChip(context, icon, color, label);
  }

  Widget _detailStatusBadge(BuildContext context, String status) {
    final (Color color, IconData icon) = switch (status) {
      'Actif'      => (AppColors.success, Icons.check_circle_outline),
      'Inactif'    => (AppColors.error, Icons.cancel_outlined),
      'En attente' => (AppColors.warning, Icons.schedule_outlined),
      'Suspendu'   => (AppColors.textTertiary, Icons.block_outlined),
      _            => (AppColors.textTertiary, Icons.help_outline),
    };
    return Container(
      padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
      decoration: BoxDecoration(
        color: color.withOpacity(0.12),
        borderRadius: BorderRadius.circular(12),
        border: Border.all(color: color.withOpacity(0.4), width: 1),
      ),
      child: Row(
        mainAxisSize: MainAxisSize.min,
        children: [
          Icon(icon, size: 13, color: color),
          const SizedBox(width: 5),
          Text(status, style: TextStyle(fontSize: 12, fontWeight: FontWeight.w700, color: color)),
        ],
      ),
    );
  }

  Widget _actionBtn(BuildContext context, String label, IconData icon, Color color, VoidCallback onPressed, {bool outlined = false}) {
    return Padding(
      padding: const EdgeInsets.only(bottom: 10),
      child: SizedBox(
        width: double.infinity,
        child: outlined
            ? OutlinedButton.icon(
                onPressed: onPressed,
                icon: Icon(icon, size: 18),
                label: Text(label, style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w600)),
                style: OutlinedButton.styleFrom(
                  foregroundColor: color,
                  side: BorderSide(color: color),
                  padding: const EdgeInsets.symmetric(vertical: 13),
                  shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
                ),
              )
            : ElevatedButton.icon(
                onPressed: onPressed,
                icon: Icon(icon, size: 18),
                label: Text(label, style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w600)),
                style: ElevatedButton.styleFrom(
                  backgroundColor: color,
                  foregroundColor: AppColors.onPrimary,
                  padding: const EdgeInsets.symmetric(vertical: 13),
                  shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
                ),
              ),
      ),
    );
  }

  List<Widget> _lifecycleButtons(BuildContext context, Map<String, dynamic> m) {
    final memberId = m['id'] as String? ?? '';
    final statut = m['statutMembre'] as String? ?? m['status'] as String? ?? '';
    // Organisation du membre — utilisée pour les actions lifecycle.
    // En contexte orgAdmin, c'est l'org fixe ; en superAdmin, on prend l'org du membre.
    final orgId = m['organisationId'] as String? ?? '';

    // Un orgAdmin ne peut pas agir sur un autre admin ou super-admin.
    // Le superAdmin peut agir sur tout le monde — pas de restriction.
    final roleCode = (m['roleCode'] as String? ?? '').toUpperCase();
    final cibleEstAdmin = roleCode == 'ORGADMIN'
        || roleCode == 'SUPERADMIN'
        || roleCode == 'ADMIN_ORGANISATION'
        || roleCode == 'SUPER_ADMIN';
    if (cibleEstAdmin && !widget.isSuperAdmin) return const [];

    // Si on n'a pas d'org pour ce membre, impossible d'envoyer les actions lifecycle
    if (orgId.isEmpty) return const [];

    return [
      if (statut == 'INVITE' || statut == 'EN_ATTENTE_VALIDATION' || statut == 'En attente')
        _actionBtn(context, "Activer l'adhésion", Icons.check_circle_outline, AppColors.success, () {
          Navigator.pop(context);
          widget.onLifecycleAction!(memberId, orgId, 'activer', null);
        }),
      if (statut == 'ACTIF' || statut == 'Actif')
        _actionBtn(context, "Suspendre l'adhésion", Icons.pause_circle_outline, AppColors.warning, () {
          _showMotifDialog(context, "Suspendre l'adhésion",
              onConfirm: (motif) => widget.onLifecycleAction!(memberId, orgId, 'suspendre', motif));
        }, outlined: true),
      if (statut == 'SUSPENDU' || statut == 'Suspendu')
        _actionBtn(context, "Réactiver l'adhésion", Icons.play_circle_outline, AppColors.info, () {
          Navigator.pop(context);
          widget.onLifecycleAction!(memberId, orgId, 'activer', null);
        }),
      if (statut != 'RADIE' && statut != 'ARCHIVE' && statut.isNotEmpty)
        _actionBtn(context, "Radier de l'organisation", Icons.block_outlined, AppColors.error, () {
          _showMotifDialog(context, 'Radier le membre',
              onConfirm: (motif) => widget.onLifecycleAction!(memberId, orgId, 'radier', motif));
        }, outlined: true),
    ];
  }

  void _showMotifDialog(BuildContext context, String titre, {required void Function(String? motif) onConfirm}) {
    final ctrl = TextEditingController();
    showDialog<void>(
      context: context,
      builder: (ctx) => AlertDialog(
        title: Text(titre),
        content: TextField(
          controller: ctrl,
          decoration: const InputDecoration(labelText: 'Motif (optionnel)', border: OutlineInputBorder()),
          maxLines: 3,
        ),
        actions: [
          TextButton(onPressed: () => Navigator.pop(ctx), child: const Text('Annuler')),
          ElevatedButton(
            style: ElevatedButton.styleFrom(backgroundColor: ModuleColors.membres, foregroundColor: AppColors.onPrimary),
            onPressed: () {
              Navigator.pop(ctx);
              Navigator.pop(context);
              onConfirm(ctrl.text.isNotEmpty ? ctrl.text : null);
            },
            child: const Text('Confirmer'),
          ),
        ],
      ),
    );
  }

  /// Confirmation de suppression définitive (SuperAdmin only).
  /// Protection anti-clic — double confirmation + saisie du nom.
  Future<void> _confirmDeleteAccount(BuildContext context, Map<String, dynamic> m) async {
    final isDark = Theme.of(context).brightness == Brightness.dark;
    final name = (m['name'] as String? ?? '').trim();
    final memberId = m['id'] as String? ?? '';
    final roleCode = (m['roleCode'] as String? ?? '').toUpperCase();
    final isAdminTarget = roleCode == 'ORGADMIN' || roleCode == 'ADMIN_ORGANISATION';
    final textPrimary = isDark ? AppColors.textPrimaryDark : AppColors.textPrimary;
    final textSecondary = isDark ? AppColors.textSecondaryDark : AppColors.textSecondary;

    final confirmed = await showDialog<bool>(
      context: context,
      barrierDismissible: false,
      builder: (ctx) => AlertDialog(
        shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(14)),
        backgroundColor: isDark ? AppColors.surfaceDark : AppColors.surface,
        title: Row(
          children: [
            Container(
              padding: const EdgeInsets.all(8),
              decoration: BoxDecoration(
                color: AppColors.error.withOpacity(isDark ? 0.2 : 0.1),
                borderRadius: BorderRadius.circular(8),
              ),
              child: const Icon(Icons.warning_amber_rounded, color: AppColors.error, size: 22),
            ),
            const SizedBox(width: 10),
            Expanded(
              child: Text(
                'Supprimer ce compte ?',
                style: TextStyle(fontSize: 16, fontWeight: FontWeight.w800, color: textPrimary),
              ),
            ),
          ],
        ),
        content: Column(
          mainAxisSize: MainAxisSize.min,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text(
              'Vous êtes sur le point de supprimer le compte de :',
              style: TextStyle(fontSize: 13, color: textSecondary),
            ),
            const SizedBox(height: 8),
            Container(
              width: double.infinity,
              padding: const EdgeInsets.all(10),
              decoration: BoxDecoration(
                color: AppColors.error.withOpacity(isDark ? 0.12 : 0.06),
                borderRadius: BorderRadius.circular(8),
                border: Border.all(color: AppColors.error.withOpacity(0.3)),
              ),
              child: Row(
                children: [
                  if (isAdminTarget) ...[
                    Icon(Icons.admin_panel_settings_outlined, size: 16, color: AppColors.error),
                    const SizedBox(width: 6),
                  ],
                  Expanded(
                    child: Text(
                      name.isEmpty ? '(sans nom)' : name,
                      style: TextStyle(fontSize: 14, fontWeight: FontWeight.w700, color: textPrimary),
                    ),
                  ),
                ],
              ),
            ),
            const SizedBox(height: 12),
            Text(
              isAdminTarget
                  ? 'Ce membre est administrateur d\'organisation. Sa suppression désactivera son compte et suspendra toutes ses adhésions.'
                  : 'Le compte sera désactivé et toutes ses adhésions seront suspendues. Cette action est irréversible.',
              style: TextStyle(fontSize: 12, color: textSecondary, height: 1.4),
            ),
          ],
        ),
        actions: [
          TextButton(
            onPressed: () => Navigator.of(ctx).pop(false),
            child: Text('Annuler', style: TextStyle(color: textSecondary, fontWeight: FontWeight.w600)),
          ),
          ElevatedButton.icon(
            onPressed: () => Navigator.of(ctx).pop(true),
            icon: const Icon(Icons.delete_forever, size: 18),
            label: const Text('Supprimer', style: TextStyle(fontWeight: FontWeight.w700)),
            style: ElevatedButton.styleFrom(
              backgroundColor: AppColors.error,
              foregroundColor: AppColors.onError,
              shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
              padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 10),
            ),
          ),
        ],
      ),
    );

    if (confirmed == true && context.mounted) {
      // Fermer l'action sheet en plus du dialog
      Navigator.of(context).pop();
      widget.onDeleteAccount!(memberId);
    }
  }

  Future<void> _showAffecterDialog(BuildContext context) async {
    if (_orgs.isEmpty) {
      try {
        final repo = GetIt.instance<IOrganizationRepository>();
        final orgs = await repo.getOrganizations(page: 0, size: 100);
        if (mounted) {
          setState(() {
            _orgs = orgs.where((o) => o.id != null && o.id!.isNotEmpty).map((o) => {'id': o.id!, 'nom': o.nomAffichage}).toList();
            widget.onOrganisationsLoaded(_orgs);
          });
        }
      } catch (_) {}
    }
    if (!mounted) return;
    String? selectedOrgId;
    await showDialog<void>(
      context: context,
      builder: (ctx) => StatefulBuilder(
        builder: (ctx, set) => AlertDialog(
          title: const Text('Affecter à une organisation'),
          content: _orgs.isEmpty
              ? const Text('Aucune organisation disponible.')
              : DropdownButtonFormField<String>(
                  decoration: const InputDecoration(labelText: 'Organisation'),
                  items: _orgs.map((o) => DropdownMenuItem(value: o['id'], child: Text(o['nom']!))).toList(),
                  onChanged: (v) => set(() => selectedOrgId = v),
                ),
          actions: [
            TextButton(onPressed: () => Navigator.pop(ctx), child: const Text('Annuler')),
            ElevatedButton(
              style: ElevatedButton.styleFrom(backgroundColor: ModuleColors.membres, foregroundColor: AppColors.onPrimary),
              onPressed: selectedOrgId == null
                  ? null
                  : () {
                      Navigator.pop(ctx);
                      Navigator.pop(context);
                      widget.onAffecterOrganisation!(widget.member['id'] as String, selectedOrgId!);
                    },
              child: const Text('Confirmer'),
            ),
          ],
        ),
      ),
    );
  }

  String _fmt(dynamic date) {
    if (date == null) return '—';
    if (date is DateTime) {
      return '${date.day.toString().padLeft(2, '0')}/${date.month.toString().padLeft(2, '0')}/${date.year}';
    }
    return date.toString();
  }
}

/// Données d'une action swipe gauche pour les cartes membres
class _SwipeAction {
  final String action;    // 'activer' | 'suspendre' | 'radier'
  final IconData icon;
  final String label;
  final Color color;
  const _SwipeAction({
    required this.action,
    required this.icon,
    required this.label,
    required this.color,
  });
}
