<?php

declare(strict_types=1);

namespace NoahVet\Reef\Test\A_Unit\Phpunit;

use NoahVet\Reef\Phpunit\Fixture\FixtureRepository;
use NoahVet\Reef\Phpunit\Fixture\ReefTokenFixture;
use NoahVet\Reef\Phpunit\Security\MockedReefOAuthAuthenticator;
use NoahVet\Reef\Security\Authentication\Token\ReefOAuthToken;
use NoahVet\Reef\Security\User\ReefOAuthUser;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Exception\AuthenticationException;

class MockedReefOAuthAuthenticatorTest extends TestCase
{
    public function testSupports(): void
    {
        $repository = new FixtureRepository();

        $authenticator = new MockedReefOAuthAuthenticator($repository);

        $request = new Request();

        self::assertFalse($authenticator->supports($request));

        $request->headers->set('Authorization', 'Bearer unit_test');
        self::assertTrue($authenticator->supports($request));
    }

    public function testAuthenticationSuccessfull(): void
    {
        $repository = new FixtureRepository();
        $user = new ReefOAuthUser('toto', null);

        $tokenFixture = new ReefTokenFixture(
            'unit_token',
            $user,
            [],
        );

        $repository->addFixture($tokenFixture);

        $authenticator = new MockedReefOAuthAuthenticator($repository);

        $request = new Request();
        $request->headers->set('Authorization', 'Bearer unit_token');

        self::assertTrue($authenticator->supports($request));
        $token = $authenticator->createToken(
            $authenticator->authenticate($request),
            'main',
        );
        self::assertInstanceOf(ReefOAuthToken::class, $token);
        self::assertEquals('main', $token->getFirewallName());
        self::assertEquals('unit_token', $token->getBearerToken());
        self::assertSame($user, $token->getUser());

        self:self::assertNull(
            $authenticator->onAuthenticationSuccess(
                $request,
                $token,
                'main',
            ),
        );
    }

    public function testOnAuthenticationFailure(): void
    {
        $repository = new FixtureRepository();

        $authenticator = new MockedReefOAuthAuthenticator($repository);
        $exception = $this->getMockBuilder(AuthenticationException::class)
            ->disableOriginalConstructor()
            ->getMock()
        ;

        $request = new Request();

        $response = $authenticator->onAuthenticationFailure($request, $exception);
        self::assertInstanceOf(JsonResponse::class, $response);
        self::assertEquals(Response::HTTP_UNAUTHORIZED, $response->getStatusCode());

        $request->headers->set('Authorization', 'Bearer invalid_token');
        $response = $authenticator->onAuthenticationFailure($request, $exception);
        self::assertInstanceOf(JsonResponse::class, $response);
        self::assertEquals(Response::HTTP_FORBIDDEN, $response->getStatusCode());
    }
}
