<?php

namespace Espo\Custom\Hooks\CBankverbindungen;

use Espo\ORM\Entity;
use Espo\Core\Exceptions\BadRequest;
use Espo\Core\Utils\Language;

class BankdatenValidation
{
    private $language;

    public function __construct(Language $language)
    {
        $this->language = $language;
    }

    public function beforeSave(Entity $entity, array $options): void
    {
        // IBAN-Normalisierung und Validierung
        $iban = $entity->get('iban');
        if ($iban !== null && $iban !== '') {
            // IBAN normalisieren: Leerzeichen entfernen und Großbuchstaben
            $ibanClean = strtoupper(str_replace(' ', '', $iban));
            $entity->set('iban', $ibanClean);
            
            // Mathematische IBAN-Prüfung mit Modulo-97
            if (!$this->validateIban($ibanClean)) {
                $message = $this->language->translateLabel('invalidIbanChecksum', 'messages', 'CBankverbindungen');
                throw new BadRequest($message);
            }
        }

        // BIC-Normalisierung und Validierung
        $bic = $entity->get('bic');
        if ($bic !== null && $bic !== '') {
            // BIC normalisieren: Leerzeichen entfernen und Großbuchstaben
            $bicClean = strtoupper(str_replace(' ', '', $bic));
            $entity->set('bic', $bicClean);
            
            // BIC-Format prüfen: 8 oder 11 Zeichen
            $bicLength = strlen($bicClean);
            if ($bicLength !== 8 && $bicLength !== 11) {
                $message = $this->language->translateLabel('invalidBicLength', 'messages', 'CBankverbindungen');
                throw new BadRequest($message);
            }
            
            // BIC-Format prüfen: Regex
            if (!preg_match('/^[A-Z]{6}[A-Z0-9]{2}([A-Z0-9]{3})?$/', $bicClean)) {
                $message = $this->language->translateLabel('invalidBicFormat', 'messages', 'CBankverbindungen');
                throw new BadRequest($message);
            }
        }
    }

    private function validateIban(string $iban): bool
    {
        // IBAN-Länge prüfen (mindestens 15 Zeichen)
        if (strlen($iban) < 15) {
            return false;
        }

        // IBAN umstellen: erste 4 Zeichen ans Ende
        $rearranged = substr($iban, 4) . substr($iban, 0, 4);

        // Buchstaben in Zahlen umwandeln (A=10, B=11, ..., Z=35)
        $numeric = '';
        for ($i = 0; $i < strlen($rearranged); $i++) {
            $char = $rearranged[$i];
            if (ctype_alpha($char)) {
                $numeric .= (string)(ord($char) - ord('A') + 10);
            } else {
                $numeric .= $char;
            }
        }

        // Modulo-97-Prüfung
        return $this->bcmod($numeric, '97') === '1';
    }

    private function bcmod(string $number, string $modulus): string
    {
        // Für große Zahlen: Modulo in Schritten berechnen
        $take = 9;
        $mod = '';

        do {
            $a = (int)($mod . substr($number, 0, $take));
            $number = substr($number, $take);
            $mod = (string)($a % (int)$modulus);
        } while (strlen($number) > 0);

        return $mod;
    }
}
