<?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 Services\Import;

use Chill\MainBundle\Entity\Address;
use Chill\MainBundle\Entity\PostalCode;
use Chill\MainBundle\Repository\AddressReferenceRepository;
use Chill\MainBundle\Repository\CountryRepository;
use Chill\MainBundle\Service\Import\AddressReferenceBaseImporter;
use Chill\MainBundle\Service\Import\AddressToReferenceMatcher;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;

/**
 * @internal
 *
 * @coversNothing
 */
class AddressToReferenceMatcherTest extends KernelTestCase
{
    private AddressToReferenceMatcher $addressToReferenceMatcher;

    private AddressReferenceRepository $addressReferenceRepository;

    private CountryRepository $countryRepository;

    private EntityManagerInterface $entityManager;

    private AddressReferenceBaseImporter $addressReferenceBaseImporter;

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

        $this->addressToReferenceMatcher = self::getContainer()->get(AddressToReferenceMatcher::class);
        $this->addressReferenceRepository = self::getContainer()->get(AddressReferenceRepository::class);
        $this->countryRepository = self::getContainer()->get(CountryRepository::class);
        $this->addressReferenceBaseImporter = self::getContainer()->get(AddressReferenceBaseImporter::class);
        $this->entityManager = self::getContainer()->get(EntityManagerInterface::class);
    }

    public function testCheckAddressesMatchingReferences(): void
    {
        if (null === $belgium = $this->countryRepository->findOneBy(['countryCode' => 'BE'])) {
            throw new \RuntimeException('Belgium not found');
        }

        $postalCode = (new PostalCode())
            ->setName('test for matcher')
            ->setPostalCodeSource('test for matcher')
            ->setCode('78910')
            ->setRefPostalCodeId($refPostalCodeId = '78910'.uniqid())
            ->setCountry($belgium)
        ;
        $this->entityManager->persist($postalCode);
        $this->entityManager->flush();

        $this->addressReferenceBaseImporter->importAddress(
            $refAddress = '010203_test'.uniqid(),
            $refPostalCodeId,
            '78910',
            $street = 'Rue Poulet',
            $streetNumber = '14',
            'test_matcher',
            $lat = 50.0123456789,
            $lon = 5.0123456789,
            4326
        );
        $this->addressReferenceBaseImporter->finalize();

        if (null === $addressReference = $this->addressReferenceRepository->findOneBy(['refId' => $refAddress])) {
            throw new \RuntimeException('address reference not created');
        }

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

        $this->assertEquals('Rue Poulet', $address->getStreet());

        $this->entityManager->persist($address);
        $this->entityManager->flush();

        // we update the address
        $this->addressReferenceBaseImporter->importAddress(
            $refAddress,
            $refPostalCodeId,
            '78910',
            'Rue Poulet aux amandes',
            '14',
            'test_matcher',
            50.01234456789,
            5.0123456789,
            4326
        );
        $this->addressReferenceBaseImporter->finalize();

        $this->entityManager->flush();

        $this->addressToReferenceMatcher->checkAddressesMatchingReferences();

        $this->entityManager->refresh($address);

        $this->assertEquals('to_review', $address->getRefStatus());

        // we update the address
        $this->addressReferenceBaseImporter->importAddress(
            $refAddress,
            $refPostalCodeId,
            '78910',
            $street,
            $streetNumber,
            'test_matcher',
            $lat,
            $lon,
            4326
        );
        $this->addressReferenceBaseImporter->finalize();

        $this->addressToReferenceMatcher->checkAddressesMatchingReferences();

        $this->entityManager->refresh($address);

        $this->assertEquals('Rue Poulet', $address->getStreet());
        $this->assertEquals('match', $address->getRefStatus());
    }
}
