<?php

declare(strict_types=1);

namespace Ferienpass\AdminBundle\Tests\Security;

use Ferienpass\AdminBundle\Security\AdminRequestMatcher;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\Request;

final class AdminRequestMatcherTest extends TestCase
{
    private AdminRequestMatcher $matcher;

    protected function setUp(): void
    {
        $this->matcher = new AdminRequestMatcher();
    }

    public function testPlainAdminUrlMatches(): void
    {
        self::assertTrue($this->matcher->matches(Request::create('/admin')));
        self::assertTrue($this->matcher->matches(Request::create('/admin/')));
        self::assertTrue($this->matcher->matches(Request::create('/admin/offers')));
    }

    public function testLocalizedAdminUrlMatches(): void
    {
        self::assertTrue($this->matcher->matches(Request::create('/de/admin')));
        self::assertTrue($this->matcher->matches(Request::create('/en/admin/offers')));
    }

    public function testFragmentDispatchingAdminControllerMatches(): void
    {
        // Mirrors what Symfony's FragmentListener sets on the sub-request at
        // priority 48, before the firewall runs at priority 8.
        $request = Request::create('/_fragment?_path=...');
        $request->attributes->set('_controller', 'Ferienpass\\AdminBundle\\Controller\\Fragment\\UserNavigationController');

        self::assertTrue($this->matcher->matches($request));
    }

    public function testFragmentDispatchingCmsControllerDoesNotMatch(): void
    {
        $request = Request::create('/_fragment');
        $request->attributes->set('_controller', 'Ferienpass\\CmsBundle\\Controller\\Fragment\\UserNavigationController');

        self::assertFalse(
            $this->matcher->matches($request),
            'The admin firewall must NOT steal CMS fragment sub-requests — those belong to contao_frontend',
        );
    }

    public function testFragmentPathWithoutControllerDoesNotMatch(): void
    {
        // FragmentListener (priority 48) runs before the firewall; if it
        // decided the signature was invalid, `_controller` is never set and
        // this matcher must not accidentally whitelist the request.
        $request = Request::create('/_fragment');

        self::assertFalse($this->matcher->matches($request));
    }

    public function testNonAdminNonFragmentUrlDoesNotMatch(): void
    {
        self::assertFalse($this->matcher->matches(Request::create('/')));
        self::assertFalse($this->matcher->matches(Request::create('/account')));
        self::assertFalse($this->matcher->matches(Request::create('/api/offers')));
    }

    public function testAdminLookalikeDoesNotMatch(): void
    {
        // The regex requires `/admin` as a path segment — `/admins` or
        // `/administration` must not trip it.
        self::assertFalse($this->matcher->matches(Request::create('/admins')));
        self::assertFalse($this->matcher->matches(Request::create('/administration/foo')));
    }
}
