<?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\Security;

use Chill\MainBundle\Security\ProvideRoleHierarchyInterface;
use Chill\MainBundle\Security\RoleDumper;
use Chill\MainBundle\Security\RoleProvider;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Security\Core\Role\RoleHierarchyInterface;
use Symfony\Contracts\Translation\TranslatorInterface;

/**
 * @internal
 *
 * @coversNothing
 */
class RoleDumperTest extends TestCase
{
    public function testDumpAsMarkdownGroupsByTitleTranslatesAndListsDependencies(): void
    {
        // Fake provider with two groups
        $provider = new class () implements ProvideRoleHierarchyInterface {
            public const R_PERSON_SEE = 'CHILL_PERSON_SEE';
            public const R_PERSON_UPDATE = 'CHILL_PERSON_UPDATE';
            public const R_REPORT_SEE = 'CHILL_REPORT_SEE';

            public function getRoles(): array
            {
                return [self::R_PERSON_SEE, self::R_PERSON_UPDATE, self::R_REPORT_SEE];
            }

            public function getRolesWithoutScope(): array
            {
                // In this test, assume REPORT_SEE does not need scope, others do
                return [self::R_REPORT_SEE];
            }

            public function getRolesWithHierarchy(): array
            {
                return [
                    'Person' => [self::R_PERSON_SEE, self::R_PERSON_UPDATE],
                    'Report' => [self::R_REPORT_SEE],
                ];
            }
        };

        $roleProvider = new RoleProvider([$provider]);

        // Fake role hierarchy: UPDATE implies SEE; others none
        $roleHierarchy = new class () implements RoleHierarchyInterface {
            public function getReachableRoleNames(array $roles): array
            {
                $output = [];
                foreach ($roles as $r) {
                    $output[] = $r;
                    if ('CHILL_PERSON_UPDATE' === $r) {
                        $output[] = 'CHILL_PERSON_SEE';
                    }
                }

                return array_values(array_unique($output));
            }
        };

        // Fake translator that clearly shows translation applied
        $translator = new class () implements TranslatorInterface {
            public function trans(string $id, array $parameters = [], ?string $domain = null, ?string $locale = null): string
            {
                return 'T('.$id.')';
            }

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

        $dumper = new RoleDumper($roleProvider, $roleHierarchy, $translator);
        $md = $dumper->dumpAsMarkdown();

        $expected = "## T(Person)\n"
            ."- **T(CHILL_PERSON_SEE)** (S)\n"
            ."- **T(CHILL_PERSON_UPDATE)** (S): T(CHILL_PERSON_SEE)\n\n"
            ."## T(Report)\n"
            ."- **T(CHILL_REPORT_SEE)** (~~S~~)\n";

        self::assertSame($expected, $md);
    }
}
