<?php

declare(strict_types=1);

namespace CpCreation\AltchaBundle\Tests\PublicApi;

use CpCreation\AltchaBundle\Security\ProtectionEnvelopeManager;
use CpCreation\AltchaBundle\Tests\Double\MutableTimeProvider;
use PHPUnit\Framework\TestCase;

final class ProtectionEnvelopeManagerTest extends TestCase
{
    public function testSignedEnvelopeBindsHostScopeTimesNonceAndOpaqueHoneypot(): void
    {
        $time = new MutableTimeProvider();
        $manager = new ProtectionEnvelopeManager('envelope-test-secret-with-enough-entropy', $time, 120);

        $envelope = $manager->issue('custom.form', 'Example.TEST');
        $claims = $manager->validateForSubmission($envelope->token, 'custom.form', 'example.test', 0, 120);

        self::assertNotNull($claims);
        self::assertSame($time->milliseconds, $claims->issuedAtMilliseconds);
        self::assertSame($time->milliseconds + 120_000, $claims->expiresAtMilliseconds);
        self::assertMatchesRegularExpression('/^[a-f0-9]{32}$/', $claims->nonce);
        self::assertMatchesRegularExpression('/^hp_[a-f0-9]{24}$/', $claims->honeypotName);
        self::assertNull($manager->validateForSubmission($envelope->token, 'other.form', 'example.test', 0, 120));
        self::assertNull($manager->validateForSubmission($envelope->token, 'custom.form', 'other.test', 0, 120));
        self::assertNull($manager->validateForSubmission($envelope->token.'x', 'custom.form', 'example.test', 0, 120));
    }

    public function testEnvelopeRejectsPrematureAndExpiredSubmissions(): void
    {
        $time = new MutableTimeProvider();
        $manager = new ProtectionEnvelopeManager('envelope-test-secret-with-enough-entropy', $time, 2);
        $envelope = $manager->issue('custom.form', 'example.test');

        self::assertNull($manager->validateForSubmission($envelope->token, 'custom.form', 'example.test', 500, 2));
        $time->milliseconds += 600;
        self::assertNotNull($manager->validateForSubmission($envelope->token, 'custom.form', 'example.test', 500, 2));
        $time->milliseconds += 1_500;
        self::assertNull($manager->validateForSubmission($envelope->token, 'custom.form', 'example.test', 500, 2));
    }
}
