<?php

declare(strict_types=1);

namespace OCA\Mitgliederverwaltung\Tests\Unit;

use OCA\Mitgliederverwaltung\Validation\IbanValidator;
use PHPUnit\Framework\TestCase;

/**
 * Comprehensive unit tests for IbanValidator.
 *
 * Covers IBAN checksum, country-specific lengths, format checks,
 * and error message validation per Issue #66.
 */
class IbanValidatorTest extends TestCase {

    // ── Valid IBANs ─────────────────────────────────────────────────

    public function testValidGermanIban(): void {
        $this->assertTrue(IbanValidator::isValid('DE89370400440532013000'));
    }

    public function testValidGermanIbanWithSpaces(): void {
        $this->assertTrue(IbanValidator::isValid('DE89 3704 0044 0532 0130 00'));
    }

    public function testValidGermanIbanLowercase(): void {
        $this->assertTrue(IbanValidator::isValid('de89370400440532013000'));
    }

    public function testValidAustrianIban(): void {
        $this->assertTrue(IbanValidator::isValid('AT611904300234573201'));
    }

    public function testValidSwissIban(): void {
        $this->assertTrue(IbanValidator::isValid('CH9300762011623852957'));
    }

    public function testValidBritishIban(): void {
        $this->assertTrue(IbanValidator::isValid('GB29NWBK60161331926819'));
    }

    public function testValidFrenchIban(): void {
        $this->assertTrue(IbanValidator::isValid('FR7630006000011234567890189'));
    }

    public function testValidDutchIban(): void {
        $this->assertTrue(IbanValidator::isValid('NL91ABNA0417164300'));
    }

    // ── Invalid checksum ────────────────────────────────────────────

    public function testInvalidChecksumFails(): void {
        // DE89 → DE88 (wrong check digits)
        $this->assertFalse(IbanValidator::isValid('DE88370400440532013000'));
    }

    public function testInvalidChecksumErrorMessage(): void {
        $error = IbanValidator::getError('DE88370400440532013000');
        $this->assertNotNull($error);
        $this->assertStringContainsString('Pruefsumme', $error);
    }

    // ── Wrong length ────────────────────────────────────────────────

    public function testTooShortIbanFails(): void {
        $this->assertFalse(IbanValidator::isValid('DE8937040044'));
    }

    public function testTooShortErrorMessage(): void {
        $error = IbanValidator::getError('DE8937040044');
        $this->assertNotNull($error);
        $this->assertStringContainsString('kurz', $error);
    }

    public function testTooLongIbanFails(): void {
        $this->assertFalse(IbanValidator::isValid('DE89370400440532013000123456789012345'));
    }

    public function testTooLongErrorMessage(): void {
        $error = IbanValidator::getError('DE89370400440532013000123456789012345');
        $this->assertNotNull($error);
        $this->assertStringContainsString('lang', $error);
    }

    public function testWrongCountryLengthFails(): void {
        // DE should be 22 chars, adding extra digit
        $this->assertFalse(IbanValidator::isValid('DE893704004405320130001'));
    }

    public function testWrongCountryLengthErrorMessage(): void {
        $error = IbanValidator::getError('DE893704004405320130001');
        $this->assertNotNull($error);
        $this->assertStringContainsString('22', $error);
        $this->assertStringContainsString('DE', $error);
    }

    // ── Invalid characters ──────────────────────────────────────────

    public function testInvalidCharactersFails(): void {
        $this->assertFalse(IbanValidator::isValid('DE89-3704-0044-0532-013000'));
    }

    public function testSpecialCharactersInIbanFails(): void {
        $this->assertFalse(IbanValidator::isValid('DE89@3704$0044!0532'));
    }

    // ── Empty / null ────────────────────────────────────────────────

    public function testEmptyStringFails(): void {
        $this->assertFalse(IbanValidator::isValid(''));
    }

    public function testEmptyStringErrorMessage(): void {
        $error = IbanValidator::getError('');
        $this->assertNotNull($error);
        $this->assertStringContainsString('leer', $error);
    }

    public function testWhitespaceOnlyFails(): void {
        $this->assertFalse(IbanValidator::isValid('   '));
    }

    // ── No country code ─────────────────────────────────────────────

    public function testNoCountryCodeFails(): void {
        $this->assertFalse(IbanValidator::isValid('89370400440532013000'));
    }

    public function testNoCountryCodeErrorMessage(): void {
        $error = IbanValidator::getError('89370400440532013000');
        $this->assertNotNull($error);
        $this->assertStringContainsString('Laendercode', $error);
    }

    // ── Valid IBAN returns null error ────────────────────────────────

    public function testValidIbanReturnsNullError(): void {
        $this->assertNull(IbanValidator::getError('DE89370400440532013000'));
    }
}
