<?php

namespace Velis\Test\Mvc;

use Phalcon\Mvc\Dispatcher;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Velis\Filter;
use Velis\Mvc\Controller\Utils\FrontendRouteUrlConverter;
use Velis\Mvc\Router;

class FrontendRouteUrlConverterTest extends TestCase
{
    private $router;

    protected function setUp(): void
    {
        $router = new Router();

        $router->add('/some/other/route', [
            'module' => 'Does',
            'controller' => 'Not',
            'action' => 'Exist',
        ])->setName('some-other-route');

        $router->add('/building/ticket/list', [
            'module' => 'Building',
            'controller' => 'Ticket',
            'action' => 'List',
        ])->setName('building-ticket-list');

        $router->add('/building/ticket/{ticket_id}', [
            'module' => 'Building',
            'controller' => 'Ticket',
            'action' => 'Index',
        ])->setName('building-ticket-index');

        $router->add('/tickets', [
            'module' => 'Building',
            'controller' => 'Ticket',
            'action' => 'List',
        ])->setName('frontend-building-ticket-list');

        $router->add('/tickets/{ticket_id}', [
            'module' => 'Building',
            'controller' => 'Ticket',
            'action' => 'Index',
        ])->setName('frontend-building-ticket-index');

        $router->add('/building/asset/{asset_id}', [
            'module' => 'Building',
            'controller' => 'Asset',
            'action' => 'Index',
        ])->setName('building-asset-index');

        $this->router = $router;
    }

    /**
     * @dataProvider provideDataForTestGetRedirectUrl
     */
    public function testGetRedirectUrl(array $dispatcherConfig, array $filter, string $referer, ?string $expectedUrl): void
    {
        $dispatcher = $this->prepareDispatcherMock($dispatcherConfig);
        $filter = $this->prepareFilterMock($filter);

        $converter = new FrontendRouteUrlConverter(
            $this->router,
            $filter,
            $dispatcher,
            $referer
        );

        $this->assertEquals($expectedUrl, $converter->getRedirectUrl());
    }

    public function provideDataForTestGetRedirectUrl(): array
    {
        return [
            [
                'dispatcherConfig' => ['Building', 'Ticket', 'List'],
                'filter' => [],
                'referer' => '/building/ticket/list',
                'expectedUrl' => '/tickets',
            ],
            [
                'dispatcherConfig' => ['Building', 'ticket', 'List'],
                'filter' => ['building_id' => 1],
                'referer' => '/building/ticket/list?building_id=1',
                'expectedUrl' => '/tickets?building_id=1',
            ],
            [
                'dispatcherConfig' => ['Building', 'ticket', 'Index'],
                'filter' => ['ticket_id' => 1],
                'referer' => '/building/ticket?ticket_id=1',
                'expectedUrl' => '/tickets/1',
            ],
            [
                'dispatcherConfig' => ['Building', 'asset', 'index'],
                'filter' => ['asset_id' => 2],
                'referer' => '/building/asset?asset_id=2',
                'expectedUrl' => null,
            ],
        ];
    }

    private function prepareDispatcherMock(array $dispatcherConfig): MockObject
    {
        $dispatcher = $this->createPartialMock(Dispatcher::class, [
            'getModuleName',
            'getControllerName',
            'getActionName',
        ]);

        $dispatcher->method('getModuleName')->willReturn($dispatcherConfig[0]);
        $dispatcher->method('getControllerName')->willReturn($dispatcherConfig[1]);
        $dispatcher->method('getActionName')->willReturn($dispatcherConfig[2]);

        return $dispatcher;
    }

    private function prepareFilterMock(array $params): MockObject
    {
        $filter = $this->createStub(Filter::class);
        $filter->method('getArrayCopy')->willReturn($params);

        return $filter;
    }
}
