<?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\Center;
use Chill\MainBundle\Entity\Scope;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Form\DataMapper\ScopePickerDataMapper;
use Chill\MainBundle\Security\Authorization\AuthorizationHelperInterface;
use Chill\MainBundle\Security\Resolver\CenterResolverManagerInterface;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\OptionsResolver\Options;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Security\Core\Role\Role;
use Symfony\Component\Security\Core\Security;

/**
 * Allow to pick amongst available scope for the current
 * user.
 *
 * Options:
 * - `role`: string, the role to check permissions for
 * - Either `subject`: object, entity to resolve centers from
 * - Or `center`: Center|array|null, the center(s) to check
 */
class ScopePickerType extends AbstractType
{
    public function __construct(
        private readonly TranslatableStringHelperInterface $translatableStringHelper,
        private readonly AuthorizationHelperInterface $authorizationHelper,
        private readonly Security $security,
        private readonly CenterResolverManagerInterface $centerResolverManager,
    ) {}

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        // Compute centers from subject
        $centers = $options['center'] ?? null;
        if (null === $centers && isset($options['subject'])) {
            $centers = $this->centerResolverManager->resolveCenters($options['subject']);
        }

        if (null === $centers) {
            throw new \RuntimeException('Either "center" or "subject" must be provided');
        }

        $reachableScopes = array_values(
            array_filter(
                $this->authorizationHelper->getReachableScopes(
                    $this->security->getUser(),
                    $options['role'],
                    $centers
                ),
                static fn (Scope $s) => $s->isActive()
            )
        );

        $builder->setAttribute('reachable_scopes_count', count($reachableScopes));

        if (0 === count($reachableScopes)) {
            $builder->setAttribute('has_scopes', false);

            return;
        }

        $builder->setAttribute('has_scopes', true);

        if (1 !== count($reachableScopes)) {
            $builder->add('scope', EntityType::class, [
                'class' => Scope::class,
                'placeholder' => 'Choose the circle',
                'choice_label' => fn (Scope $c) => $this->translatableStringHelper->localize($c->getName()),
                'choices' => $reachableScopes,
            ]);
            $builder->setDataMapper(new ScopePickerDataMapper());
        } else {
            $builder->add('scope', HiddenType::class, [
                'data' => $reachableScopes[0]->getId(),
            ]);
            $builder->setDataMapper(new ScopePickerDataMapper($reachableScopes[0]));
        }
    }

    public function buildView(FormView $view, FormInterface $form, array $options)
    {
        $view->vars['fullWidth'] = true;
        // display of label is handled by the EntityType
        $view->vars['label'] = false;
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver
            ->setRequired('role')
            ->setAllowedTypes('role', ['string'])
            ->setDefined('subject')
            ->setAllowedTypes('subject', ['object'])
            ->setDefined('center')
            ->setAllowedTypes('center', [Center::class, 'array', 'null']);
    }
}
