<?php

declare(strict_types=1);

namespace GatoGraphQL\GatoGraphQL\Registries;

use GatoGraphQL\GatoGraphQL\Exception\UserAuthorizationException;
use GatoGraphQL\GatoGraphQL\Security\UserAuthorizationSchemes\UserAuthorizationSchemeInterface;

class UserAuthorizationSchemeRegistry implements UserAuthorizationSchemeRegistryInterface
{
    /**
     * @var array<string,UserAuthorizationSchemeInterface>
     */
    protected array $userAuthorizationSchemes = [];
    private ?UserAuthorizationSchemeInterface $defaultUserAuthorizationScheme = null;

    public function addUserAuthorizationScheme(
        UserAuthorizationSchemeInterface $userAuthorizationScheme
    ): void {
        $this->userAuthorizationSchemes[$userAuthorizationScheme->getName()] = $userAuthorizationScheme;
    }

    /**
     * Registered UserAuthorizationSchemes, ordered by priority.
     *
     * @return UserAuthorizationSchemeInterface[]
     */
    public function getUserAuthorizationSchemes(): array
    {
        $userAuthorizationSchemes = array_values($this->userAuthorizationSchemes);
        usort(
            $userAuthorizationSchemes,
            fn (UserAuthorizationSchemeInterface $a, UserAuthorizationSchemeInterface $b) => $a->getPriority() <=> $b->getPriority()
        );
        return $userAuthorizationSchemes;
    }

    /**
     * @throws UserAuthorizationException When the scheme is not registered
     */
    public function getUserAuthorizationScheme(string $name): UserAuthorizationSchemeInterface
    {
        if (!isset($this->userAuthorizationSchemes[$name])) {
            throw new UserAuthorizationException(sprintf(
                \__('User authorization scheme with name \'%s\' does not exist', 'gatographql'),
                $name
            ));
        }
        return $this->userAuthorizationSchemes[$name];
    }

    public function getDefaultUserAuthorizationScheme(): UserAuthorizationSchemeInterface
    {
        if ($this->defaultUserAuthorizationScheme === null) {
            // They are ordered by priority => get the first item
            $userAuthorizationSchemes = $this->getUserAuthorizationSchemes();
            if ($userAuthorizationSchemes === []) {
                throw new UserAuthorizationException(
                    \__('No user authorization scheme has been registered', 'gatographql')
                );
            }
            $this->defaultUserAuthorizationScheme = $userAuthorizationSchemes[0];
        }
        return $this->defaultUserAuthorizationScheme;
    }
}
