<?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\PersonBundle\Entity\Person;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;

/**
 * @internal
 *
 * @coversNothing
 */
final class PersonAddressControllerTest extends WebTestCase
{
    /**
     * @var \Symfony\Component\BrowserKit\AbstractBrowser
     */
    protected $client;

    /**
     * @var \Doctrine\ORM\EntityManagerInterface The entity manager
     */
    protected $em;

    /**
     * @var Person The person on which the test is executed
     */
    protected static $person;

    /**
     * @var \Chill\MainBundle\Entity\PostalCode
     */
    protected $postalCode;

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

        $em = self::$kernel->getContainer()
            ->get('doctrine.orm.entity_manager');

        $center = $em->getRepository(\Chill\MainBundle\Entity\Center::class)
            ->findOneBy(['name' => 'Center A']);

        self::$person = (new Person())
            ->setLastName('Tested person')
            ->setFirstName('Test')
            ->setCenter($center)
            ->setGender(Person::MALE_GENDER);

        $em->persist(self::$person);
        $em->flush();
    }

    /**
     * Prepare client and create a random person.
     */
    protected function setUp(): void
    {
        self::bootKernel();

        $this->em = self::$kernel->getContainer()
            ->get('doctrine.orm.entity_manager');

        $this->postalCode = $this->em->getRepository(\Chill\MainBundle\Entity\PostalCode::class)
            ->findOneBy(['code' => 1000]);

        $this->client = self::createClient([], [
            'PHP_AUTH_USER' => 'center a_social',
            'PHP_AUTH_PW' => 'password',
        ]);
    }

    public static function tearDownAfter()
    {
        $this->refreshPerson();
        $this->em->remove(self::$person);
        $this->em->flush();
    }

    /**
     * @depends testEmptyList
     */
    public function testCreateAddress()
    {
        $crawler = $this->client->request('GET', '/fr/person/'.
                self::$person->getId().'/address/new');

        $this->assertTrue($this->client->getResponse()->isSuccessful());

        // get the form and populate the most obvious fields (postcode will come later)
        $form = $crawler->filter('.bt-create')->form([
            'address[streetAddress1]' => 'Rue de la Paix, 50',
            'address[streetAddress2]' => $this->postalCode->getId(),
            'address[validFrom]' => '15-01-2016',
        ]);

        // select a random postal code
        $values = $form['address[postCode]']->availableOptionValues();
        $form['address[postCode]']->setValue($values[array_rand($values)]);

        $this->client->submit($form);

        $crawler = $this->client->followRedirect();

        $this->assertMatchesRegularExpression(
            '|/fr/person/[0-9]{1,}/address/list|',
            $this->client->getHistory()->current()->getUri(),
            'assert that the current page is on |/fr/person/[0-9]{1,}/address/list|'
        );
        $this->assertEquals(
            1,
            $crawler
                ->filter('div.flash_message.success')
                ->count(),
            'Asserting that the response page contains a success flash message'
        );
        $this->assertEquals(
            1,
            $crawler
                ->filter('td:contains("Rue de la Paix, 50")')
                ->count(),
            'Asserting that the page contains the new address'
        );
    }

    public function testEmptyList()
    {
        $crawler = $this->client->request('GET', '/fr/person/'.
                self::$person->getId().'/address/list');

        $this->assertTrue($this->client->getResponse()->isSuccessful());

        $this->assertEquals(
            1,
            $crawler->filter('td:contains("Pas d\'adresse renseignée")')
                ->count(),
            "assert that a message say 'no address given'"
        );
    }

    /**
     * @depends testCreateAddress
     */
    public function testUpdateAddress()
    {
        $this->refreshPerson();
        $address = self::$person->getLastAddress();

        $crawler = $this->client->request('GET', '/fr/person/'.self::$person->getId()
                .'/address/'.$address->getId().'/edit');

        $this->assertTrue($this->client->getResponse()->isSuccessful());

        $form = $crawler->filter('.bt-save')->form([
            'address[streetAddress1]' => 'Rue du Trou Normand, 15',
            'address[validFrom]' => '15-01-2015',
        ]);

        $this->client->submit($form);

        $crawler = $this->client->followRedirect();

        $this->assertMatchesRegularExpression(
            '|/fr/person/[0-9]{1,}/address/list|',
            $this->client->getHistory()->current()->getUri(),
            'assert that the current page is on |/fr/person/[0-9]{1,}/address/list|'
        );
        $this->assertGreaterThan(
            0,
            $crawler
                ->filter('div.flash_message.success')
                ->count(),
            'Asserting that the response page contains a success flash message'
        );
        $this->assertEquals(
            1,
            $crawler
                ->filter('td:contains("Rue du Trou Normand")')
                ->count(),
            'Asserting that the page contains the new address'
        );
    }

    /**
     * Reload the person from the db.
     */
    protected function refreshPerson()
    {
        self::$person = $this->em->getRepository(Person::class)
            ->find(self::$person->getId());
    }
}
