<?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\Controller;

use Chill\MainBundle\Entity\Gender;
use Chill\MainBundle\Entity\GenderEnum;
use Chill\MainBundle\Entity\GenderIconEnum;
use Chill\MainBundle\Repository\CenterRepositoryInterface;
use Chill\MainBundle\Test\PrepareClientTrait;
use Chill\PersonBundle\Entity\Person;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;

/**
 * @internal
 *
 * @coversNothing
 */
final class PersonControllerViewTest extends WebTestCase
{
    use PrepareClientTrait;

    /**
     * @var list<array<class-string, int>>
     */
    private static array $toDelete = [];

    protected function tearDown(): void
    {
        self::ensureKernelShutdown();
    }

    public static function tearDownAfterClass(): void
    {
        self::bootKernel();

        $em = self::getContainer()->get(EntityManagerInterface::class);

        foreach (self::$toDelete as [$class, $id]) {
            $entity = $em->find($class, $id);

            if (null === $entity) {
                throw new \RuntimeException(sprintf('entity not found: %s, %d', $class, $id));
            }

            $em->remove($entity);
        }

        $em->flush();
    }

    /**
     * Test if the  view page is accessible.
     *
     * @group configurable_fields
     *
     * @dataProvider providePerson
     */
    public function testViewPerson(int $personId): void
    {
        $client = $this->getClientAuthenticated();

        $crawler = $client->request('GET', $this->makeViewPath($personId));

        self::assertResponseIsSuccessful();

        $this->assertGreaterThan(0, $crawler->filter('html:contains("Foo")')->count());
        $this->assertGreaterThan(0, $crawler->filter('html:contains("BAR")')->count());
    }

    /**
     * Test if the view page of a given person is not accessible for a user
     * of another center of the person.
     *
     * @dataProvider providePerson
     */
    public function testViewPersonAccessDeniedForUnauthorized(int $personId): void
    {
        $client = $this->getClientAuthenticated('center b_social');

        $client->request('GET', $this->makeViewPath($personId));

        self::assertResponseStatusCodeSame(
            403,
            'The view page of a person of a center A must not be accessible for user of center B'
        );
    }

    public static function providePerson(): iterable
    {
        self::bootKernel();
        $centerRepository = self::getContainer()->get(CenterRepositoryInterface::class);
        $em = self::getContainer()->get(EntityManagerInterface::class);
        $center = $centerRepository->findOneBy(['name' => 'Center A']);

        $gender = new Gender();
        $gender->setGenderTranslation(GenderEnum::MALE);
        $gender->setLabel(['fr' => 'homme']);
        $gender->setIcon(GenderIconEnum::MALE);
        $em->persist($gender);

        $person = new Person();
        $person
            ->setFirstName('Foo')
            ->setLastName('Bar')
            ->setBirthdate(new \DateTime('2017-09-30'))
            ->setGender($gender)
            ->setCenter($center);

        $em->persist($person);

        self::$toDelete[] = [Person::class, $person->getId()];

        $em->flush();

        yield [$person->getId()];

        self::ensureKernelShutdown();
    }

    private function makeViewPath(int $personId): string
    {
        return "/fr/person/{$personId}/general";
    }
}
