<?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');
        $method->setAccessible(true);

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

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

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

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

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

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

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

        $event->expects($this->once())
            ->method('isMasterRequest')
            ->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');
        $method->setAccessible(true);

        $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()
    {
        return [
            // Test redirect without '**' in destination
            'normal' => [
                '/old-page',
                '/old-page',
                '/new-page',
                '/new-page'
            ],
            // Test redirect with '**' in destination
            'multiple' => [
                '/old-page/some/path',
                '/old-page/**',
                '/new-page/**',
                '/new-page/some/path'
            ],
            // Test redirect with wildcard in origin URL
            'single' => [
                '/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'
            ],
            // Commented because it's not supported yet
//            // Test redirect with multiple invert wildcard in origin URL
//            'multiple-invert-wildcard' => [
//                '/old-page/2/1',
//                '/old-page/*2*/*1*',
//                '/new-page/*1*/*2*',
//                '/new-page/1/2'
//            ],
        ];
    }
}
