<?php

declare(strict_types=1);

namespace Ferienpass\AdminBundle\Tests\Controller;

use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Routing\Attribute\Route;

/**
 * Validates that all admin-bundle controllers have proper route attributes
 * and that route names follow the expected conventions.
 */
final class RouteConfigurationTest extends TestCase
{
    
    #[DataProvider('controllerProvider')]
    
    public function testControllerHasRouteAttribute(string $class): void
    {
        $ref = new \ReflectionClass($class);
        $classRoutes = $ref->getAttributes(Route::class);

        $methodRoutes = [];
        foreach ($ref->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) {
            if ($method->getDeclaringClass()->getName() !== $class) {
                continue;
            }
            $attrs = $method->getAttributes(Route::class);
            if ($attrs) {
                $methodRoutes = array_merge($methodRoutes, $attrs);
            }
        }

        self::assertGreaterThan(
            0,
            \count($classRoutes) + \count($methodRoutes),
            \sprintf('Controller %s should have at least one Route attribute', $class),
        );
    }

    
    #[DataProvider('namedRouteProvider')]
    
    public function testRouteNameStartsWithAdmin(string $class, string $method, string $expectedNamePrefix): void
    {
        $found = false;

        // Check method-level route attributes
        $ref = new \ReflectionMethod($class, $method);
        foreach ($ref->getAttributes(Route::class) as $attr) {
            $route = $attr->newInstance();
            if (null !== $route->getName()) {
                $found = true;
                self::assertStringStartsWith(
                    $expectedNamePrefix,
                    $route->getName(),
                    \sprintf('%s::%s route name should start with "%s"', $class, $method, $expectedNamePrefix),
                );
            }
        }

        // Also check class-level route attributes (some controllers define name there)
        $classRef = new \ReflectionClass($class);
        foreach ($classRef->getAttributes(Route::class) as $attr) {
            $route = $attr->newInstance();
            if (null !== $route->getName()) {
                $found = true;
                self::assertStringStartsWith(
                    $expectedNamePrefix,
                    $route->getName(),
                    \sprintf('%s class route name should start with "%s"', $class, $expectedNamePrefix),
                );
            }
        }

        self::assertTrue($found, \sprintf('%s::%s should have a named route', $class, $method));
    }

    public static function controllerProvider(): iterable
    {
        $controllers = [
            \Ferienpass\AdminBundle\Controller\Page\HomeController::class,
            \Ferienpass\AdminBundle\Controller\Page\LoginController::class,
            \Ferienpass\AdminBundle\Controller\Page\Error404Controller::class,
            \Ferienpass\AdminBundle\Controller\Page\SecurityController::class,
            \Ferienpass\AdminBundle\Controller\Page\LostPasswordController::class,
            \Ferienpass\AdminBundle\Controller\Page\RegistrationController::class,
            \Ferienpass\AdminBundle\Controller\FlashMessageController::class,
            \Ferienpass\AdminBundle\Controller\AdminSearchController::class,
        ];

        foreach ($controllers as $class) {
            yield $class => [$class];
        }
    }

    public static function namedRouteProvider(): iterable
    {
        yield 'HomeController' => [
            \Ferienpass\AdminBundle\Controller\Page\HomeController::class,
            '__invoke',
            'admin_',
        ];
        yield 'LoginController' => [
            \Ferienpass\AdminBundle\Controller\Page\LoginController::class,
            '__invoke',
            'admin_',
        ];
        yield 'Error404Controller' => [
            \Ferienpass\AdminBundle\Controller\Page\Error404Controller::class,
            '__invoke',
            'admin_',
        ];
        yield 'RegistrationController' => [
            \Ferienpass\AdminBundle\Controller\Page\RegistrationController::class,
            '__invoke',
            'admin_',
        ];
        yield 'FlashMessageController' => [
            \Ferienpass\AdminBundle\Controller\FlashMessageController::class,
            '__invoke',
            'admin_',
        ];
        yield 'AdminSearchController' => [
            \Ferienpass\AdminBundle\Controller\AdminSearchController::class,
            'search',
            'admin_',
        ];
    }
}
