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

class RoleProvider
{
    /**
     * an array where keys are the role, and value is the title
     * for the given role.
     *
     * Null when not initialized.
     */
    private ?array $rolesTitlesCache = null;

    public function __construct(
        /**
         * @var iterable<ProvideRoleInterface>
         */
        private readonly iterable $providers,
    ) {}

    public function getRoles(): array
    {
        $roles = [];

        foreach ($this->providers as $provider) {
            $roles = array_merge($roles, $provider->getRoles());
        }

        return $roles;
    }

    public function getRolesWithoutScopes(): array
    {
        $roles = [];

        foreach ($this->providers as $provider) {
            $roles = array_merge($roles, $provider->getRolesWithoutScope());
        }

        return $roles;
    }

    /**
     * Get the title for each role.
     */
    public function getRoleTitle(string $role): ?string
    {
        $this->initializeRolesTitlesCache();

        if (!\array_key_exists($role, $this->rolesTitlesCache)) {
            // this case might happens when the role is not described in
            // `getRolesWithHierarchy`
            return null;
        }

        return $this->rolesTitlesCache[$role];
    }

    /**
     * initialize the array for caching role and titles.
     */
    private function initializeRolesTitlesCache(): void
    {
        // break if already initialized
        if (null !== $this->rolesTitlesCache) {
            return;
        }

        foreach ($this->providers as $provider) {
            if ($provider instanceof ProvideRoleHierarchyInterface) {
                foreach ($provider->getRolesWithHierarchy() as $title => $roles) {
                    foreach ($roles as $role) {
                        $this->rolesTitlesCache[$role] = $title;
                    }
                }
            } else {
                $this->rolesTitlesCache = array_merge(
                    $this->rolesTitlesCache,
                    \array_fill_keys($provider->getRoles(), null)
                );
            }
        }
    }
}
