<?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;

use Chill\MainBundle\Entity\Center;
use Chill\MainBundle\Entity\Location;
use Chill\MainBundle\Entity\Scope;
use Chill\MainBundle\Entity\UserJob;
use Chill\MainBundle\Form\Type\ChillDateType;
use Chill\MainBundle\Form\Type\ChillPhoneNumberType;
use Chill\MainBundle\Form\Type\PickCivilityType;
use Chill\MainBundle\Repository\UserJobRepository;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Doctrine\ORM\EntityRepository;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints\Length;
use Symfony\Component\Validator\Constraints\NotBlank;
use Symfony\Component\Validator\Constraints\Regex;

class UserType extends AbstractType
{
    public function __construct(private readonly TranslatableStringHelper $translatableStringHelper, protected ParameterBagInterface $parameterBag, private readonly UserJobRepository $userJobRepository) {}

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('username')
            ->add('email', EmailType::class, [
                'required' => true,
            ])
            ->add('phonenumber', ChillPhoneNumberType::class, [
                'required' => false,
            ])
            ->add('label', TextType::class)
            ->add('civility', PickCivilityType::class, [
                'required' => false,
                'label' => 'Civility',
                'placeholder' => 'choose civility',
            ])
            ->add('mainCenter', EntityType::class, [
                'label' => 'Main center',
                'required' => false,
                'placeholder' => 'Choose a main center',
                'class' => Center::class,
                'query_builder' => static function (EntityRepository $er) {
                    $qb = $er->createQueryBuilder('c');
                    $qb->where($qb->expr()->eq('c.isActive', 'true'));
                    $qb->addOrderBy('c.name');

                    return $qb;
                },
            ])
            ->add('mainScope', EntityType::class, [
                'label' => 'Main scope',
                'required' => false,
                'placeholder' => 'Choose a main scope',
                'class' => Scope::class,
                'choice_label' => fn (Scope $c) => $this->translatableStringHelper->localize($c->getName()),
            ])
            ->add('userJob', EntityType::class, [
                'label' => 'user job',
                'required' => false,
                'placeholder' => 'choose a job',
                'class' => UserJob::class,
                'choice_label' => fn (UserJob $c) => $this->translatableStringHelper->localize($c->getLabel()),
                'choices' => $this->loadAndSortUserJobs(),
            ])
            ->add('mainLocation', EntityType::class, [
                'label' => 'Main location',
                'required' => false,
                'placeholder' => 'choose a location',
                'class' => Location::class,
                'choice_label' => fn (Location $l) => $this->translatableStringHelper->localize($l->getLocationType()->getTitle()).' - '.$l->getName(),
                'query_builder' => static function (EntityRepository $er) {
                    $qb = $er->createQueryBuilder('l');
                    $qb->orderBy('l.locationType');
                    $qb->orderBy('l.name', 'ASC');
                    $qb->where('l.availableForUsers = TRUE');

                    return $qb;
                },
            ])
            ->add('absenceStart', ChillDateType::class, [
                'required' => false,
                'input' => 'datetime_immutable',
                'label' => 'absence.Absence start',
            ])
            ->add('absenceEnd', ChillDateType::class, [
                'required' => false,
                'input' => 'datetime_immutable',
                'label' => 'absence.Absence end',
            ]);

        // @phpstan-ignore-next-line
        if ($options['is_creation'] && $this->parameterBag->get('chill_main.access_user_change_password')) {
            $builder->add('plainPassword', RepeatedType::class, [
                'mapped' => false,
                'type' => PasswordType::class,
                'required' => false,
                'options' => [],
                'first_options' => [
                    'label' => 'Password',
                ],
                'second_options' => [
                    'label' => 'Repeat the password',
                ],
                'invalid_message' => 'The password fields must match',
                'constraints' => [
                    new Length([
                        'min' => 9,
                        'minMessage' => 'The password must be greater than {{ limit }} characters',
                    ]),
                    new NotBlank(),
                    new Regex([
                        'pattern' => "/((?=.*\\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%!,;:+\"'-\\/{}~=µ\\(\\)£]).{6,})/",
                        'message' => 'The password must contains one letter, one '
                        .'capitalized letter, one number and one special character '
                        ."as *[@#$%!,;:+\"'-/{}~=µ()£]). Other characters are allowed.",
                    ]),
                ],
            ]);
        } else {
            $builder->add(
                $builder
                    ->create('enabled', ChoiceType::class, [
                        'choices' => [
                            'Disabled, the user is not allowed to login' => 0,
                            'Enabled, the user is active' => 1,
                        ],
                        'expanded' => false,
                        'multiple' => false,
                    ])
            );
        }
    }

    private function loadAndSortUserJobs(): array
    {
        $items = $this->userJobRepository->findBy(['active' => true]);

        usort(
            $items,
            fn ($a, $b) => mb_strtolower((string) $this->translatableStringHelper->localize($a->getLabel()))
            <=>
            mb_strtolower((string) $this->translatableStringHelper->localize($b->getLabel()))
        );

        return $items;
    }

    /**
     * @param OptionsResolverInterface $resolver
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'data_class' => \Chill\MainBundle\Entity\User::class,
        ]);

        $resolver
            ->setDefaults(['is_creation' => false])
            ->addAllowedValues('is_creation', [true, false]);
    }

    /**
     * @return string
     */
    public function getBlockPrefix()
    {
        return 'chill_mainbundle_user';
    }
}
