<?php

namespace App\Modules\Citizenship\DE;

use App\Core\Citizenship\AbstractCitizenship;

class DE extends AbstractCitizenship
{
    public function getVerificationFields(): array
    {
        return [
            'individual_id' => [
                'type' => 'text',
                'label' => 'Steuerliche Identifikationsnummer',
                'placeholder' => '12345678901',
                'group' => 'individual',
            ],
            'company_id' => [
                'type' => 'text',
                'label' => 'USt-IdNr',
                'placeholder' => 'DE123456789',
                'group' => 'company',
            ],
        ];
    }

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

    protected function getModuleLabel(): string
    {
        return 'DE — Deutschland Identitätsprüfung';
    }

    protected function getModuleDescription(): string
    {
        return 'Steuer-ID and USt-IdNr validation for Germany';
    }

    /**
     * Steuerliche Identifikationsnummer (IdNr) — komplett OFFLINE prüfbar.
     *
     * Regeln (BZSt / ISO 7064 MOD 11,10):
     *  - Genau 11 Ziffern, erste Ziffer ungleich 0.
     *  - In den ersten 10 Stellen: entweder genau eine Ziffer zweimal
     *    (und dadurch genau eine Ziffer fehlt), ODER — seit 2016 —
     *    genau eine Ziffer dreimal an nicht direkt aufeinanderfolgenden
     *    Positionen (und zwei Ziffern fehlen). Nie mehr als das.
     *  - 11. Stelle ist eine ISO-7064-MOD-11,10-Prüfziffer über die
     *    ersten 10 Stellen.
     *
     * Referenz: BZSt „Prüfung der steuerlichen Identifikationsnummer",
     * ISO/IEC 7064 (MOD 11,10).
     */
    private function validateSteuerId(string $value): array
    {
        $value = preg_replace('/\s+/', '', trim($value));
        if (! preg_match('/^\d{11}$/', $value)) {
            return $this->failResult('Steuer-ID muss 11 Ziffern enthalten.');
        }
        if ($value[0] === '0') {
            return $this->failResult('Steuer-ID darf nicht mit 0 beginnen.');
        }

        $first10 = substr($value, 0, 10);

        if (! $this->steuerIdDigitDistributionValid($first10)) {
            return $this->failResult('Steuer-ID: ungültige Ziffernverteilung in den ersten 10 Stellen.');
        }

        if (! $this->steuerIdChecksumValid($value)) {
            return $this->failResult('Steuer-ID: Prüfziffer stimmt nicht (ISO 7064 MOD 11,10).');
        }

        return $this->successResult('Gültige Steuer-ID (Prüfziffer bestätigt).');
    }

    /**
     * Ziffernverteilung der ersten 10 Stellen.
     * Erlaubt: (a) genau eine Ziffer zweimal, alle anderen höchstens einmal
     * (→ 9 verschiedene Ziffern) ODER (b) genau eine Ziffer dreimal, aber
     * nicht an drei direkt aufeinanderfolgenden Positionen (→ 8 verschiedene
     * Ziffern). Alle anderen Verteilungen sind ungültig.
     */
    private function steuerIdDigitDistributionValid(string $first10): bool
    {
        $counts = array_count_values(str_split($first10));
        $max = max($counts);
        $distinct = count($counts);

        if ($max === 2 && $distinct === 9) {
            // genau eine Ziffer doppelt, sonst alle einfach
            return count(array_filter($counts, fn ($c) => $c === 2)) === 1;
        }

        if ($max === 3 && $distinct === 8) {
            // genau eine Ziffer dreifach, sonst alle einfach
            if (count(array_filter($counts, fn ($c) => $c === 3)) !== 1) {
                return false;
            }
            // die dreifache Ziffer darf nicht dreimal direkt hintereinander stehen
            $tripleDigit = (string) array_search(3, $counts, true);

            return ! str_contains($first10, str_repeat($tripleDigit, 3));
        }

        return false;
    }

    /**
     * ISO 7064 MOD 11,10 Prüfziffernberechnung über die ersten 10 Stellen;
     * 11. Stelle muss dem Ergebnis entsprechen.
     */
    private function steuerIdChecksumValid(string $value): bool
    {
        $product = 10;
        for ($i = 0; $i < 10; $i++) {
            $sum = ((int) $value[$i] + $product) % 10;
            if ($sum === 0) {
                $sum = 10;
            }
            $product = ($sum * 2) % 11;
        }
        $check = (11 - $product) % 10;

        return $check === (int) $value[10];
    }

    /**
     * USt-IdNr (deutsche Umsatzsteuer-Identifikationsnummer).
     *
     * Für die deutsche USt-IdNr gibt es KEINEN öffentlich dokumentierten
     * Offline-Prüfziffernalgorithmus (anders als bei manchen EU-Ländern);
     * die belastbare Gültigkeitsprüfung erfolgt online über das EU-VIES-
     * bzw. BZSt-Verfahren. Ohne konfigurierte API prüfen wir daher nur das
     * Format und geben das ehrlich als „nur Format" zurück — keine
     * vorgetäuschte Verifizierung.
     */
    private function validateUstIdNr(string $value): array
    {
        $value = strtoupper(preg_replace('/\s+/', '', trim($value)));
        if (! preg_match('/^DE\d{9}$/', $value)) {
            return $this->failResult('USt-IdNr muss Format DE123456789 haben.');
        }

        return $this->successResult('USt-IdNr: Format gültig (keine Offline-Prüfziffer verfügbar — belastbare Prüfung nur online via VIES/BZSt).');
    }
}
