import 'package:flutter/services.dart';

/// Format français : 10 chiffres affichés par paires (ex. 06 12 34 56 78).

/// Ne garde que les chiffres (max 10).
String normalizePhone(String raw) {
  final digits = raw.replaceAll(RegExp(r'\D'), '');
  return digits.length > 10 ? digits.substring(0, 10) : digits;
}

/// Indique si [digitsOnly] (déjà normalisé par [normalizePhone]) commence par `0`.
/// Chaîne vide : `true` (pas encore de saisie).
bool frenchNationalPhoneStartsWithZero(String digitsOnly) {
  if (digitsOnly.isEmpty) {
    return true;
  }
  return digitsOnly.startsWith('0');
}

/// Validation téléphone France : 10 chiffres, commence par `0`, 2ᵉ chiffre 1–9 (format national).
///
/// Utiliser sur tout champ « numéro français » (inscription, admin, relais, etc.).
/// Si [allowEmpty] est `true`, une valeur vide ou blanche est acceptée.
String? validateFrenchNationalPhone(String? raw, {bool allowEmpty = false}) {
  final trimmed = raw?.trim() ?? '';
  if (trimmed.isEmpty) {
    return allowEmpty ? null : 'Le numéro de téléphone est obligatoire.';
  }
  final digits = normalizePhone(trimmed);
  if (digits.isEmpty) {
    return allowEmpty ? null : 'Le numéro de téléphone est obligatoire.';
  }
  if (!frenchNationalPhoneStartsWithZero(digits)) {
    return 'En France, le numéro doit commencer par 0 (ex. 06 12 34 56 78).';
  }
  if (digits.length < 10) {
    return 'Le numéro doit contenir 10 chiffres.';
  }
  if (digits.length > 10) {
    return 'Le numéro ne peut pas dépasser 10 chiffres.';
  }
  if (!RegExp(r'^0[1-9]\d{8}$').hasMatch(digits)) {
    return 'Numéro de téléphone invalide.';
  }
  return null;
}

/// Retourne le numéro formaté pour l'affichage (ex. "06 12 34 56 78").
/// Si [raw] est vide après normalisation, retourne [raw] tel quel (pour afficher "–" etc.).
String formatPhoneForDisplay(String raw) {
  if (raw.trim().isEmpty) {
    return raw;
  }
  final normalized = normalizePhone(raw);
  if (normalized.isEmpty) {
    return raw;
  }
  return formatFrenchPhoneDigits(normalized);
}

/// Affiche les chiffres par paires (ex. `0612345678` → `06 12 34 56 78`).
String formatFrenchPhoneDigits(String normalizedDigits) {
  if (normalizedDigits.isEmpty) {
    return '';
  }
  final buffer = StringBuffer();
  for (var i = 0; i < normalizedDigits.length; i++) {
    if (i > 0 && i.isEven) {
      buffer.write(' ');
    }
    buffer.write(normalizedDigits[i]);
  }
  return buffer.toString();
}

int _cursorOffsetInFormattedPhone(String normalized, int digitCountBeforeCursor) {
  final k = digitCountBeforeCursor.clamp(0, normalized.length);
  if (k == 0) {
    return 0;
  }
  return formatFrenchPhoneDigits(normalized.substring(0, k)).length;
}

/// Formatter de saisie : chiffres uniquement, paires espacées, max 10 chiffres.
///
/// - Si le premier chiffre est **1 à 7**, un **0** est ajouté automatiquement devant (ex. `6` → `06`).
/// - Si l’utilisateur tape **8** ou **9** en premier, la saisie est ignorée (numéros spéciaux `08` / `09`).
/// - S’il commence déjà par **0**, aucun préfixe n’est ajouté.
class FrenchPhoneNumberFormatter extends TextInputFormatter {
  const FrenchPhoneNumberFormatter();

  static const String _autoPrefixFirstDigits = '1234567';

  @override
  TextEditingValue formatEditUpdate(
    TextEditingValue oldValue,
    TextEditingValue newValue,
  ) {
    var digits = newValue.text.replaceAll(RegExp(r'\D'), '');
    var didPrependZero = false;

    if (digits.isNotEmpty) {
      final first = digits[0];
      if (first == '8' || first == '9') {
        return oldValue;
      }
      if (first != '0' && _autoPrefixFirstDigits.contains(first)) {
        digits = '0$digits';
        didPrependZero = true;
        if (digits.length > 10) {
          digits = digits.substring(0, 10);
        }
      } else if (first != '0') {
        return oldValue;
      }
    }

    final normalized = digits.length > 10 ? digits.substring(0, 10) : digits;
    final formatted = formatFrenchPhoneDigits(normalized);

    final sel = newValue.selection;
    var digitsBeforeCursor = newValue.text
        .substring(0, sel.start.clamp(0, newValue.text.length))
        .replaceAll(RegExp(r'\D'), '')
        .length;
    if (didPrependZero) {
      digitsBeforeCursor = (digitsBeforeCursor + 1).clamp(0, normalized.length);
    }

    final clampedOffset =
        _cursorOffsetInFormattedPhone(normalized, digitsBeforeCursor).clamp(0, formatted.length);

    return TextEditingValue(
      text: formatted,
      selection: TextSelection.collapsed(offset: clampedOffset),
    );
  }
}

/// Formatters à réutiliser sur tout champ téléphone France ([TextFormField], [CustomAppTextField], etc.).
final List<TextInputFormatter> frenchPhoneInputFormatters = [
  FilteringTextInputFormatter.digitsOnly,
  LengthLimitingTextInputFormatter(10),
  const FrenchPhoneNumberFormatter(),
];
