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

use Chill\MainBundle\Form\Event\CustomizeFormEvent;
use Chill\MainBundle\Form\Type\ChillDateType;
use Chill\MainBundle\Form\Type\ChillPhoneNumberType;
use Chill\MainBundle\Form\Type\PickAddressType;
use Chill\MainBundle\Form\Type\PickCenterType;
use Chill\MainBundle\Form\Type\PickCivilityType;
use Chill\PersonBundle\Actions\PersonCreate\PersonCreateDTO;
use Chill\PersonBundle\Config\ConfigPersonAltNamesHelper;
use Chill\PersonBundle\Form\Type\PersonAltNameType;
use Chill\PersonBundle\Form\Type\PickGenderType;
use Chill\PersonBundle\Security\Authorization\PersonVoter;
use libphonenumber\PhoneNumberType;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints\Callback;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;

final class CreationPersonType extends AbstractType
{
    // TODO: This is only used in test.
    // TODO: See if this is still valid and update accordingly.
    public const NAME = 'chill_personbundle_person_creation';

    private readonly bool $askCenters;

    public function __construct(
        private readonly ConfigPersonAltNamesHelper $configPersonAltNamesHelper,
        private readonly EventDispatcherInterface $dispatcher,
        ParameterBagInterface $parameterBag,
    ) {
        $this->askCenters = $parameterBag->get('chill_main')['acl']['form_show_centers'];
    }

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('firstName')
            ->add('lastName')
            ->add('civility', PickCivilityType::class, [
                'required' => false,
                'label' => 'Civility',
                'placeholder' => 'choose civility',
            ])
            ->add('gender', PickGenderType::class, [
                'required' => true, 'placeholder' => null,
            ])
            ->add('birthdate', ChillDateType::class, [
                'required' => false,
            ])
            ->add('phonenumber', ChillPhoneNumberType::class, [
                'required' => false,
                'type' => PhoneNumberType::FIXED_LINE,
            ])
            ->add('mobilenumber', ChillPhoneNumberType::class, [
                'required' => false,
                'type' => PhoneNumberType::MOBILE,
            ])
            ->add('email', EmailType::class, [
                'required' => false,
            ])
            ->add('addressForm', CheckboxType::class, [
                'label' => 'Create a household and add an address',
                'required' => false,
                'help' => 'A new household will be created. The person will be member of this household.',
            ])
            ->add('address', PickAddressType::class, [
                'required' => false,
                'label' => false,
            ]);

        $builder->add('identifiers', PersonIdentifiersType::class, [
            'by_reference' => false,
            'step' => 'on_create',
        ]);

        if ($this->askCenters) {
            $builder
                ->add('center', PickCenterType::class, [
                    'required' => false,
                    'role' => PersonVoter::CREATE,
                ]);
        }

        if ($this->configPersonAltNamesHelper->hasAltNames()) {
            $builder->add('altNames', PersonAltNameType::class, [
                'by_reference' => false,
            ]);
        }

        $this->dispatcher->dispatch(
            new CustomizeFormEvent(self::class, $builder),
            CustomizeFormEvent::NAME
        );
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'data_class' => PersonCreateDTO::class,
            'constraints' => [
                new Callback($this->validateCheckedAddress(...)),
            ],
        ]);
    }

    /**
     * @return string
     */
    public function getBlockPrefix()
    {
        return self::NAME;
    }

    public function validateCheckedAddress($data, ExecutionContextInterface $context, $payload): void
    {
        if (!$data instanceof PersonCreateDTO) {
            throw new UnexpectedTypeException($data, PersonCreateDTO::class);
        }

        $addressFrom = $data->addressForm;
        $address = $data->address;

        if ($addressFrom && null === $address) {
            $context->buildViolation('person_creation.If you want to create an household, an address is required')
                ->atPath('addressForm')
                ->addViolation();
        }
    }
}
