<?php

/*
 * This file is part of the Serenity package.
 *
 * (c) CP Creation <web@cpcreation.fr>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Serenity\CoreBundle\Shared\Form\Extension;

use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\Form\Extension\Core\Type\FormType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;

class SecurityExtension extends AbstractTypeExtension
{
    public function __construct(private readonly AuthorizationCheckerInterface $authorizationChecker)
    {
    }

    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->setDefaults([
            'is_granted_attribute' => null,
            'is_granted_hide' => false,
            'is_granted_disabled' => false,
        ]);
    }

    public function finishView(FormView $view, FormInterface $form, array $options): void
    {
        if ($options['is_granted_disabled']) {
            return;
        }

        if ($this->isGranted($options)) {
            return;
        }

        $this->disableView($view);
    }

    /**
     * @param array<string> $options
     */
    private function isGranted(array $options): bool
    {
        if (!$options['is_granted_attribute']) {
            return true;
        }

        if ($this->authorizationChecker->isGranted($options['is_granted_attribute'])) {
            return true;
        }

        return false;
    }

    private function disableView(FormView $view): void
    {
        $view->vars['attr']['disabled'] = true;

        foreach ($view as $child) {
            $this->disableView($child);
        }
    }

    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        if (!$options['is_granted_attribute']) {
            return;
        }

        if ($options['is_granted_disabled']) {
            return;
        }

        if ($options['is_granted_hide']) {
            $builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) use ($options) {
                if ($this->isGranted($options) || null === $event->getForm()->getParent()) {
                    return;
                }
                $form = $event->getForm();
                $event->getForm()->getParent()->remove($form->getName());
            });
        } else {
            $builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) use ($options) {
                if ($this->isGranted($options)) {
                    return;
                }
                $event->setData($event->getForm()->getViewData());
            });
        }
    }

    public static function getExtendedTypes(): iterable
    {
        return [FormType::class];
    }
}
