<?php

namespace Lc\SovBundle\Controller\User;

use Doctrine\DBAL\Exception\ForeignKeyConstraintViolationException;
use Doctrine\ORM\EntityManagerInterface;
use EasyCorp\Bundle\EasyAdminBundle\Collection\EntityCollection;
use EasyCorp\Bundle\EasyAdminBundle\Config\Action;
use EasyCorp\Bundle\EasyAdminBundle\Config\Actions;
use EasyCorp\Bundle\EasyAdminBundle\Config\Crud;
use EasyCorp\Bundle\EasyAdminBundle\Config\KeyValueStore;
use EasyCorp\Bundle\EasyAdminBundle\Context\AdminContext;
use EasyCorp\Bundle\EasyAdminBundle\Event\AfterCrudActionEvent;
use EasyCorp\Bundle\EasyAdminBundle\Event\BeforeCrudActionEvent;
use EasyCorp\Bundle\EasyAdminBundle\Event\BeforeEntityDeletedEvent;
use EasyCorp\Bundle\EasyAdminBundle\Exception\EntityRemoveException;
use EasyCorp\Bundle\EasyAdminBundle\Exception\ForbiddenActionException;
use EasyCorp\Bundle\EasyAdminBundle\Exception\InsufficientEntityPermissionException;
use EasyCorp\Bundle\EasyAdminBundle\Field\ChoiceField;
use EasyCorp\Bundle\EasyAdminBundle\Field\EmailField;
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField;
use EasyCorp\Bundle\EasyAdminBundle\Security\Permission;
use Lc\SovBundle\Container\User\UserContainer;
use Lc\SovBundle\Controller\AbstractAdminController;
use Lc\SovBundle\Definition\ActionDefinition;
use Lc\SovBundle\Definition\ApplicationDefinition;
use Lc\SovBundle\Definition\RolesDefinition;
use Lc\SovBundle\Definition\RolesDefinitionInterface;
use Lc\SovBundle\Doctrine\EntityManager;
use Lc\SovBundle\Doctrine\Extension\BlameableInterface;
use Lc\SovBundle\Factory\User\UserFactory;
use Lc\SovBundle\Form\User\ConfirmDeleteUserFormType;
use Lc\SovBundle\Model\User\UserInterface;
use Lc\SovBundle\Translation\FlashBagTranslator;
use Lc\SovBundle\Translation\TranslatorAdmin;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Session\SessionInterface;

abstract class UserAdminController extends AbstractAdminController
{
    public function buildIndexActions(Actions $actions): void
    {
        parent::buildIndexActions($actions); // TODO: Change the autogenerated stub

        $actions->add(Crud::PAGE_INDEX, $this->getSwitchUserAction());
    }

    public function getSwitchUserAction(): Action
    {
        $switchAction = Action::new(
            ActionDefinition::SWITCH_USER,
            $this->get(TranslatorAdmin::class)->transAction(ActionDefinition::SWITCH_USER),
            'fa fa-fw fa-user-secret'
        )
            ->linkToCrudAction(ActionDefinition::SWITCH_USER)
            ->setLabel($this->get(TranslatorAdmin::class)->transAction(ActionDefinition::SWITCH_USER))
            ->setCssClass('in-dropdown text-info action-confirm action_switch');

        return $switchAction;
    }

    public function overrideEntitiesActions(?EntityCollection $entities, string $pageName): void
    {
        parent::overrideEntitiesActions($entities, $pageName); // TODO: Change the autogenerated stub
        foreach ($entities as $entity) {
            foreach ($entity->getActions() as $action) {
                if ($action->getName() == ActionDefinition::SWITCH_USER) {
                    $url = $this->generateUrl(
                        $this->getParameter('lc_sov.homepage_route'),
                        array('_switch_user' => $entity->getInstance()->getEmail())
                    );
                    $action->setLinkUrl($url);
                }
            }
        }
    }

    public function configureFields(string $pageName): iterable
    {
        return [
            EmailField::new('email'),
            TextField::new('lastname'),
            TextField::new('firstname'),
            ChoiceField::new('roles')
                ->allowMultipleChoices()
                ->autocomplete()
                ->setChoices($this->getUserContainer()->getRoleDefinition()->getRolesList())
        ];
    }

    public function createEntity(string $entityFqcn)
    {
        return $this->get(UserContainer::class)->getFactory()->create();
    }

