<?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 Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\KernelBrowser;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Symfony\Component\DomCrawler\Form;

/**
 * Test creation and deletion for persons.
 *
 * @internal
 *
 * @coversNothing
 */
final class PersonControllerCreateTest extends WebTestCase
{
    use PrepareClientTrait;

    public const BIRTHDATE_INPUT = 'chill_personbundle_person_creation[birthdate]';

    public const CENTER_INPUT = 'chill_personbundle_person_creation[center]';

    public const CREATEDATE_INPUT = 'chill_personbundle_person_creation[creation_date]';

    public const FIRSTNAME_INPUT = 'chill_personbundle_person_creation[firstName]';

    public const GENDER_INPUT = 'chill_personbundle_person_creation[gender]';

    public const LASTNAME_INPUT = 'chill_personbundle_person_creation[lastName]';

    public const LONG_TEXT = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero. Sed cursus ante dapibus diam. Sed nisi. Nulla quis sem at nibh elementum imperdiet. Duis sagittis ipsum. Praesent mauris. Fusce nec tellus sed augue semper porta. Mauris massa. Vestibulum lacinia arcu eget nulla. Class aptent taciti sociosq. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero. Sed cursus ante dapibus diam. Sed nisi. Nulla quis sem at nibh elementum imperdiet. Duis sagittis ipsum. Praesent mauris. Fusce nec tellus sed augue semper porta.Mauris massa. Vestibulum lacinia arcu eget nulla. Class aptent taciti sociosq.';

    private readonly KernelBrowser $client;

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

        // remove two people created during test
        $jesus = $em->getRepository(\Chill\PersonBundle\Entity\Person::class)
            ->findOneBy(['firstName' => 'God']);

        if (null !== $jesus) {
            $em->remove($jesus);
        }

        $jesus2 = $em->getRepository(\Chill\PersonBundle\Entity\Person::class)
            ->findOneBy(['firstName' => 'roger']);

        if (null !== $jesus2) {
            $em->remove($jesus2);
        }
        $em->flush();
        self::ensureKernelShutdown();
    }

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

    /**
     * Test the "add a person" page : test that required elements are present.
     *
     * see https://redmine.champs-libres.coop/projects/chillperson/wiki/Test_plan_for_page_%22add_a_person%22
     */
    public function testAddAPersonPage()
    {
        $client = $this->getClientAuthenticated();
        $crawler = $client->request('GET', '/fr/person/new');

        $this->assertTrue(
            $client->getResponse()->isSuccessful(),
            'The page is accessible at the URL /{_locale}/person/new'
        );
        $form = $crawler->selectButton("Créer l'usager")->form();

        $this->assertInstanceOf(
            Form::class,
            $form,
            'The page contains a button'
        );
        $this->assertTrue(
            $form->has(self::FIRSTNAME_INPUT),
            'The page contains a "firstname" input'
        );
        $this->assertTrue(
            $form->has(self::LASTNAME_INPUT),
            'The page contains a "lastname" input'
        );
        $this->assertTrue(
            $form->has(self::GENDER_INPUT),
            'The page contains a "gender" input'
        );
        $this->assertTrue(
            $form->has(self::BIRTHDATE_INPUT),
            'The page has a "date of birth" input'
        );

        $genderType = $form->get(self::GENDER_INPUT);
        $this->assertEquals(
            'select',
            $genderType->getType(),
            'The gender input is a select form to select a gender entity'
        );
        /*        $this->assertEquals(
                    3,
                    \count($genderType->availableOptionValues()),
                    'The gender input has three options: man, women and undefined'
                );
                $this->assertTrue(
                    \in_array('man', $genderType->availableOptionValues(), true),
                    'gender has "homme" option'
                );
                $this->assertTrue(
                    \in_array('woman', $genderType->availableOptionValues(), true),
                    'gender has "femme" option'
                );
                $this->assertFalse($genderType->hasValue(), 'The gender input is not checked');*/

        return $form;
    }

    public function testReviewExistingDetectionInversedLastNameWithFirstName(): never
    {
        $this->markTestSkipped();
        $client = $this->getClientAuthenticated();

        $crawler = $client->request('GET', '/fr/person/new');

        // test the page is loaded before continuing
        $this->assertTrue($client->getResponse()->isSuccessful());

        $form = $crawler->selectButton("Créer l'usager")->form();
        $form = $this->fillAValidCreationForm($form, 'Charline', 'dd', new \DateTime('1970-10-15'));
        $client->submit($form);

        $this->assertStringContainsString(
            'usager a un nom similaire',
            $client->getCrawler()->text(),
            'check that the page has detected the lastname of a person existing in database'
        );

        // inversion
        $form = $crawler->selectButton("Créer l'usager")->form();
        $form = $this->fillAValidCreationForm($form, 'dd', 'Charline');
        $client->submit($form);

        $this->assertStringContainsString(
            'usager a un nom similaire',
            $client->getCrawler()->text(),
            'check that the page has detected the lastname of a person existing in database'
        );
    }

    /**
     * Test the creation of a valid person.
     *
     * @return string The id of the created person
     */
    public function testValidForm()
    {
        $client = $this->getClientAuthenticated();
        $crawler = $client->request('GET', '/fr/person/new');

        $form = $crawler->selectButton("Créer l'usager")->form();
        $this->fillAValidCreationForm($form, uniqid(), uniqid());
        $client->submit($form);

        self::assertResponseRedirects();
    }

    /**
     * test adding a person with a user with multi center
     * is valid.
     */
    public function testValidFormWithMultiCenterUser()
    {
        $client = $this->getClientAuthenticated('multi_center');

        $crawler = $client->request('GET', '/fr/person/new');

        $this->assertTrue(
            $client->getResponse()->isSuccessful(),
            'The page is accessible at the URL /{_locale}/person/new'
        );
        $form = $crawler->selectButton("Créer l'usager")->form();

        // create a very long name to avoid collision
        $this->fillAValidCreationForm($form, uniqid(), uniqid());

        $this->assertTrue(
            $form->has(self::CENTER_INPUT),
            'The page contains a "center" input'
        );
        $centerInput = $form->get(self::CENTER_INPUT);
        /*
        $availableValues = $centerInput->availableOptionValues();
        $lastCenterInputValue = end($availableValues);
        $centerInput->setValue($lastCenterInputValue);
         */

        $client->submit($form);

        self::assertResponseRedirects();
    }

    private function fillAValidCreationForm(
        Form &$creationForm,
        string $firstname = 'God',
        string $lastname = 'Jesus',
        ?\DateTime $birthdate = null,
    ) {
        $creationForm->get(self::FIRSTNAME_INPUT)->setValue($firstname.'_'.uniqid());
        $creationForm->get(self::LASTNAME_INPUT)->setValue($lastname.'_'.uniqid());
        // Todo change hardcoded id
        $creationForm->get(self::GENDER_INPUT)->select(5);
        $date = $birthdate ?? new \DateTime('1947-02-01');
        $creationForm->get(self::BIRTHDATE_INPUT)->setValue($date->format('Y-m-d'));

        return $creationForm;
    }
}
