<?php

declare(strict_types=1);

namespace App\Tests\Unit\Administration\Infrastructure\Security;

use App\Administration\Infrastructure\Security\GradingModeVoter;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\User\UserInterface;

final class GradingModeVoterTest extends TestCase
{
    private GradingModeVoter $voter;

    protected function setUp(): void
    {
        $this->voter = new GradingModeVoter();
    }

    #[Test]
    public function itAbstainsForUnrelatedAttributes(): void
    {
        $user = $this->createMock(UserInterface::class);
        $user->method('getRoles')->willReturn(['ROLE_ADMIN']);

        $token = $this->createMock(TokenInterface::class);
        $token->method('getUser')->willReturn($user);

        $result = $this->voter->vote($token, null, ['SOME_OTHER_ATTRIBUTE']);

        self::assertSame(GradingModeVoter::ACCESS_ABSTAIN, $result);
    }

    #[Test]
    public function itDeniesAccessToUnauthenticatedUsers(): void
    {
        $token = $this->createMock(TokenInterface::class);
        $token->method('getUser')->willReturn(null);

        $result = $this->voter->vote($token, null, [GradingModeVoter::VIEW]);

        self::assertSame(GradingModeVoter::ACCESS_DENIED, $result);
    }

    #[Test]
    public function itGrantsViewToSuperAdmin(): void
    {
        $result = $this->voteWithRole('ROLE_SUPER_ADMIN', GradingModeVoter::VIEW);
        self::assertSame(GradingModeVoter::ACCESS_GRANTED, $result);
    }

    #[Test]
    public function itGrantsViewToAdmin(): void
    {
        $result = $this->voteWithRole('ROLE_ADMIN', GradingModeVoter::VIEW);
        self::assertSame(GradingModeVoter::ACCESS_GRANTED, $result);
    }

    #[Test]
    public function itGrantsViewToProf(): void
    {
        $result = $this->voteWithRole('ROLE_PROF', GradingModeVoter::VIEW);
        self::assertSame(GradingModeVoter::ACCESS_GRANTED, $result);
    }

    #[Test]
    public function itGrantsViewToVieScolaire(): void
    {
        $result = $this->voteWithRole('ROLE_VIE_SCOLAIRE', GradingModeVoter::VIEW);
        self::assertSame(GradingModeVoter::ACCESS_GRANTED, $result);
    }

    #[Test]
    public function itGrantsViewToSecretariat(): void
    {
        $result = $this->voteWithRole('ROLE_SECRETARIAT', GradingModeVoter::VIEW);
        self::assertSame(GradingModeVoter::ACCESS_GRANTED, $result);
    }

    #[Test]
    public function itDeniesViewToParent(): void
    {
        $result = $this->voteWithRole('ROLE_PARENT', GradingModeVoter::VIEW);
        self::assertSame(GradingModeVoter::ACCESS_DENIED, $result);
    }

    #[Test]
    public function itDeniesViewToEleve(): void
    {
        $result = $this->voteWithRole('ROLE_ELEVE', GradingModeVoter::VIEW);
        self::assertSame(GradingModeVoter::ACCESS_DENIED, $result);
    }

    #[Test]
    public function itGrantsConfigureToSuperAdmin(): void
    {
        $result = $this->voteWithRole('ROLE_SUPER_ADMIN', GradingModeVoter::CONFIGURE);
        self::assertSame(GradingModeVoter::ACCESS_GRANTED, $result);
    }

    #[Test]
    public function itGrantsConfigureToAdmin(): void
    {
        $result = $this->voteWithRole('ROLE_ADMIN', GradingModeVoter::CONFIGURE);
        self::assertSame(GradingModeVoter::ACCESS_GRANTED, $result);
    }

    #[Test]
    public function itDeniesConfigureToProf(): void
    {
        $result = $this->voteWithRole('ROLE_PROF', GradingModeVoter::CONFIGURE);
        self::assertSame(GradingModeVoter::ACCESS_DENIED, $result);
    }

    #[Test]
    public function itDeniesConfigureToVieScolaire(): void
    {
        $result = $this->voteWithRole('ROLE_VIE_SCOLAIRE', GradingModeVoter::CONFIGURE);
        self::assertSame(GradingModeVoter::ACCESS_DENIED, $result);
    }

    #[Test]
    public function itDeniesConfigureToSecretariat(): void
    {
        $result = $this->voteWithRole('ROLE_SECRETARIAT', GradingModeVoter::CONFIGURE);
        self::assertSame(GradingModeVoter::ACCESS_DENIED, $result);
    }

    private function voteWithRole(string $role, string $attribute): int
    {
        $user = $this->createMock(UserInterface::class);
        $user->method('getRoles')->willReturn([$role]);

        $token = $this->createMock(TokenInterface::class);
        $token->method('getUser')->willReturn($user);

        return $this->voter->vote($token, null, [$attribute]);
    }
}