    public function delete(AdminContext $context)
    {
        $entityManager = $this->getEntityManager();

        // Todo envisager un refactor similaire pour toutes les fonctions CRUD
        $eaBeforeCrudActionEventDelete = $this->eaBeforeCrudActionEventDelete($context);
        if (!is_null($eaBeforeCrudActionEventDelete)) {
            return $eaBeforeCrudActionEventDelete;
        }

        $user = $context->getEntity()->getInstance();

        $event = new BeforeEntityDeletedEvent($user);
        $this->container->get('event_dispatcher')->dispatch($event);
        if ($event->isPropagationStopped()) {
            return $event->getResponse();
        }

        $user = $event->getEntityInstance();


        // Creéer formulaire avec un champ confirm
        $confirmDeleteUserForm = $this->createForm(ConfirmDeleteUserFormType::class, null, array(
            'action' => $this->getAdminUrlGenerator()->generateUrl()
        ));
        $confirmDeleteUserForm->handleRequest($context->getRequest());

        $entityManager->delete($user);

        $warningMessages = $this->getDeleteUserWarningMessageList($user);

        //Avant la suppression on s'assure que l'utilisateur à confirmer et qu'il n'y aucun message d'erreur
        if ($confirmDeleteUserForm->isSubmitted() && count($warningMessages['danger']) === 0) {
            //Détecter les tables qui possède des relations avec un champ qui n'existe plus
            //Dans le cas ci-dessous détecter les adresses lié à un utilisateur qui n'existe plus
            //SELECT * FROM address a LEFT OUTER JOIN user u ON(u.id=a.user_id) WHERE u.id is null
            try {
                $entityManager->flush();
                $this->addFlashTranslator('success', 'deleted');
            } catch (ForeignKeyConstraintViolationException $e) {
                throw new EntityRemoveException(['entity_name' => $context->getEntity()->getName(), 'message' => $e->getMessage()]);
            }
            return $this->redirect($this->getAdminUrlGenerator()->setAction(Crud::PAGE_INDEX)->setEntityId(null)->generateUrl());

        }else{
            if($confirmDeleteUserForm->isSubmitted()){
                $this->addFlashTranslator('error', 'cannotDelete');
            }
        }

        $responseParameters = $this->configureResponseParameters(KeyValueStore::new([
            'pageName' => Crud::PAGE_DETAIL,
            'templatePath' => '@LcSov/adminlte/crud/delete.html.twig',
            'confirm_delete_user_form' => $confirmDeleteUserForm->createView(),
            'global_actions' => array(),
            'batch_actions' => array(),
            'warning_message_list' => $warningMessages
        ]));

        $event = new AfterCrudActionEvent($context, $responseParameters);
        $this->get('event_dispatcher')->dispatch($event);
        if ($event->isPropagationStopped()) {
            return $event->getResponse();
        }

        return $responseParameters;
    }

    public function getDeleteUserWarningMessageList(UserInterface $user): array
    {
        $warningMessages = array();
        $warningMessages['danger'] = [];
        $warningMessages['warning'] = [];
        $warningMessages['info'] = [];


        $entityManager = $this->getEntityManager();

        $entityToDeleteListCount = array();
        $entityToDeleteListName = array();
        foreach ($entityManager->getUnitOfWork()->getScheduledEntityDeletions() as $entityToDelete) {
            if (isset($entityToDeleteListCount[(new \ReflectionClass($entityToDelete))->getShortName()])) {
                $entityToDeleteListCount[(new \ReflectionClass($entityToDelete))->getShortName()]++;
            } else {
                $entityToDeleteListCount[(new \ReflectionClass($entityToDelete))->getShortName()] = 1;
            }
            $entityToDeleteListName[(new \ReflectionClass($entityToDelete))->getShortName()][] = $entityToDelete->getId();
        }

        foreach ($entityToDeleteListCount as $entityName => $entityToDeleteCount) {
            $warningMessages['info'][] = $this->getTranslatorAdmin()->transFlashMessage(
                'error',
                'deleteEntityCascade',
                'User',
                array(
                    '%entity%' => $this->getTranslatorAdmin()->trans('entity.'.$entityName.'.label_plurial'),
                    '%count%' => $entityToDeleteCount
                )
            );
        }

        return $warningMessages;
    }
}
