/**
 * Utilitaire de validation du NIR (numéro de sécurité sociale français).
 * - Format 15 caractères (chiffres ou 2A/2B pour la Corse).
 * - Clé de contrôle : 97 - (NIR13 mod 97). Pour 2A/2B, conversion temporaire (INSEE : 2A→19, 2B→20).
 * - En cas d'incohérence avec les données (sexe, date, lieu) : warning uniquement, pas de rejet.
 */

const NIR_CORSE_2A = '19';
const NIR_CORSE_2B = '20';

/** Regex 15 caractères : sexe (1-3) + 4 chiffres + (2A|2B|2 chiffres) + 6 chiffres + 2 chiffres clé */
const NIR_FORMAT = /^[1-3]\d{4}(?:2A|2B|\d{2})\d{6}\d{2}$/i;

/**
 * Convertit le NIR en chaîne de 13 chiffres pour le calcul de la clé (2A→19, 2B→20).
 */
export function nirTo13Digits(nir: string): string {
  const n = nir.toUpperCase().replace(/\s/g, '');
  if (n.length !== 15) return '';
  const dept = n.slice(5, 7);
  let deptNum: string;
  if (dept === '2A') deptNum = NIR_CORSE_2A;
  else if (dept === '2B') deptNum = NIR_CORSE_2B;
  else deptNum = dept;
  return n.slice(0, 5) + deptNum + n.slice(7, 13);
}

/**
 * Vérifie que le format NIR est valide (15 caractères, 2A/2B acceptés).
 */
export function isNirFormatValid(nir: string): boolean {
  if (!nir || typeof nir !== 'string') return false;
  const n = nir.replace(/\s/g, '').toUpperCase();
  return NIR_FORMAT.test(n);
}

/**
 * Calcule la clé de contrôle attendue (97 - (NIR13 mod 97)).
 * Retourne un nombre entre 1 et 97.
 */
export function computeNirKey(nir13: string): number {
  const num = parseInt(nir13, 10);
  if (Number.isNaN(num) || nir13.length !== 13) return -1;
  return 97 - (num % 97);
}

/**
 * Vérifie la clé de contrôle du NIR (15 caractères).
 * Retourne true si le NIR est valide (format + clé).
 */
export function isNirKeyValid(nir: string): boolean {
  const n = nir.replace(/\s/g, '').toUpperCase();
  if (n.length !== 15) return false;
  const nir13 = nirTo13Digits(n);
  if (nir13.length !== 13) return false;
  const expectedKey = computeNirKey(nir13);
  const actualKey = parseInt(n.slice(13, 15), 10);
  return expectedKey === actualKey;
}

export interface NirValidationResult {
  valid: boolean;
  error?: string;
  warning?: string;
}

/**
 * Valide le NIR (format + clé). En cas d'incohérence avec date de naissance ou sexe, ajoute un warning sans invalider.
 */
export function validateNir(
  nir: string,
  options?: { dateNaissance?: string; genre?: 'H' | 'F' },
): NirValidationResult {
  const n = (nir || '').replace(/\s/g, '').toUpperCase();
  if (n.length === 0) return { valid: false, error: 'Le NIR est requis' };
  if (!isNirFormatValid(n)) {
    return { valid: false, error: 'Le NIR doit contenir 15 caractères (chiffres, ou 2A/2B pour la Corse)' };
  }
  if (!isNirKeyValid(n)) {
    return { valid: false, error: 'Clé de contrôle du NIR invalide' };
  }
  let warning: string | undefined;
  if (options?.genre) {
    const sexNir = n[0];
    const expectedSex = options.genre === 'F' ? '2' : '1';
    if (sexNir !== expectedSex) {
      warning = 'Le NIR ne correspond pas au genre indiqué (position 1 du NIR).';
    }
  }
  if (options?.dateNaissance) {
    try {
      const d = new Date(options.dateNaissance);
      if (!Number.isNaN(d.getTime())) {
        const year2 = d.getFullYear() % 100;
        const month = d.getMonth() + 1;
        const nirYear = parseInt(n.slice(1, 3), 10);
        const nirMonth = parseInt(n.slice(3, 5), 10);
        if (nirYear !== year2 || nirMonth !== month) {
          warning = warning
            ? `${warning} Le NIR ne correspond pas à la date de naissance (positions 2-5).`
            : 'Le NIR ne correspond pas à la date de naissance indiquée (positions 2-5).';
        }
      }
    } catch {
      // ignore
    }
  }
  return { valid: true, warning };
}
