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

use Chill\MainBundle\Doctrine\Model\Point;
use Chill\MainBundle\Entity\Address;
use Chill\MainBundle\Entity\AddressReference;
use Chill\MainBundle\Repository\AddressRepository;
use Chill\MainBundle\Test\PrepareClientTrait;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;

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

    private AddressRepository $addressRepository;

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

    /**
     * @dataProvider addressToReviewProvider
     */
    public function testMarkAddressAsReviewed(int $addressId): void
    {
        $client = $this->getClientAuthenticated();

        $client->request('POST', "/api/1.0/main/address/reference-match/{$addressId}/set/reviewed");

        $this->assertResponseIsSuccessful();

        $this->addressRepository = self::getContainer()->get(AddressRepository::class);
        $address = $this->addressRepository->find($addressId);

        $this->assertEquals(Address::ADDR_REFERENCE_STATUS_REVIEWED, $address->getRefStatus());
    }

    public static function addressToReviewProvider(): iterable
    {
        self::bootKernel();
        $em = self::getContainer()->get(EntityManagerInterface::class);

        $nb = $em->createQuery('SELECT count(a) FROM '.Address::class.' a')
            ->getSingleScalarResult();

        if (0 === $nb) {
            throw new \RuntimeException("There aren't any address with a ref status 'matched'");
        }

        /** @var Address $address */
        $address = $em->createQuery('SELECT a FROM '.Address::class.' a')
            ->setFirstResult(random_int(0, $nb))
            ->setMaxResults(1)
            ->getSingleResult();

        $address->setRefStatus(Address::ADDR_REFERENCE_STATUS_TO_REVIEW);
        $em->flush();

        yield [$address->getId()];

        self::ensureKernelShutdown();
    }

    /**
     * @dataProvider addressUnsyncedProvider
     */
    public function testSyncAddressWithReference(int $addressId): void
    {
        $client = $this->getClientAuthenticated();

        $client->request('POST', "/api/1.0/main/address/reference-match/{$addressId}/sync-with-reference");

        $this->assertResponseIsSuccessful();

        $this->addressRepository = self::getContainer()->get(AddressRepository::class);
        $address = $this->addressRepository->find($addressId);

        $this->assertEquals(Address::ADDR_REFERENCE_STATUS_MATCH, $address->getRefStatus());
        $this->assertEquals($address->getAddressReference()->getStreet(), $address->getStreet());
        $this->assertEquals($address->getAddressReference()->getStreetNumber(), $address->getStreetNumber());
        $this->assertEquals($address->getAddressReference()->getPoint()->toWKT(), $address->getPoint()->toWKT());
    }

    public static function addressUnsyncedProvider(): iterable
    {
        self::bootKernel();
        $em = self::getContainer()->get(EntityManagerInterface::class);

        $nb = $em->createQuery('SELECT count(a) FROM '.AddressReference::class.' a')
            ->getSingleScalarResult();

        if (0 === $nb) {
            throw new \RuntimeException("There isn't any address reference");
        }

        $ref = $em->createQuery('SELECT a FROM '.AddressReference::class.' a')
            ->setMaxResults(1)
            ->setFirstResult(random_int(0, $nb - 1))
            ->getSingleResult();

        $address = Address::createFromAddressReference($ref);

        // make the address dirty
        $address->setStreet('tagada')
            ->setStreetNumber('-250')
            ->setPoint(Point::fromLonLat(0, 0))
            ->setRefStatus(Address::ADDR_REFERENCE_STATUS_TO_REVIEW);

        $em->persist($address);
        $em->flush();

        yield [$address->getId()];

        self::ensureKernelShutdown();
    }
}
