<?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\Form\Type\DataTransformer\CenterTransformer;
use Chill\MainBundle\Repository\CenterRepository;
use Chill\MainBundle\Security\Authorization\AuthorizationHelperInterface;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\CallbackTransformer;
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\OptionsResolver;
use Symfony\Component\Security\Core\Security;
use function count;

/**
 * Pick a center.
 *
 * For a given role and, eventually, scopes, show a dropdown (if more than
 * one reachable center) or a HiddenType (if one or zero center).
 */
class PickCenterType extends AbstractType
{
    public function __construct(protected AuthorizationHelperInterface $authorizationHelper, protected Security $security, protected CenterRepository $centerRepository) {}

    /**
     * add a data transformer if user can reach only one center.
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $centers = $this->getReachableCenters($options['role'], $options['scopes']);

        $centersActive = array_filter($centers, fn (Center $c) => $c->getIsActive());

        if (\count($centers) <= 1) {
            $multiple = $options['choice_options']['multiple'] ?? false;
            $builder->add('center', HiddenType::class);
            $builder->get('center')->addModelTransformer(
                new CenterTransformer($this->centerRepository, $multiple)
            );
        } else {
            $builder->add(
                'center',
                EntityType::class,
                \array_merge(
                    $options['choice_options'],
                    [
                        'class' => Center::class,
                        'choices' => $centersActive,
                    ]
                )
            );
        }

        $builder
            ->addModelTransformer(new CallbackTransformer(
                static function ($data) {
                    if (null === $data) {
                        return ['center' => null];
                    }

                    return ['center' => $data];
                },
                static fn ($data) => $data['center']
            ));
    }

    public function buildView(FormView $view, FormInterface $form, array $options)
    {
        $view->vars['is_hidden'] = \count($this->getReachableCenters(
            $options['role'],
            $options['scopes']
        )) <= 1;
    }

    /**
     * return a 'hidden' field if only one center is available.
     *
     * Return a 'choice' field if more than one center is available.
     *
     * @return string
     *
     * @throws \RuntimeException if the user is not associated with any center
     */
    /*
    public function getParent()
    {
        $nbReachableCenters = count($this->reachableCenters);

        if ($nbReachableCenters <= 1) {
            return HiddenType::class;
        } else {
            return EntityType::class;
        }
    }
     */

    /**
     * configure default options, i.e. add choices if user can reach multiple
     * centers.
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver
            ->setDefault('class', Center::class)
            ->setRequired('role')
            ->setAllowedTypes('role', ['string'])
            ->setDefault('scopes', [])
            ->setAllowedTypes('scopes', ['iterable'])
            ->setDefault('choice_options', []);
        /*
            ->setDefault('choices', $this->reachableCenters)
            ->setDefault('placeholder', 'Pick a center')
            ;
         */
    }

    private function getReachableCenters(string $role, iterable $scopes): array
    {
        if (0 < \count($scopes)) {
            $centers = [];

            foreach ($scopes as $scope) {
                foreach (
                    $this->authorizationHelper
                        ->getReachableCenters($this->security->getUser(), $role, $scope) as $center
                ) {
                    $centers[spl_object_hash($center)] = $center;
                }
            }

            return \array_values($centers);
        }

        return $this->authorizationHelper
            ->getReachableCenters($this->security->getUser(), $role);
    }
}
