<?php

declare(strict_types=1);

use App\Domain\QrCode\QrCode;
use App\Domain\QrCode\Service\QrCodeEncoder;
use App\Domain\QrCode\ValueObject\ErrorCorrectionLevel;
use App\Domain\QrCode\ValueObject\QrCodeVersion;

test('QrCodeEncoder kann numerische Daten kodieren', function () {
    $encoder = new QrCodeEncoder();
    $qrCode = new QrCode('12345', ErrorCorrectionLevel::M);
    $version = new QrCodeVersion(1);

    $encoded = $encoder->encode($qrCode, $version);

    // Prüfe, dass das Ergebnis ein binärer String ist
    expect($encoded)->toBeString();
    expect(strlen($encoded) % 8)->toBe(0); // Muss ein Vielfaches von 8 sein

    // Prüfe den Mode Indicator für numerische Daten (0001)
    expect(substr($encoded, 0, 4))->toBe('0001');
});

test('QrCodeEncoder kann alphanumerische Daten kodieren', function () {
    $encoder = new QrCodeEncoder();
    $qrCode = new QrCode('ABC123', ErrorCorrectionLevel::M);
    $version = new QrCodeVersion(1);

    $encoded = $encoder->encode($qrCode, $version);

    // Prüfe, dass das Ergebnis ein binärer String ist
    expect($encoded)->toBeString();
    expect(strlen($encoded) % 8)->toBe(0); // Muss ein Vielfaches von 8 sein

    // Prüfe den Mode Indicator für alphanumerische Daten (0010)
    expect(substr($encoded, 0, 4))->toBe('0010');
});

test('QrCodeEncoder kann Byte-Daten kodieren', function () {
    $encoder = new QrCodeEncoder();
    $qrCode = new QrCode('Hello World!', ErrorCorrectionLevel::M);
    $version = new QrCodeVersion(1);

    $encoded = $encoder->encode($qrCode, $version);

    // Prüfe, dass das Ergebnis ein binärer String ist
    expect($encoded)->toBeString();
    expect(strlen($encoded) % 8)->toBe(0); // Muss ein Vielfaches von 8 sein

    // Prüfe den Mode Indicator für Byte-Daten (0100)
    expect(substr($encoded, 0, 4))->toBe('0100');
});

test('QrCodeEncoder fügt Terminator und Padding korrekt hinzu', function () {
    $encoder = new QrCodeEncoder();
    $qrCode = new QrCode('1', ErrorCorrectionLevel::M); // Minimale Daten
    $version = new QrCodeVersion(1);

    $encoded = $encoder->encode($qrCode, $version);

    // Prüfe, dass das Ergebnis ein binärer String ist
    expect($encoded)->toBeString();

    // Prüfe die Länge (sollte der vollen Datenkapazität entsprechen)
    $expectedLength = (new QrCodeVersion(1))->getDataCapacity(ErrorCorrectionLevel::M) * 8;
    expect(strlen($encoded))->toBe($expectedLength);

    // Prüfe, ob Pad-Bytes vorhanden sind (11101100 oder 00010001)
    $containsPadBytes = str_contains($encoded, '11101100') || str_contains($encoded, '00010001');
    expect($containsPadBytes)->toBeTrue();
});
