<?php

declare(strict_types=1);

/*
 * Chill is a software for social workers
 *
 * For the full copyright and license information, please view
 * the LICENSE file that was distributed with this source code.
 */

namespace Chill\MainBundle\Tests\Security\Authorization;

use Chill\MainBundle\Entity\SavedExport;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Entity\UserGroup;
use Chill\MainBundle\Export\ExportInterface;
use Chill\MainBundle\Export\ExportManager;
use Chill\MainBundle\Security\Authorization\SavedExportVoter;
use PHPUnit\Framework\TestCase;
use Prophecy\Argument;
use Prophecy\PhpUnit\ProphecyTrait;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface;
use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface;

/**
 * @internal
 *
 * @coversNothing
 */
class SavedExportVoterTest extends TestCase
{
    use ProphecyTrait;

    /**
     * @dataProvider voteProvider
     */
    public function testVote(string $attribute, mixed $savedExport, User $user, $expectedResult, ?bool $isGranted = null): void
    {
        $export = $this->prophesize(ExportInterface::class);
        $exportManager = $this->prophesize(ExportManager::class);
        $exportManager->getExport('dummy_export')->willReturn($export->reveal());
        $exportManager->isGrantedForElement(Argument::any())->willReturn($isGranted);

        $accessDecisionManager = $this->prophesize(AccessDecisionManagerInterface::class);

        $voter = new SavedExportVoter($exportManager->reveal(), $accessDecisionManager->reveal());
        $token = new UsernamePasswordToken($user, 'default', ['ROLE_USER']);

        self::assertEquals($expectedResult, $voter->vote($token, $savedExport, [$attribute]));
    }

    public static function voteProvider(): iterable
    {
        $alls = [SavedExportVoter::GENERATE, SavedExportVoter::GENERATE, SavedExportVoter::EDIT, SavedExportVoter::DELETE];
        $userA = new User();
        $userB = new User();
        $userC = new User();
        $group = new UserGroup();
        $group->addUser($userC);

        $savedExport = new SavedExport();
        $savedExport->setExportAlias('dummy_export');
        $savedExport->setUser($userA);

        // abstain
        foreach ($alls as $attribute) {
            yield [
                $attribute,
                new \stdClass(),
                $userA,
                VoterInterface::ACCESS_ABSTAIN,
                true,
            ];
        }

        yield [
            'dummy',
            $savedExport,
            $userA,
            VoterInterface::ACCESS_ABSTAIN,
            false,
        ];

        foreach ($alls as $attribute) {
            yield [
                $attribute,
                $savedExport,
                $userA,
                VoterInterface::ACCESS_GRANTED,
                true,
            ];
        }

        yield [
            SavedExportVoter::GENERATE,
            $savedExport,
            $userA,
            VoterInterface::ACCESS_DENIED,
            false,
        ];

        foreach ($alls as $attribute) {
            yield [
                $attribute,
                $savedExport,
                $userB,
                VoterInterface::ACCESS_DENIED,
                true,
            ];
        }

        $savedExport = new SavedExport();
        $savedExport->setExportAlias('dummy_export');
        $savedExport->setUser($userA);
        $savedExport->addShare($userB);

        yield [
            SavedExportVoter::GENERATE,
            $savedExport,
            $userB,
            VoterInterface::ACCESS_DENIED,
            false,
        ];

        yield [
            SavedExportVoter::GENERATE,
            $savedExport,
            $userB,
            VoterInterface::ACCESS_GRANTED,
            true,
        ];

        foreach ([SavedExportVoter::EDIT, SavedExportVoter::DELETE] as $attribute) {
            yield [
                $attribute,
                $savedExport,
                $userB,
                VoterInterface::ACCESS_DENIED,
                true,
            ];
        }
    }
}
