<?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\Test\PrepareClientTrait;
use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Entity\Relationships\Relation;
use Chill\PersonBundle\Entity\Relationships\Relationship;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Symfony\Component\HttpFoundation\Request;

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

    /**
     * A cache for all relations.
     *
     * @var array<int, Relation>|null
     */
    private static ?array $relations = null;

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

    /**
     * @dataProvider personProvider
     */
    public function testGetRelationshipByPerson(int $personId)
    {
        self::ensureKernelShutdown();
        $client = $this->getClientAuthenticated();
        $client->request(Request::METHOD_GET, sprintf('/api/1.0/relations/relationship/by-person/%d.json', $personId));

        $response = $client->getResponse();
        $this->assertEquals(200, $response->getStatusCode(), 'Test to see that API response returns a status code 200');
    }

    public static function personProvider(): array
    {
        self::bootKernel();
        $em = self::getContainer()->get(EntityManagerInterface::class);
        $personIdHavingRelation = $em->createQueryBuilder()
            ->select('p.id')
            ->from(Person::class, 'p')
            ->join('p.centerCurrent', 'center_current')
            ->join('center_current.center', 'c')
            ->where('c.name LIKE :name')
            ->andWhere('EXISTS (SELECT 1 FROM '.Relationship::class.' r WHERE r.fromPerson = p OR r.toPerson = p)')
            ->setParameter('name', 'Center A')
            ->getQuery()
            ->setMaxResults(1)
            ->getSingleScalarResult();

        $personIdWithoutRelation = $em->createQueryBuilder()
            ->select('p.id')
            ->from(Person::class, 'p')
            ->join('p.centerCurrent', 'center_current')
            ->join('center_current.center', 'c')
            ->where('c.name LIKE :name')
            ->andWhere('NOT EXISTS (SELECT 1 FROM '.Relationship::class.' r WHERE r.fromPerson = p OR r.toPerson = p)')
            ->setParameter('name', 'Center A')
            ->getQuery()
            ->setMaxResults(1)
            ->getSingleScalarResult();

        self::ensureKernelShutdown();

        return [
            [$personIdHavingRelation, $personIdWithoutRelation],
        ];
    }

    /**
     * @dataProvider relationProvider
     */
    public function testPostRelationship(mixed $fromPersonId, mixed $toPersonId, mixed $relationId, mixed $isReverse): void
    {
        $client = $this->getClientAuthenticated();

        $client->request(
            Request::METHOD_POST,
            '/api/1.0/relations/relationship.json',
            [],
            [],
            [],
            \json_encode([
                'type' => 'relationship',
                'fromPerson' => ['id' => $fromPersonId, 'type' => 'person'],
                'toPerson' => ['id' => $toPersonId, 'type' => 'person'],
                'relation' => ['id' => $relationId, 'type' => 'relation'],
                'reverse' => $isReverse,
            ], JSON_THROW_ON_ERROR)
        );

        $response = $client->getResponse();
        $this->assertEquals(200, $response->getStatusCode());
    }

    public static function relationProvider(): array
    {
        self::bootKernel();
        $em = self::getContainer()->get(EntityManagerInterface::class);
        $personIdWithoutRelations = $em->createQueryBuilder()
            ->select('p.id')
            ->from(Person::class, 'p')
            ->join('p.centerCurrent', 'center_current')
            ->join('center_current.center', 'c')
            ->where('c.name LIKE :name')
            ->andWhere('NOT EXISTS (SELECT 1 FROM '.Relationship::class.' r WHERE r.fromPerson = p OR r.toPerson = p)')
            ->setParameter('name', 'Center A')
            ->getQuery()
            ->setMaxResults(2)
            ->getResult();

        self::ensureKernelShutdown();

        return [
            [$personIdWithoutRelations[0]['id'], $personIdWithoutRelations[1]['id'], self::getRandomRelation($em)->getId(), true],
        ];
    }

    private static function getRandomRelation(EntityManagerInterface $em): Relation
    {
        if (null === self::$relations) {
            self::$relations = $em->getRepository(Relation::class)
                ->findAll();
        }

        return self::$relations[\array_rand(self::$relations)];
    }
}
