<?php

declare(strict_types=1);

/*
 * Chill is a software for social workers
 *
 * For the full copyright and license information, please view
 * the LICENSE file that was distributed with this source code.
 */

namespace Chill\MainBundle\Tests\Services;

use Chill\MainBundle\Routing\LocalMenuBuilderInterface;
use Chill\MainBundle\Routing\MenuComposer;
use Knp\Menu\MenuFactory;
use PHPUnit\Framework\TestCase;
use Prophecy\PhpUnit\ProphecyTrait;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Routing\RouteCollection;
use Symfony\Contracts\Translation\TranslatorInterface;

/**
 * Tests for MenuComposer methods.
 *
 * We only verify that items provided by local menu builders are present
 * when getRoutesFor() yields no routes, and that hasLocalMenuBuilder behaves
 * as expected with the configured builders.
 *
 * @internal
 *
 * @coversNothing
 */
final class MenuComposerTest extends TestCase
{
    use ProphecyTrait;

    private function buildMenuComposerWithDefaultBuilder(): array
    {
        // Router: returns an empty RouteCollection so getRoutesFor() yields []
        $routerProphecy = $this->prophesize(RouterInterface::class);
        $routerProphecy->getRouteCollection()->willReturn(new RouteCollection());
        $router = $routerProphecy->reveal();

        // Menu factory from Knp\Menu
        $menuFactory = new MenuFactory();

        // Translator: identity translator
        $translator = new class () implements TranslatorInterface {
            public function trans(string $id, array $parameters = [], ?string $domain = null, ?string $locale = null): string
            {
                return $id;
            }

            public function getLocale(): string
            {
                return 'en';
            }
        };

        // Local builder that adds two items to the requested menu
        $builder = new class () implements LocalMenuBuilderInterface {
            public static function getMenuIds(): array
            {
                return ['main'];
            }

            public function buildMenu($menuId, \Knp\Menu\MenuItem $menu, array $parameters)
            {
                // Ensure we can use parameters passed to getMenuFor
                $suffix = $parameters['suffix'] ?? '';
                $menu->addChild('local_item_one', [
                    'label' => 'Local Item One'.$suffix,
                ])->setExtras(['order' => 1]);
                $menu->addChild('local_item_two', [
                    'label' => 'Local Item Two'.$suffix,
                ])->setExtras(['order' => 2]);
            }
        };

        $composer = new MenuComposer(
            $router,
            $menuFactory,
            $translator,
            [$builder]
        );

        return [$composer, $builder];
    }

    public function testGetMenuForReturnsItemsFromLocalBuildersOnly(): void
    {
        [$composer] = $this->buildMenuComposerWithDefaultBuilder();

        $menu = $composer->getMenuFor('main', []);

        // No routes were added, only local builder items should be present
        $children = $menu->getChildren();
        self::assertCount(2, $children, 'Menu should contain exactly the items provided by local builders');

        // Assert the two expected items exist with their names
        self::assertNotNull($menu->getChild('local_item_one'));
        self::assertNotNull($menu->getChild('local_item_two'));

        // And that their labels include the parameter suffix
        self::assertSame('Local Item One', $menu->getChild('local_item_one')->getLabel());
        self::assertSame('Local Item Two', $menu->getChild('local_item_two')->getLabel());
    }

    public function testHasLocalMenuBuilder(): void
    {
        [$composer] = $this->buildMenuComposerWithDefaultBuilder();

        self::assertTrue($composer->hasLocalMenuBuilder('main'));
        self::assertFalse($composer->hasLocalMenuBuilder('secondary'));
    }
}
