<?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\Form\Type;

use Chill\MainBundle\Entity\Scope;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Repository\UserACLAwareRepositoryInterface;
use Chill\MainBundle\Repository\UserRepository;
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Chill\MainBundle\Templating\Entity\UserRender;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\OptionsResolver\Options;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Role\Role;

/**
 * Pick a user available for the given role and center.
 *
 * Options :
 *
 * - `role`  : the role the user can reach
 * - `center`: the center a user can reach
 */
class UserPickerType extends AbstractType
{
    /**
     * @var AuthorizationHelper
     */
    protected $authorizationHelper;

    /**
     * @var TokenStorageInterface
     */
    protected $tokenStorage;

    public function __construct(
        AuthorizationHelper $authorizationHelper,
        TokenStorageInterface $tokenStorage,
        protected UserRepository $userRepository,
        protected UserACLAwareRepositoryInterface $userACLAwareRepository,
        private readonly UserRender $userRender,
    ) {
        $this->authorizationHelper = $authorizationHelper;
        $this->tokenStorage = $tokenStorage;
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver
            // create `center` option
            ->setRequired('center')
            ->setAllowedTypes('center', [\Chill\MainBundle\Entity\Center::class, 'null', 'array'])
            // create ``role` option
            ->setRequired('role')
            ->setAllowedTypes('role', ['string']);

        $resolver
            ->setDefault('having_permissions_group_flag', null)
            ->setAllowedTypes('having_permissions_group_flag', ['string', 'null'])
            ->setDefault('class', User::class)
            ->setDefault('placeholder', 'Choose an user')
            ->setDefault('choice_label', fn (User $u) => $this->userRender->renderString($u, []))
            ->setDefault('scope', null)
            ->setAllowedTypes('scope', [Scope::class, 'array', 'null'])
            ->setNormalizer('choices', function (Options $options) {
                $role = $options['role'];
                $users = $this->userACLAwareRepository
                    ->findUsersByReachedACL($role, $options['center'], $options['scope'], true);

                if (null !== $options['having_permissions_group_flag']) {
                    return $this->userRepository
                        ->findUsersHavingFlags($options['having_permissions_group_flag'], $users);
                }

                return $users;
            });
    }

    public function getParent()
    {
        return EntityType::class;
    }
}
