<?php

namespace App\Modules\Citizenship\FR;

use App\Core\Citizenship\AbstractCitizenship;

class FR extends AbstractCitizenship
{
    public function getVerificationFields(): array
    {
        return [
            'individual_id' => [
                'type' => 'text',
                'label' => 'Numéro de Sécurité Sociale (NIR)',
                'placeholder' => '1 84 12 76 451 089 46',
                'group' => 'individual',
            ],
            'company_id' => [
                'type' => 'text',
                'label' => 'SIRET',
                'placeholder' => '12345678901234',
                'group' => 'company',
            ],
        ];
    }

    public function validateField(string $fieldKey, string $value, array $allData = []): array
    {
        return match ($fieldKey) {
            'individual_id' => $this->validateNir($value),
            'company_id' => $this->validateSiret($value),
            default => $this->successResult(),
        };
    }

    protected function getModuleLabel(): string
    {
        return "FR — France Vérification d'Identité";
    }

    protected function getModuleDescription(): string
    {
        return 'NIR and SIRET validation for France';
    }

    /**
     * NIR (Numéro d'Inscription au Répertoire / numéro de sécurité sociale).
     *
     * Structure : 13 chiffres + clé de contrôle sur 2 chiffres (15 caractères).
     *   sexe(1) année(2) mois(2) département(2) commune(3) ordre(3) | clé(2)
     *
     * Clé officielle INSEE : clé = 97 - (nombre mod 97).
     * Cas Corse : le département peut être 2A ou 2B (lettres). Convention
     * officielle appliquée avant le modulo : 2A → 19, 2B → 18. (Équivalent au
     * remplacement A/B→0 puis soustraction de 1 000 000 / 2 000 000, la valeur
     * de position du département étant 10^6.)
     */
    private function validateNir(string $value): array
    {
        $clean = strtoupper(preg_replace('/\s+/', '', trim($value)));

        // 13 caractères (Corse: 2A/2B autorisés en position département) + clé sur 2 chiffres.
        if (! preg_match('/^([12])(\d{4})(\d{2}|2[AB])(\d{6})(\d{2})$/', $clean, $m)) {
            return $this->failResult('NIR invalide : format attendu 15 caractères (chiffres, Corse 2A/2B admis).');
        }

        $dept = $m[3];
        $key = (int) $m[5];

        // Substitution Corse pour le calcul du modulo.
        $deptNumeric = match ($dept) {
            '2A' => '19',
            '2B' => '18',
            default => $dept,
        };

        $number = $m[1] . $m[2] . $deptNumeric . $m[4]; // 13 chiffres numériques

        // 13 chiffres ⩽ 9 999 999 999 999 < PHP_INT_MAX (64 bits) → modulo direct sûr.
        $expectedKey = 97 - ((int) $number % 97);

        if ($key < 1 || $key > 97 || $expectedKey !== $key) {
            return $this->failResult('NIR invalide : clé de contrôle incorrecte.');
        }

        return $this->successResult('NIR valide.');
    }

    /**
     * SIRET : 14 chiffres, validé par l'algorithme de Luhn (mod 10).
     * (SIREN 9 chiffres + NIC 5 chiffres ; l'ensemble satisfait Luhn.)
     */
    private function validateSiret(string $value): array
    {
        $clean = preg_replace('/\s+/', '', trim($value));
        if (! preg_match('/^\d{14}$/', $clean)) {
            return $this->failResult('Le SIRET doit contenir 14 chiffres.');
        }

        if (! $this->luhnValid($clean)) {
            return $this->failResult('SIRET invalide : la clé de Luhn est incorrecte.');
        }

        return $this->successResult('SIRET valide.');
    }

    /**
     * Validation Luhn (mod 10) sur une chaîne de chiffres.
     */
    private function luhnValid(string $digits): bool
    {
        $sum = 0;
        $len = strlen($digits);

        // On double un chiffre sur deux à partir de la droite.
        for ($i = 0; $i < $len; $i++) {
            $d = (int) $digits[$len - 1 - $i];
            if ($i % 2 === 1) {
                $d *= 2;
                if ($d > 9) {
                    $d -= 9;
                }
            }
            $sum += $d;
        }

        return $sum % 10 === 0;
    }
}
