<?php

declare(strict_types=1);

/*
 * This file is part of the Sonata Project package.
 *
 * (c) Thomas Rabaix <thomas.rabaix@sonata-project.org>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace App\Application\Sonata\UserBundle\Admin;

use App\Entity\Adherent;
use App\Entity\Geoloc;
use App\Entity\Groupe;
use App\Events\MLCEvents;
use FOS\UserBundle\Event\UserEvent;
use Sonata\AdminBundle\Datagrid\DatagridMapper;
use Sonata\AdminBundle\Datagrid\ListMapper;
use Sonata\AdminBundle\Form\FormMapper;
use Sonata\AdminBundle\Form\Type\ModelType;
use Sonata\AdminBundle\Route\RouteCollection;
use Sonata\AdminBundle\Show\ShowMapper;
use Sonata\CoreBundle\Form\Type\DatePickerType;
use Sonata\Form\Type\DateTimeRangePickerType;
use Sonata\UserBundle\Admin\Model\UserAdmin as BaseUserAdmin;
use Sonata\UserBundle\Form\Type\SecurityRolesType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\Extension\Core\Type\LocaleType;
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\Extension\Core\Type\TimezoneType;
use Symfony\Component\Form\Extension\Core\Type\UrlType;
use Symfony\Component\Form\FormTypeInterface;

class UserAdmin extends BaseUserAdmin
{
    public function configure()
    {
        parent::configure();
        $this->setTemplate('edit', '@kohinos/bundles/SonataAdminBundle/base_edit.html.twig');
    }

    protected function configureRoutes(RouteCollection $collection)
    {
        // Remove 'delete' action for non tav envs
        if (!$this->getConfigurationPool()->getContainer()->getParameter('tav_env')) {
            if ($this->isChild()) {
                $collection->remove('delete');

                return;
            }

            // This is the route configuration as a parent
            $collection->remove('delete');
        }
    }

    /**
     * {@inheritdoc}
     */
    protected function configureListFields(ListMapper $listMapper): void
    {
        $listMapper
            ->addIdentifier('username')
            ->add('email')
            ->add('possiblegroups', null, [
                'label' => 'Rôles',
            ])
            ->add('enabled', null, [
                'label' => 'Activé',
                'editable' => true,
            ])
            ->add('createdAt')
            ->add('lastLogin')
            ->add('_action', null, [
                'label' => 'Actions',
                'actions' => [
                    'edit' => [],
                ],
            ])
        ;

        // Add delete action on users in TAV envs for super admin
        if ($this->isGranted('ROLE_SUPER_ADMIN') && $this->getConfigurationPool()->getContainer()->getParameter('tav_env')) {
            $listMapper
                ->remove('_action')
                ->add('_action', null, [
                    'label' => 'Actions',
                    'actions' => [
                        'edit' => [],
                        'delete' => []
                    ],
                ])
            ;
        }

        // TODO: SECURITY BREACH, RESET ASAP!!!
        // if ('dev' == $_ENV['APP_ENV'] && $this->isGranted('ROLE_ALLOWED_TO_SWITCH')) {
        if ($this->isGranted('ROLE_ALLOWED_TO_SWITCH')) {
            $listMapper
                ->add('impersonating', 'string', ['template' => '@SonataUser/Admin/Field/impersonating.html.twig'])
            ;
        }
    }

    /**
     * {@inheritdoc}
     */
    protected function configureDatagridFilters(DatagridMapper $filterMapper): void
    {
        $filterMapper
            ->add('id')
            ->add('username')
            ->add('email')
            ->add('groups')
            ->add('createdAt', 'doctrine_orm_datetime_range', [
                'field_type' => DateTimeRangePickerType::class,
                'label' => 'Date de création',
            ])
            ->add('lastLogin', 'doctrine_orm_datetime_range', [
                'field_type' => DateTimeRangePickerType::class,
                'label' => 'Date de dernière connexion',
            ])
        ;
    }

    /**
     * {@inheritdoc}
     */
    protected function configureShowFields(ShowMapper $showMapper): void
    {
        $showMapper
            ->with('General')
                ->add('username')
                ->add('email')
            ->end()
            ->with('Groups')
                ->add('possiblegroups')
            ->end()
            ->with('Profile')
                // ->add('dateOfBirth')
                ->add('firstname')
                ->add('lastname')
                // ->add('website')
                // ->add('biography')
                // ->add('gender')
                // ->add('locale')
                // ->add('timezone')
                ->add('phone')
            ->end()
            // ->with('Social')
            //     ->add('facebookUid')
            //     ->add('facebookName')
            //     ->add('twitterUid')
            //     ->add('twitterName')
            //     ->add('gplusUid')
            //     ->add('gplusName')
            // ->end()
            // ->with('Security')
            //     ->add('token')
            //     ->add('twoStepVerificationCode')
            // ->end()
        ;
    }

    /**
     * {@inheritdoc}
     */
    protected function configureFormFields(FormMapper $formMapper): void
    {
        $subject = $this->getSubject();
        // define group zoning
        $formMapper
            ->tab('User')
                ->with('Profile', ['class' => 'col-md-6'])->end()
                ->with('General', ['class' => 'col-md-6'])->end()
                // ->with('Social', ['class' => 'col-md-6'])->end()
            ->end();
        if (($this->isGranted('ROLE_SUPER_ADMIN') || $this->isGranted('ROLE_ADMIN_SIEGE'))) {
            $formMapper
                ->tab('Security')
                ->with('Groups', ['class' => 'col-md-8'])->end()
                ->with('Status', ['class' => 'col-md-4'])->end()
                // ->with('Keys', ['class' => 'col-md-4'])->end()
                // ->with('Roles', ['class' => 'col-md-12'])->end()
                ->end()
            ;
        }

        $now = new \DateTime();

        $genderOptions = [
            'choices' => call_user_func([$this->getUserManager()->getClass(), 'getGenderList']),
            'required' => true,
            'translation_domain' => $this->getTranslationDomain(),
        ];

        // w: Remove this when dropping support for SF 2.8
        if (method_exists(FormTypeInterface::class, 'setDefaultOptions')) {
            $genderOptions['choices_as_values'] = true;
        }

        // $formMapper->removeGroup('Social');
        $formMapper
            ->tab('User')
                ->with('General')
                    ->add('username')
                    ->add('email')
        ;
        if ('dev' == $_ENV['APP_ENV'] && $this->isGranted('ROLE_SUPER_ADMIN')) {
            $formMapper
                ->add('plainPassword', RepeatedType::class, [
                    'type' => PasswordType::class,
                    'options' => ['translation_domain' => 'FOSUserBundle'],
                    'first_options' => ['label' => 'form.password'],
                    'second_options' => ['label' => 'form.password_confirmation'],
                    'translation_domain' => 'FOSUserBundle',
                    'invalid_message' => 'fos_user.password.mismatch',
                    'required' => (!$this->getSubject() || null === $this->getSubject()->getId()),
                ])
            ;
        } else {
            $formMapper
                ->add('plainPassword', HiddenType::class, [
                    'data' => random_bytes(10),
                    'required' => false,
                    'validation_groups' => false,
                ])
            ;
        }
        $formMapper->end()
                ->with('Profile')
                    // ->add('dateOfBirth', DatePickerType::class, [
                    //     'years' => range(1900, $now->format('Y')),
                    //     'dp_min_date' => '1-1-1900',
                    //     'dp_max_date' => $now->format('c'),
                    //     'required' => false,
                    // ])
                    ->add('firstname', null, ['required' => false])
                    ->add('lastname', null, ['required' => false])
                    // ->add('website', UrlType::class, ['required' => false])
                    // ->add('biography', TextType::class, ['required' => false])
                    // ->add('gender', ChoiceType::class, $genderOptions)
                    // ->add('locale', LocaleType::class, ['required' => false])
                    // ->add('timezone', TimezoneType::class, ['required' => false])
                    ->add('phone', null, ['required' => false])
                ->end()
                // ->with('Social')
                //     ->add('facebookUid', null, ['required' => false])
                //     ->add('facebookName', null, ['required' => false])
                //     ->add('twitterUid', null, ['required' => false])
                //     ->add('twitterName', null, ['required' => false])
                //     ->add('gplusUid', null, ['required' => false])
                //     ->add('gplusName', null, ['required' => false])
                // ->end()
            ->end();

        if (($this->isGranted('ROLE_SUPER_ADMIN') || $this->isGranted('ROLE_ADMIN_SIEGE'))) {
            $formMapper
                ->tab('Security')
                    ->with('Status')
                        ->add('enabled', null, ['required' => false])
                        ->add('canValidateAchat', null, [
                            'label' => "Peut valider les demandes d'achat de e-mlc (Admin Siege ou Trésorier)",
                            'required' => false,
                        ])
                    ->end()
            ;
            $hideOrShowGroupe = ['class' => 'groupesgeres_select hide'];
            $hideOrShowComptoir = ['class' => 'comptoirsgeres_select hide'];
            $possiblegroups = $subject->getPossiblegroups();
            foreach ($possiblegroups as $group) {
                if ($group->hasRole('ROLE_GESTION_GROUPE') || $group->hasRole('ROLE_CONTACT') || $group->hasRole('ROLE_TRESORIER')) {
                    $hideOrShowGroupe = ['class' => 'groupesgeres_select'];
                }
                if ($group->hasRole('ROLE_COMPTOIR')) {
                    $hideOrShowComptoir = ['class' => 'comptoirsgeres_select'];
                }
            }
            $formMapper
                    ->with('Groups')
                        ->add('possiblegroups', ModelType::class, [
                            'label' => 'Groupes de rôles possibles',
                            'required' => false,
                            'expanded' => true,
                            'multiple' => true,
                            'attr' => ['class' => 'possible_group_cblist'],
                        ])
                        // @TODO : Si on veut voir le groupe choisit par l'utilisateur
                        // ->add('groups', null, [
                        //     'label' => 'Rôle actuel',
                        //     'required' => false,
                        //     'disabled' => true
                        // ])
                        ->add('groupesgeres', null, [
                            'required' => false,
                            'label' => 'Groupe local géré (obligatoire)',
                            'attr' => $hideOrShowGroupe,
                            'label_attr' => $hideOrShowGroupe,
                            'multiple' => true,
                            'by_reference' => false,
                        ])
                        ->add('comptoirsgeres', null, [
                            'required' => false,
                            'label' => 'Comptoir géré (obligatoire)',
                            'attr' => $hideOrShowComptoir,
                            'label_attr' => $hideOrShowComptoir,
                            'multiple' => true,
                            'by_reference' => false,
                        ])
                    ->end()
                    // ->with('Roles')
                    //     ->add('realRoles', SecurityRolesType::class, [
                    //         'label' => 'form.label_roles',
                    //         'expanded' => true,
                    //         'multiple' => true,
                    //         'required' => false,
                    //     ])
                    // ->end()
                ->end()
            ;
        }
        // ->with('Keys')
        //     ->add('token', null, ['required' => false])
        //     ->add('twoStepVerificationCode', null, ['required' => false])
        // ->end()
    }

    public function getBatchActions()
    {
        $actions = parent::getBatchActions();
        unset($actions['delete']);

        return $actions;
    }

    public function getDashboardActions()
    {
        $actions = parent::getDashboardActions();
        unset($actions['list']);

        return $actions;
    }

    public function preUpdate($user): void
    {
        parent::preUpdate($user);
        $em = $this->getConfigurationPool()->getContainer()->get('doctrine')->getManager();

        /* ON EMPECHE ICI DE DESACTIVER LES ROLES SUPER ADMIN OU ADMIN SIEGE */
        if ($user->hasRole('ROLE_SUPER_ADMIN') || $user->hasRole('ROLE_ADMIN_SIEGE')) {
            if (!$user->isEnabled()) {
                $user->setEnabled(1);
                $em->persist($user);
                $em->flush();
            }
        }
    }

    public function postUpdate($user): void
    {
        $this->postPersist($user);
    }

    public function prePersist($user)
    {
        if ($user->isEnabled()) {
            $this->getConfigurationPool()->getContainer()->get('event_dispatcher')->dispatch(MLCEvents::REGISTRATION_USER, new UserEvent($user, $this->getRequest()));
        }
    }

    public function postPersist($user): void
    {
        // On empeche d'enregistrer des comptoirs/groupes gérés si la case correspondante n'est pas cochée dans le choix des possiblegroups
        $em = $this->getConfigurationPool()->getContainer()->get('doctrine')->getManager();

        $possiblegroups = $user->getPossiblegroups();

        $groupesgeres = $user->getGroupesgeres();
        $comptoirsgeres = $user->getComptoirsgeres();

        $isComptoir = false;
        $isGroup = false;
        foreach ($possiblegroups as $possiblegroup) {
            if ('Comptoir' == $possiblegroup->getName()) {
                $isComptoir = true;
            } elseif ('Gestionnaire de Groupe' == $possiblegroup->getName() || 'Contact' == $possiblegroup->getName()) {
                $isGroup = true;
            } elseif ('Adherent' == $possiblegroup->getName() && null == $user->getAdherent()) {
                $groupeByDefault = $this->getConfigurationPool()->getContainer()->get('doctrine')->getRepository(Groupe::class)->findAll()[0];
                // On crée l'entité Adhérent si on coche la case Adhérent et que l'utilisateur ne l'est pas encore
                $adherent = new Adherent();
                $adherent->setUser($user);
                $user->setAdherent($adherent);
                $adherent->setGeoloc(new Geoloc());
                $adherent->setGroupe($groupeByDefault);
                $adherent->setEcompte(0);
                $em->persist($adherent);
                $flashbag = $this->getRequest()->getSession()->getFlashBag();
                $flashbag->get('sonata_flash_success');
                $flashbag->set(
                    'sonata_flash_success',
                    $this->trans("L'utilisateur est désormais Adhérent et rattaché au premier groupe local par défaut, vous pouvez le changer dans l'édition de l'adhérent !")
                );
            }
        }

        if (!$isComptoir && !$comptoirsgeres->isEmpty()) {
            foreach ($comptoirsgeres as $comptoir) {
                $user->removeComptoirsgere($comptoir);
            }
        }

        if (!$isGroup && !$groupesgeres->isEmpty()) {
            foreach ($groupesgeres as $group) {
                $user->removeGroupesgere($group);
            }
        }

        $em->persist($user);
        $em->flush();
    }
}
