<?php

namespace AutoAdmin\Bundle\Tests\Unit\Seo\EventListener;

use AutoAdmin\Bundle\Seo\Entity\Redirect;
use AutoAdmin\Bundle\Seo\EventListener\RedirectEventListener;
use PHPUnit\Framework\TestCase;
use ReflectionClass;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Event\RequestEvent;

class RedirectEventListenerTest extends TestCase
{
    public function testSearchMatchingRedirectIsNotMasterRequest()
    {
        $reflect = new ReflectionClass(RedirectEventListener::class);
        $method = $reflect->getMethod('searchMatchingRedirect');

        $redirectEventListener = $this->getMockBuilder(RedirectEventListener::class)
            ->disableOriginalConstructor()
            ->getMock();

        $event = $this->getMockBuilder(RequestEvent::class)
            ->disableOriginalConstructor()
            ->onlyMethods(['isMainRequest'])
            ->getMock();

        $event->expects($this->once())
            ->method('isMainRequest')
            ->willReturn(false);

        $this->assertNull($method->invokeArgs($redirectEventListener, [$event]));
    }

    /**
     * @dataProvider dataProviderTestSearchMatchingRedirectExcludeUri
     */
    public function testSearchMatchingRedirectExcludeUri(string $uri)
    {
        $reflect = new ReflectionClass(RedirectEventListener::class);
        $method = $reflect->getMethod('searchMatchingRedirect');

        $redirectEventListener = $this->getMockBuilder(RedirectEventListener::class)
            ->disableOriginalConstructor()
            ->getMock();

        $event = $this->getMockBuilder(RequestEvent::class)
            ->disableOriginalConstructor()
            ->onlyMethods(['isMainRequest', 'getRequest'])
            ->getMock();

        $event->expects($this->once())
            ->method('isMainRequest')
            ->willReturn(true);

        $request = $this->getMockBuilder(Request::class)
            ->disableOriginalConstructor()
            ->onlyMethods(['getRequestUri'])
            ->getMock();

        $request->expects($this->once())
            ->method('getRequestUri')
            ->willReturn($uri);

        $event->expects($this->once())
            ->method('getRequest')
            ->willReturn($request);

        $this->assertNull($method->invokeArgs($redirectEventListener, [$event]));
    }

    public function dataProviderTestSearchMatchingRedirectExcludeUri()
    {
        return [
            'toolbar' => ['/_wdt/'],
            'admin' => ['/admin/'],
        ];
    }

    /**
     * @dataProvider dataProviderTestHandleDestination
     */
    public function testHandleDestination(string $uri, string $origin, string $destination, string $expected)
    {
        $reflect = new ReflectionClass(RedirectEventListener::class);
        $method = $reflect->getMethod('handleDestination');

        $redirectEventListener = $this->getMockBuilder(RedirectEventListener::class)
            ->disableOriginalConstructor()
            ->getMock();

        $redirect = $this->getMockBuilder(Redirect::class)
            ->disableOriginalConstructor()
            ->getMock();

        $redirect->expects($this->once())
            ->method('getDestination')
            ->willReturn($destination);

        $redirect->expects($this->once())
            ->method('getOrigin')
            ->willReturn($origin);

        $this->assertEquals($expected, $method->invokeArgs($redirectEventListener, [$redirect, $uri]));
    }

    public function dataProviderTestHandleDestination(): array
    {
        return [
            // Test redirect classic
            'normal' => [
                '/old-page',
                '/old-page',
                '/new-page',
                '/new-page',
            ],
            // Test redirect with '**' at the end
            'multiple-end' => [
                '/old-page/some/path',
                '/old-page/**',
                '/new-page/**',
                '/new-page/some/path',
            ],
            // Test redirect with '**' at a middle
            'multiple-middle' => [
                '/old-page/some/path',
                '/old-**/some/path',
                '/new-**/some/path',
                '/new-page/some/path',
            ],
            // Test redirect with wildcard in origin URL
            'single-end' => [
                '/old-something/page',
                '/old-something/*',
                '/new-page',
                '/new-page',
            ],
            // Test redirect with wildcard in origin URL
            'single-middle' => [
                '/old-something/page',
                '/old-*/page',
                '/new-page',
                '/new-page',
            ],
            // Test redirect with numerated wildcard in origin URL
            'single-numerated' => [
                '/old-page/1',
                '/old-page/*1*',
                '/new-page/*1*',
                '/new-page/1',
            ],
            // Test redirect with multiple wildcard in origin URL
            'multiple-wildcard' => [
                '/old-page/1/2/3',
                '/old-page/*1*/*2*/*3*',
                '/new-page/*1*/*2*/*3*',
                '/new-page/1/2/3',
            ],
            // Test redirect with multiple mixed wildcard in origin URL
            'multiple-mixed-wildcard' => [
                '/old-page/1/2/3',
                '/old-page/*1*/*2*/*3*',
                '/new-page/*3*/*1*/*2*',
                '/new-page/3/1/2',
            ],
        ];
    }
}
