<?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\PersonBundle\Tests\Export\Helper;

use Chill\MainBundle\Entity\Center;
use Chill\MainBundle\Entity\Scope;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Repository\CenterRepositoryInterface;
use Chill\MainBundle\Repository\ScopeRepositoryInterface;
use Chill\MainBundle\Security\Authorization\AuthorizationHelperInterface;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Export\Helper\FilterListAccompanyingPeriodHelper;
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\QueryBuilder;
use Prophecy\Argument;
use Prophecy\PhpUnit\ProphecyTrait;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\Security\Core\Security;

/**
 * @internal
 *
 * @coversNothing
 */
final class FilterListAccompanyingPeriodHelperTest extends KernelTestCase
{
    use ProphecyTrait;

    private CenterRepositoryInterface $centerRepository;
    private ScopeRepositoryInterface $scopeRepository;
    private EntityManagerInterface $entityManager;

    protected function setUp(): void
    {
        parent::setUp();
        self::bootKernel();

        $this->centerRepository = self::getContainer()->get(CenterRepositoryInterface::class);
        $this->scopeRepository = self::getContainer()->get(ScopeRepositoryInterface::class);
        $this->entityManager = self::getContainer()->get(EntityManagerInterface::class);
    }

    /**
     * @dataProvider dataProviderTestAddFilterAccompanyingPeriod
     */
    public function testAddFilterAccompanyingPeriod(QueryBuilder $qb, ParameterBagInterface $parameterBag): void
    {
        // mock security
        $user = $this->entityManager->createQuery('SELECT u FROM '.User::class.' u')
            ->setMaxResults(1)->getSingleResult();
        if (null === $user) {
            throw new \RuntimeException('no user found');
        }

        // mock authorization helper
        $scopes = $this->scopeRepository->findAll();
        $scopesConfidentials = [] !== $scopes ? [$scopes[0]] : [];
        $authorizationHelper = $this->prophesize(AuthorizationHelperInterface::class);
        $authorizationHelper->getReachableScopes($user, AccompanyingPeriodVoter::SEE_DETAILS, Argument::type(Center::class))
            ->willReturn($scopes);
        $authorizationHelper->getReachableScopes($user, AccompanyingPeriodVoter::SEE_CONFIDENTIAL_ALL, Argument::type(Center::class))
            ->willReturn($scopesConfidentials);

        $filter = new FilterListAccompanyingPeriodHelper(
            $this->centerRepository,
            $authorizationHelper->reveal(),
            $parameterBag
        );

        $filter->addFilterAccompanyingPeriods($qb, [], $this->getACL(), $user, []);

        $qb->setMaxResults(1);
        $result = $qb->getQuery()->getResult();

        self::assertIsArray($result);
    }

    public static function dataProviderTestAddFilterAccompanyingPeriod(): iterable
    {
        self::bootKernel();
        $entityManager = self::getContainer()->get(EntityManagerInterface::class);
        $qb = $entityManager->createQueryBuilder();

        $qb
            ->select('acp.id')
            ->from(AccompanyingPeriod::class, 'acp');

        yield [
            $qb,
            new ParameterBag(['chill_main' => ['acl' => ['filter_stats_by_center' => true]]]),
        ];

        yield [
            $qb,
            new ParameterBag(['chill_main' => ['acl' => ['filter_stats_by_center' => false]]]),
        ];
    }

    /**
     * @return list<array{center: Center, circles: list<Scope>}> the ACL, structured as an array
     *
     * @throws \RuntimeException when no center or circle is found
     */
    private function getACL(): array
    {
        $centers = $this->centerRepository->findAll();
        $circles = $this->scopeRepository->findAll();

        if (0 === \count($centers)) {
            throw new \RuntimeException('No center found. Did you forget to run `doctrine:fixtures:load` command before ?');
        }

        if (0 === \count($circles)) {
            throw new \RuntimeException('No circle found. Did you forget to run `doctrine:fixtures:load` command before ?');
        }

        return [[
            'center' => $centers[0],
            'circles' => [
                $circles,
            ], ]];
    }
}
