<?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\Search;

use Chill\MainBundle\Test\PrepareClientTrait;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;

/**
 * Test Person search.
 *
 * @internal
 *
 * @coversNothing
 */
final class PersonSearchTest extends WebTestCase
{
    use PrepareClientTrait;

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

    public function testDefaultAccented(): never
    {
        $this->markTestSkipped('skipped until adapted to new fixtures');
        $crawlerSpecial = $this->generateCrawlerForSearch('@person manço');

        $this->assertMatchesRegularExpression('/MANÇO/', $crawlerSpecial->filter('.list-with-period')->text());

        $crawlerNoSpecial = $this->generateCrawlerForSearch('@person manco');

        $this->assertMatchesRegularExpression('/MANÇO/', $crawlerNoSpecial->filter('.list-with-period')->text());

        $crawlerSpecial = $this->generateCrawlerForSearch('@person Étienne');

        $this->assertMatchesRegularExpression('/Étienne/', $crawlerSpecial->filter('.list-with-period')->text());

        $crawlerNoSpecial = $this->generateCrawlerForSearch('@person etienne');

        $this->assertMatchesRegularExpression('/Étienne/', $crawlerNoSpecial->filter('.list-with-period')->text());
    }

    public function testExpected()
    {
        $client = $this->getAuthenticatedClient();

        $crawler = $client->request('GET', '/fr/search', [
            'q' => '@person Depardieu',
        ]);

        $this->assertMatchesRegularExpression('/DEPARDIEU/', $crawler->filter('.list-with-period')->text());
    }

    public function testExpectedNamed()
    {
        $client = $this->getAuthenticatedClient();

        $crawler = $client->request('GET', '/fr/search', [
            'q' => '@person Depardieu', 'name' => 'person_regular',
        ]);

        $this->assertMatchesRegularExpression('/DEPARDIEU/', $crawler->filter('.list-with-period')->text());
    }

    public function testLastNameAccentued()
    {
        $crawlerSpecial = $this->generateCrawlerForSearch('@person lastname:manço');

        $this->assertMatchesRegularExpression('/MANÇO/', $crawlerSpecial->filter('.list-with-period')->text());

        self::ensureKernelShutdown();

        $crawlerNoSpecial = $this->generateCrawlerForSearch('@person lastname:manco');

        $this->assertMatchesRegularExpression('/MANÇO/', $crawlerNoSpecial->filter('.list-with-period')->text());
    }

    public function testSearchBirthdate()
    {
        $crawler = $this->generateCrawlerForSearch('@person birthdate:1948-12-27');

        $this->assertMatchesRegularExpression('/Gérard/', $crawler->filter('.list-with-period')->text());
        $this->assertMatchesRegularExpression('/Bart/', $crawler->filter('.list-with-period')->text());
    }

    public function testSearchByFirstName()
    {
        $crawler = $this->generateCrawlerForSearch('@person firstname:Jean');

        $this->assertMatchesRegularExpression('/DEPARDIEU/', $crawler->filter('.list-with-period')->text());
    }

    public function testSearchByFirstNameAccented()
    {
        $crawlerSpecial = $this->generateCrawlerForSearch('@person firstname:Gérard');

        $this->assertMatchesRegularExpression('/Gérard/', $crawlerSpecial->filter('.list-with-period')->text());

        self::ensureKernelShutdown();

        $crawlerNoSpecial = $this->generateCrawlerForSearch('@person firstname:Gerard');

        $this->assertMatchesRegularExpression('/Gérard/', $crawlerNoSpecial->filter('.list-with-period')->text());
    }

    public function testSearchByFirstNameLower()
    {
        $crawler = $this->generateCrawlerForSearch('@person firstname:Gérard');

        $this->assertMatchesRegularExpression('/DEPARDIEU/', $crawler->filter('.list-with-period')->text());
    }

    public function testSearchByFirstNameLower2()
    {
        $crawler = $this->generateCrawlerForSearch('@person firstname:jean');

        $this->assertMatchesRegularExpression('/DEPARDIEU/', $crawler->filter('.list-with-period')->text());
    }

    public function testSearchByFirstNamePartim()
    {
        $crawler = $this->generateCrawlerForSearch('@person firstname:Ger');

        $this->assertMatchesRegularExpression('/DEPARDIEU/', $crawler->filter('.list-with-period')->text());
    }

