import 'package:flutter/services.dart';

/// Utilitaires NIR (Numéro d'Inscription au Répertoire) – INSEE, 15 caractères.
/// Corse : 2A (2A) et 2B (2B) au lieu de 19/20. Clé de contrôle : 97 - (NIR13 mod 97).

/// Normalise le NIR : 15 caractères, sans espaces ni séparateurs. Corse conservée (2A/2B).
String normalizeNir(String input) {
  if (input.isEmpty) return '';
  final cleaned = input.replaceAll(' ', '').replaceAll('-', '').replaceAll('/', '').toUpperCase();
  final buf = StringBuffer();
  int i = 0;
  while (i < cleaned.length && buf.length < 15) {
    final c = cleaned[i];
    if (buf.length < 5) {
      if (c.compareTo('0') >= 0 && c.compareTo('9') <= 0) buf.write(c);
      i++;
    } else if (buf.length == 5) {
      if (c == '2' && i + 1 < cleaned.length && (cleaned[i + 1] == 'A' || cleaned[i + 1] == 'B')) {
        buf.write('2');
        buf.write(cleaned[i + 1]);
        i += 2;
      } else if ((c == 'A' || c == 'B')) {
        buf.write('2');
        buf.write(c);
        i++;
      } else if (c.compareTo('0') >= 0 && c.compareTo('9') <= 0) {
        buf.write(c);
        if (i + 1 < cleaned.length && cleaned[i + 1].compareTo('0') >= 0 && cleaned[i + 1].compareTo('9') <= 0) {
          buf.write(cleaned[i + 1]);
          i += 2;
        } else {
          i++;
        }
      } else {
        i++;
      }
    } else {
      if (c.compareTo('0') >= 0 && c.compareTo('9') <= 0) buf.write(c);
      i++;
    }
  }
  return buf.toString().length > 15 ? buf.toString().substring(0, 15) : buf.toString();
}

/// Retourne la chaîne brute à 15 caractères (chiffres + 2A ou 2B).
String nirToRaw(String normalized) {
  String s = normalized.replaceAll(' ', '').replaceAll('-', '').replaceAll('/', '');
  if (s.length > 15) s = s.substring(0, 15);
  return s;
}

/// Formate pour affichage : 1 12 34 56 789 012 - 34 ou 1 12 34 2A 789 012 - 34 (Corse).
String formatNir(String raw) {
  final r = nirToRaw(raw);
  if (r.length < 15) return r;
  // Même structure pour tous : sexe + année + mois + département + commune + ordre-clé.
  return '${r.substring(0, 1)} ${r.substring(1, 3)} ${r.substring(3, 5)} ${r.substring(5, 7)} ${r.substring(7, 10)} ${r.substring(10, 13)} - ${r.substring(13, 15)}';
}

/// Aligné sur le backend (NIR côté API / nir.util.ts) : sexe 1–3, département 2A ou 2B pour la Corse.
bool _isFormatValid(String raw) {
  final r = raw.toUpperCase();
  if (r.length != 15) return false;
  return RegExp(r'^[1-3]\d{4}(?:2A|2B|\d{2})\d{6}\d{2}$').hasMatch(r);
}

/// Clé INSEE : 97 - (NIR13 mod 97). Corse : 2A→19, 2B→20 (aligné backend).
int _controlKey(String raw13) {
  String n;
  if (raw13.length >= 7 && raw13.substring(5, 7) == '2A') {
    n = '${raw13.substring(0, 5)}19${raw13.substring(7)}';
  } else if (raw13.length >= 7 && raw13.substring(5, 7) == '2B') {
    n = '${raw13.substring(0, 5)}20${raw13.substring(7)}';
  } else {
    n = '${raw13.substring(0, 5)}${raw13.substring(5, 7)}${raw13.substring(7)}';
  }
  final big = int.tryParse(n);
  if (big == null) return -1;
  return 97 - (big % 97);
}

/// Valide le NIR (format + clé). Retourne null si valide, message d'erreur sinon.
String? validateNir(String? value) {
  if (value == null || value.isEmpty) return 'NIR requis';
  final raw = nirToRaw(value).toUpperCase();
  if (raw.length != 15) return 'Le NIR doit contenir 15 caractères (chiffres, ou 2A/2B pour la Corse)';
  if (!_isFormatValid(raw)) return 'Format NIR invalide (ex. 1 12 34 56 789 012 - 34 ou 2A pour la Corse)';
  final key = _controlKey(raw.substring(0, 13));
  final keyStr = key >= 0 && key <= 99 ? key.toString().padLeft(2, '0') : '';
  final expectedKey = raw.substring(13, 15);
  if (key < 0 || keyStr != expectedKey) return 'Clé de contrôle NIR invalide';
  return null;
}

/// Formateur de saisie : affiche le NIR formaté (1 12 34 56 789 012 - 34) et limite à 15 caractères utiles.
class NirInputFormatter extends TextInputFormatter {
  @override
  TextEditingValue formatEditUpdate(
    TextEditingValue oldValue,
    TextEditingValue newValue,
  ) {
    final raw = normalizeNir(newValue.text);
    if (raw.isEmpty) return newValue;
    final formatted = formatNir(raw);
    final offset = formatted.length;
    return TextEditingValue(
      text: formatted,
      selection: TextSelection.collapsed(offset: offset),
    );
  }
}
