<?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\Address;
use Chill\MainBundle\Entity\AddressReference;
use Chill\MainBundle\Entity\Center;
use Chill\MainBundle\Entity\Gender;
use Chill\MainBundle\Entity\GenderEnum;
use Chill\MainBundle\Entity\GenderIconEnum;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Test\PrepareClientTrait;
use Chill\PersonBundle\Entity\Household\Household;
use Chill\PersonBundle\Entity\Household\HouseholdMember;
use Chill\PersonBundle\Entity\Person;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Symfony\Component\HttpFoundation\Request;

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

    private static array $toDelete = [];

    /**
     * @dataProvider generateHouseholdAssociatedWithAddressReference
     */
    public function testFindHouseholdByAddressReference(int $addressReferenceId, int $expectedHouseholdId)
    {
        $client = $this->getClientAuthenticated();

        $client->request(
            Request::METHOD_GET,
            "/api/1.0/person/household/by-address-reference/{$addressReferenceId}.json"
        );

        $this->assertResponseIsSuccessful();
        $data = json_decode($client->getResponse()->getContent(), true, 512, JSON_THROW_ON_ERROR);
        $this->assertArrayHasKey('count', $data);
        $this->assertArrayHasKey('results', $data);

        $householdIds = \array_map(static fn ($r) => $r['id'], $data['results']);

        $this->assertContains($expectedHouseholdId, $householdIds);
    }

    public static function generateHouseholdAssociatedWithAddressReference()
    {
        self::bootKernel();
        $em = self::getContainer()->get(EntityManagerInterface::class);
        $centerA = $em->getRepository(Center::class)->findOneBy(['name' => 'Center A']);
        $nbReference = $em->createQueryBuilder()->select('count(ar)')->from(AddressReference::class, 'ar')
            ->getQuery()->getSingleScalarResult();

        if (0 === $nbReference) {
            throw new \RuntimeException('any reference found. Add a reference in database to perform this test');
        }

        $reference = $em->createQueryBuilder()->select('ar')->from(AddressReference::class, 'ar')
            ->setFirstResult(\random_int(0, $nbReference - 1))
            ->setMaxResults(1)
            ->getQuery()->getSingleResult();

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

        $p = new Person();
        $p->setFirstname('test')->setLastName('test lastname')
            ->setGender($gender)
            ->setCenter($centerA);
        $em->persist($p);
        $h = new Household();
        $h->addMember($m = (new HouseholdMember())->setPerson($p));
        $h->addAddress($a = Address::createFromAddressReference($reference)->setValidFrom(new \DateTime('today')));
        $em->persist($a);
        $em->persist($m);
        $em->persist($h);

        $em->flush();

        self::$toDelete += [
            [HouseholdMember::class, $m->getId()],
            [User::class, $p->getId()],
            [Household::class, $h->getId()],
            [Person::class, $p->getId()],
        ];

        yield [$reference->getId(), $h->getId()];

        self::ensureKernelShutdown();
    }

    /**
     * @dataProvider generateHouseholdId
     */
    public function testSuggestAddressByHousehold(int $householdId)
    {
        $client = $this->getClientAuthenticated();

        $client->request(
            Request::METHOD_GET,
            "/api/1.0/person/address/suggest/by-household/{$householdId}.json"
        );

        $this->assertResponseIsSuccessful();
    }

    public static function generateHouseholdId()
    {
        self::bootKernel();

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

        $householdIds = $qb
            ->select('DISTINCT household.id')
            ->from(Household::class, 'household')
            ->join('household.members', 'members')
            ->join('members.person', 'person')
            ->join('person.centerCurrent', 'cc')
            ->join('cc.center', 'center')
            ->where($qb->expr()->eq('center.name', ':center_name'))
            ->andWhere($qb->expr()->gt('SIZE(person.accompanyingPeriodParticipations)', 0))
            ->setParameter('center_name', 'Center A')
            ->setMaxResults(100)
            ->getQuery()
            ->getResult();

        \shuffle($householdIds);

        yield [\array_pop($householdIds)['id']];

        yield [\array_pop($householdIds)['id']];

        yield [\array_pop($householdIds)['id']];

        self::ensureKernelShutdown();
    }

    /**
     * @dataProvider generatePersonId
     */
    public function testSuggestByAccompanyingPeriodParticipation(int $personId)
    {
        $client = $this->getClientAuthenticated();

        $client->request(
            Request::METHOD_GET,
            "/api/1.0/person/household/suggest/by-person/{$personId}/through-accompanying-period-participation.json"
        );

        $this->assertResponseIsSuccessful();
    }

    public static function generatePersonId()
    {
        self::bootKernel();

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

        $personIds = $qb
            ->select('p.id AS pid')
            ->from(Person::class, 'p')
            ->where(
                $qb->expr()->gte('SIZE(p.accompanyingPeriodParticipations)', 2)
            )
            ->getQuery()
            ->setMaxResults(1)
            ->getSingleResult();

        yield [$personIds['pid']];

        self::ensureKernelShutdown();
    }
}
