<?php
declare(strict_types=1);

namespace App\Service\Access;

use App\Entity\Access\Access;
use App\Entity\Organization\Organization;
use App\Repository\Access\AccessRepository;
use App\Service\ServiceIterator\OptionalsRolesIterator;
use App\Test\Service\Access\UtilsTest;
use Doctrine\Common\Collections\Criteria;
use Symfony\Component\Security\Core\Role\RoleHierarchyInterface;

/**
 * Class Utils : service rassemblant des fonctions d'aides pour les questions se rapportant à l'access
 * @package App\Service\Resource
 */
class Utils
{
    public function __construct(
        readonly private RoleHierarchyInterface $roleHierarchy,
        readonly private AccessRepository $accessRepository,
        readonly private OptionalsRolesIterator $optionalsRolesIterator
    )
    {}

    /**
     * Filtre un tableau d'Access pour ne laisser que les Accesses ne correspondant pas à l'Access passé en second parametre
     * @param array<Access> $accesses
     * @param Access $access
     * @return array<Access>
     * @see UtilsTest::testFilterAccesses()
     * TODO: est-ce qu'on essaierait pas de trouver un nom plus explicite? j'ai pas trop d'idée la tout de suite cela dit
     */
    public function filterAccesses(array $accesses, Access $access): array
    {
        return array_filter($accesses, function($a) use($access){
            /** @var Access $a */
            return $a->getId() !== $access->getId();
        });
    }

    /**
     * Recherche parmis les roles si l'Access possède celui passé en paramètre
     * @param Access $access
     * @param string $roleToHave
     * @return bool
     * @see UtilsTest::testHasRoles()
     */
    public function hasRoles(Access $access, string $roleToHave): bool
    {
        return in_array($roleToHave, $this->getAllRoles($access), true);
    }

    /**
     * Va récupérer les roles d'access + les roles optionnels possibles
     * @param Access $access
     * @return string[]
     * @see UtilsTest::testGetAllRoles()
     */
    public function getAllRoles(Access $access): array
    {
        $roles = $this->optionalsRolesIterator->getOptionalsRoles($access);
        return $this->roleHierarchy->getReachableRoleNames(array_merge($access->getRoles(), $roles));
    }

    /**
     * Renvoie l'access de l'organization qui est le "super admin"
     *
     * @param Organization $organization
     * @return Access|null
     * @see UtilsTest::testGetAdminAccess()
     */
    public function findAdminFor(Organization $organization): ?Access
    {
        return $this->accessRepository->findOneBy([
            'adminAccess' => true,
            'organization' => $organization
        ]);
    }
}
