<?php

declare(strict_types=1);

namespace App\Tests\Unit\Auth;

use App\Domain\Auth\Token;
use App\Domain\Auth\TokenIssuer;
use App\Domain\Auth\TokenKind;
use PHPUnit\Framework\TestCase;

final class TokenIssuerTest extends TestCase
{
    public function testIssuedTokenMatchesFormat(): void
    {
        $issuer = new TokenIssuer();

        foreach (TokenKind::cases() as $kind) {
            $raw = $issuer->issue($kind);
            self::assertSame(1, preg_match('/^irdb_(rep|con|adm|svc)_[A-Z2-7]{32}$/', $raw), "format mismatch for {$kind->value}: {$raw}");
            self::assertStringStartsWith('irdb_' . $kind->code() . '_', $raw);
        }
    }

    public function testIssuedTokensAreUnique(): void
    {
        $issuer = new TokenIssuer();
        $set = [];
        for ($i = 0; $i < 50; ++$i) {
            $set[$issuer->issue(TokenKind::Admin)] = true;
        }
        self::assertCount(50, $set);
    }

    public function testIssuedTokenRoundTripsThroughParse(): void
    {
        $issuer = new TokenIssuer();
        foreach (TokenKind::cases() as $kind) {
            $raw = $issuer->issue($kind);
            $parsed = Token::parse($raw);
            self::assertNotNull($parsed, "parse failed for {$raw}");
            self::assertSame($kind, $parsed->kind);
            self::assertSame($raw, $parsed->raw);
        }
    }

    public function testIssuedBodyAlwaysExactlyThirtyTwoBase32Chars(): void
    {
        // SEC_REVIEW F39: 20 bytes (160 bits) divides exactly by 5 → 32
        // base32 chars with zero trailing-bit ambiguity. The previous dead
        // `str_pad` branch in `base32Encode` (which prompted the F39
        // finding) is gone, but the property it implied — every char
        // carries 5 useful bits — must hold across many random samples.
        $issuer = new TokenIssuer();
        for ($i = 0; $i < 100; ++$i) {
            $raw = $issuer->issue(TokenKind::Admin);
            $body = substr($raw, strlen('irdb_adm_'));
            self::assertSame(32, strlen($body), "issued body must be 32 chars: {$raw}");
            self::assertSame(1, preg_match('/^[A-Z2-7]{32}$/', $body), "issued body must use canonical base32: {$raw}");
        }
    }
}