    public function testSearchByFirstNamePartim2()
    {
        $crawler = $this->generateCrawlerForSearch('@person firstname:ean');

        $this->assertMatchesRegularExpression('/DEPARDIEU/', $crawler->filter('.list-with-period')->text());
    }

    public function testSearchByLastName()
    {
        $crawler = $this->generateCrawlerForSearch('@person lastname:Depardieu');

        $this->assertMatchesRegularExpression('/DEPARDIEU/', $crawler->filter('.list-with-period')->text());
    }

    public function testSearchCombineBirthdateAndLastName(): never
    {
        $this->markTestSkipped('skipped until adapted to new fixtures');
        $crawler = $this->generateCrawlerForSearch('@person birthdate:1948-12-27 lastname:(Van Snick)');

        $this->assertMatchesRegularExpression('/Bart/', $crawler->filter('.list-with-period')->text());
        $this->assertDoesNotMatchRegularExpression('/DEPARDIEU/', $crawler->filter('.list-with-period')->text());
    }

    public function testSearchCombineGenderAndLastName(): never
    {
        $this->markTestSkipped('skipped until adapted to new fixtures');
        $crawler = $this->generateCrawlerForSearch('@person gender:woman lastname:(Depardieu)');

        $this->assertMatchesRegularExpression('/Charline/', $crawler->filter('.list-with-period')->text());
        $this->assertDoesNotMatchRegularExpression('/Gérard/', $crawler->filter('.list-with-period')->text());
    }

    public function testSearchCombineLastnameAndFirstName(): never
    {
        $this->markTestSkipped('skipped until adapted to new fixtures');
        $crawler = $this->generateCrawlerForSearch('@person lastname:Depardieu firstname:Jean');

        $this->assertMatchesRegularExpression('/Depardieu/', $crawler->filter('.list-with-period')->text());
        // if this is a AND clause, Jean Depardieu should not appears
        $this->assertDoesNotMatchRegularExpression(
            '/Gérard/',
            $crawler->filter('.list-with-period')->text(),
            'assert clause firstname and nationality are AND'
        );
    }

    public function testSearchCombineLastnameAndNationality(): never
    {
        $this->markTestSkipped('skipped until adapted to new fixtures');
        $crawler = $this->generateCrawlerForSearch('@person lastname:Depardieu nationality:RU');

        $this->assertMatchesRegularExpression('/Gérard/', $crawler->filter('.list-with-period')->text());
        // if this is a AND clause, Jean Depardieu should not appears
        $this->assertDoesNotMatchRegularExpression(
            '/Jean/',
            $crawler->filter('.list-with-period')->text(),
            'assert clause firstname and nationality are AND'
        );
    }

    public function testSearchMultipleTrigramUseAndClauseInDefault(): never
    {
        $this->markTestSkipped('skipped until adapted to new fixtures');
        $crawler = $this->generateCrawlerForSearch('@person cha dep');

        $this->assertMatchesRegularExpression('/Charline/', $crawler->filter('.list-with-period')->text());
        $this->assertDoesNotMatchRegularExpression('/Gérard/', $crawler->filter('.list-with-period')->text());
        $this->assertDoesNotMatchRegularExpression('/Jean/', $crawler->filter('.list-with-period')->text());
    }

    /**
     * test that person which a user cannot see are not displayed in results.
     */
    public function testSearchWithAuthorization()
    {
        $crawlerCanSee = $this->generateCrawlerForSearch('Gérard', 'center a_social');

        $this->assertMatchesRegularExpression(
            '/DEPARDIEU/',
            $crawlerCanSee->text(),
            'center a_social may see "Depardieu" in center a'
        );
        self::ensureKernelShutdown();

        $crawlerCannotSee = $this->generateCrawlerForSearch('Gérard', 'center b_social');
        $this->assertDoesNotMatchRegularExpression(
            '/DEPARDIEU/',
            $crawlerCannotSee->text(),
            'center b_social may not see "Depardieu" in center b'
        );
    }

    private function generateCrawlerForSearch($pattern, $username = 'center a_social')
    {
        $client = $this->getAuthenticatedClient($username);

        $crawler = $client->request('GET', '/fr/search', [
            'q' => $pattern,
        ]);

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

        return $crawler;
    }

    /**
     * @return \Symfony\Component\BrowserKit\AbstractBrowser
     */
    private function getAuthenticatedClient(mixed $username = 'center a_social')
    {
        return $this->getClientAuthenticated($username);
    }
}
