<?php

namespace Lc\SovBundle\Controller;

use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\QueryBuilder;
use EasyCorp\Bundle\EasyAdminBundle\Collection\ActionCollection;
use EasyCorp\Bundle\EasyAdminBundle\Collection\EntityCollection;
use EasyCorp\Bundle\EasyAdminBundle\Collection\FieldCollection;
use EasyCorp\Bundle\EasyAdminBundle\Collection\FilterCollection;
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\Config\Option\EA;
use EasyCorp\Bundle\EasyAdminBundle\Context\AdminContext;
use EasyCorp\Bundle\EasyAdminBundle\Contracts\Controller\CrudControllerInterface;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController as EaAbstractCrudController;
use EasyCorp\Bundle\EasyAdminBundle\Dto\EntityDto;
use EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto;
use EasyCorp\Bundle\EasyAdminBundle\Dto\SearchDto;
use EasyCorp\Bundle\EasyAdminBundle\Event\AfterCrudActionEvent;
use EasyCorp\Bundle\EasyAdminBundle\Event\AfterEntityUpdatedEvent;
use EasyCorp\Bundle\EasyAdminBundle\Event\BeforeCrudActionEvent;
use EasyCorp\Bundle\EasyAdminBundle\Event\BeforeEntityDeletedEvent;
use EasyCorp\Bundle\EasyAdminBundle\Event\BeforeEntityUpdatedEvent;
use EasyCorp\Bundle\EasyAdminBundle\Exception\ForbiddenActionException;
use EasyCorp\Bundle\EasyAdminBundle\Exception\InsufficientEntityPermissionException;
use EasyCorp\Bundle\EasyAdminBundle\Factory\ControllerFactory;
use EasyCorp\Bundle\EasyAdminBundle\Factory\EntityFactory;
use EasyCorp\Bundle\EasyAdminBundle\Factory\FilterFactory;
use EasyCorp\Bundle\EasyAdminBundle\Factory\PaginatorFactory;
use EasyCorp\Bundle\EasyAdminBundle\Field\AssociationField;
use EasyCorp\Bundle\EasyAdminBundle\Field\FormField;
use EasyCorp\Bundle\EasyAdminBundle\Field\TextareaField;
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField;
use EasyCorp\Bundle\EasyAdminBundle\Provider\AdminContextProvider;
use EasyCorp\Bundle\EasyAdminBundle\Router\AdminUrlGenerator;
use EasyCorp\Bundle\EasyAdminBundle\Security\Permission;
use Lc\CaracoleBundle\Model\Section\SectionInterface;
use Lc\SovBundle\Component\EntityComponent;
use Lc\SovBundle\Definition\ActionDefinition;
use Lc\SovBundle\Doctrine\Extension\DevAliasInterface;
use Lc\SovBundle\Doctrine\Extension\OpenGraphInterface;
use Lc\SovBundle\Doctrine\Extension\SeoInterface;
use Lc\SovBundle\Doctrine\Extension\SortableInterface;
use Lc\SovBundle\Doctrine\Extension\StatusInterface;
use Lc\SovBundle\Doctrine\Extension\TranslatableInterface;
use Lc\SovBundle\Doctrine\Extension\TreeInterface;
use Lc\SovBundle\Field\CollectionField;
use Lc\SovBundle\Field\Filter\FilterManager;
use Lc\SovBundle\Field\ImageManagerField;
use Lc\SovBundle\Form\Common\FiltersFormType;
use Lc\SovBundle\Form\Common\PositionType;
use Lc\SovBundle\Model\User\UserInterface;
use Lc\SovBundle\Repository\EntityRepository;
use Lc\SovBundle\Repository\RepositoryQueryInterface;
use Lc\SovBundle\Translation\FlashBagTranslator;
use Lc\SovBundle\Translation\TranslatorAdmin;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Response;

abstract class AbstractAdminController extends EaAbstractCrudController
{
    use ControllerTrait;

    protected FormInterface $filtersForm;
    protected bool $isRepositoryQueryFiltered = false;

    abstract public function getRepositoryQuery(): RepositoryQueryInterface;


    public function configureResponseParameters(KeyValueStore $responseParameters): KeyValueStore
    {
        if ($responseParameters->get('global_actions')) {
            $this->overrideGlobalActions($responseParameters->get('global_actions'));
        }
        if ($responseParameters->get('entities')) {
            $this->overrideEntitiesActions($responseParameters->get('entities'), $responseParameters->get('pageName'));
        }
        if (Crud::PAGE_INDEX === $responseParameters->get('pageName')) {
            $responseParameters->set('fields', $this->configureFields('index'));

            if (isset($this->filtersForm)) {
                $responseParameters->set('filters_form', $this->filtersForm);
            }
        }

        $responseParameters->set('translation_entity_name', $this->getTranslationEntityName());

        return $responseParameters;
    }

    public function getTranslationEntityName()
    {
        return $this->getEntityFqcn();
    }

    public function overrideEntitiesActions(?EntityCollection $entities, string $pageName): void
    {
    }

    public function overrideGlobalActions(?ActionCollection $actions): void
    {
        if ($actions) {
            $context = $this->get(AdminContextProvider::class)->getContext();
            $adminUrlGenerator = $this->get(AdminUrlGenerator::class);

            foreach ($actions as $i => $action) {
                //récriture du bouton 'retour au parent'
                if ($action->getName() == 'index_parent') {
                    $entity = $context->getEntity()->getInstance();
                    if ($entity !== null) {
                        if ($entity->getParent() !== null) {
                            $url = $adminUrlGenerator
                                ->setController($context->getCrud()->getControllerFqcn())
                                ->set('entityId', $entity->getParent()->getId())
                                ->generateUrl();
                            $action->setLinkUrl($url);
                        }
                    } else {
                        unset($actions[$i]);
                    }
                }

                if ($action->getName() == 'sort') {
                    $entityId = $context->getRequest()->get('entityId');
                    if ($entityId != null) {
                        $url = $adminUrlGenerator
                            ->setController($context->getCrud()->getControllerFqcn())
                            ->setAction($action->getName())
                            ->set('entityId', $entityId)
                            ->generateUrl();
                        $action->setLinkUrl($url);
                    }
                }
                if ($action->getName() == ActionDefinition::WRITE_TO_USER) {
                    $entity = $context->getEntity()->getInstance();
                    if ($entity !== null) {
                        if (method_exists($entity, 'getUser')) {
                            $url = $this->generateEaUrl(UserA)->setController($context->getCrud()->getControllerFqcn())
                                ->set('entityId', $entity->getParent()->getId())
                                ->generateUrl();
                            $action->setLinkUrl($url);
                        }
                    } else {
                        unset($actions[$i]);
                    }
                }
            }
        }
    }

    protected function getRequestCrudAction(): string
    {
        return $this->getRequestStack()->getCurrentRequest()->get('crudAction');
    }

    public function configureCrud(Crud $crud): Crud
    {
        $crud = parent::configureCrud($crud);
        if ($this->getRequestCrudAction() === ActionDefinition::SORT) {
            $crud->setPaginatorPageSize(9999);
        } else {
            $this->setMaxResults($crud);
        }

        $crud->setFormOptions(['translation_entity_name' => $this->getTranslationEntityName()]);

        if ($this->isInstanceOf(SortableInterface::class)) {
            $crud->setDefaultSort(['position' => 'ASC']);
        } else {
            $crud->setDefaultSort(['id' => 'DESC']);
        }

        return $crud;
    }

    public function setMaxResults(Crud $crud): void
    {
        $entityClass = $this->getEntityFqcn();
        $paramListMaxResults = 'listMaxResults';
        $paramSessionListMaxResults = $entityClass . '-' . $paramListMaxResults;
        $requestListMaxResults = $this->get(RequestStack::class)->getCurrentRequest()->get($paramListMaxResults);

        if ($requestListMaxResults) {
            $this->get('session')->set($paramSessionListMaxResults, $requestListMaxResults);
        }
        $maxResults = $this->get('session')->get($paramSessionListMaxResults) ? $this->get('session')->get(
            $paramSessionListMaxResults
        ) : 30;

        $crud->setPaginatorPageSize($maxResults);
    }

    public function getSeoPanel(): ?array
    {
        if ($this->isInstanceOf(SeoInterface::class)) {
            return [
                FormField::addPanel('seo')->setTemplateName('crud/field/generic'),
                TextField::new('metaTitle')->setLabel('Meta Title')->setHelp(
                    'Affiché dans les résultats de recherche Google'
                )->hideOnIndex(),
                TextareaField::new('metaDescription')->setLabel('Meta description')->setHelp(
                    'Affiché dans les résultats de recherche Google'
                )->hideOnIndex(),
                CollectionField::new('oldUrls')
                    ->setFormTypeOption('entry_type', TextType::class)->setLabel(
                        'Anciennes urls du document'
                    )->hideOnIndex(),
            ];
        } else {
            return null;
        }
    }

    public function getConfPanel(): ?array
    {
        if ($this->isInstanceOf(DevAliasInterface::class)) {
            return [
                FormField::addPanel('configuration')->setTemplateName('crud/field/generic'),
                TextField::new('devAlias')->hideOnIndex(),
            ];
        } else {
            return null;
        }
    }

    public function sort(AdminContext $context)
    {
        $event = new BeforeCrudActionEvent($context);
        $this->get('event_dispatcher')->dispatch($event);
        if ($event->isPropagationStopped()) {
            return $event->getResponse();
        }

        //if (!$this->isGranted(Permission::EA_EXECUTE_ACTION) || !$this->isInstanceOf(SortableInterface::class)) {
        if (!$this->isInstanceOf(SortableInterface::class)) {
            throw new ForbiddenActionException($context);
        }

        $fields = FieldCollection::new($this->configureFields(Crud::PAGE_INDEX));
        $filters = $this->get(FilterFactory::class)->create(
            $context->getCrud()->getFiltersConfig(),
            $fields,
            $context->getEntity()
        );

        $queryBuilder = $this->createSortQueryBuilder($context->getSearch(), $context->getEntity(), $fields, $filters);
        $paginator = $this->get(PaginatorFactory::class)->create($queryBuilder);

        $entities = $this->get(EntityFactory::class)->createCollection($context->getEntity(), $paginator->getResults());
        $this->get(EntityFactory::class)->processFieldsForAll($entities, $fields);

        $sortableForm = $this->createFormBuilder(array('entities', $paginator->getResults()))
            ->add(
                'entities',
                CollectionType::class,
                array(
                    'required' => true,
                    'allow_add' => true,
                    'entry_type' => PositionType::class,
                )
            )
            ->getForm();

        $entityManager = $this->getDoctrine()->getManagerForClass($this->getEntityFqcn());
        $repository = $entityManager->getRepository($this->getEntityFqcn());

        $sortableForm->handleRequest($context->getRequest());

        if ($sortableForm->isSubmitted() && $sortableForm->isValid()) {
            foreach ($sortableForm->get('entities')->getData() as $elm) {
                $entityInstance = $repository->find($elm['id']);
                $entityDto = $context->getEntity()->newWithInstance($entityInstance);

                if (!$entityDto->isAccessible()) {
                    throw new InsufficientEntityPermissionException($context);
                }

                $event = new BeforeEntityUpdatedEvent($entityInstance);
                $this->get('event_dispatcher')->dispatch($event);
                $entityInstance = $event->getEntityInstance();

                $entityInstance->setPosition($elm['position']);
                $this->updateEntity($entityManager, $entityInstance);

                // @TODO : ce dispatch déclenche UpdateProductfamilyAfterFlushEventSubscriber dans Caracole et on tombe sur une erreur "Maximum execution time"
                //$this->get('event_dispatcher')->dispatch(new AfterEntityUpdatedEvent($entityInstance));
            }

            $url = $this->get(AdminUrlGenerator::class)
                ->setAction(ActionDefinition::INDEX)
                ->generateUrl();
            $this->addFlashTranslator('success', 'sorted');

            return $this->redirect($url);
        }

        $responseParameters = $this->configureResponseParameters(
            KeyValueStore::new(
                [
                    'pageName' => Crud::PAGE_INDEX,
                    'templatePath' => '@LcSov/adminlte/crud/sort.html.twig',
                    'entities' => $entities,
                    'paginator' => $paginator,
                    'global_actions' => array(),
                    'batch_actions' => array(),
                    'filters' => $filters,
                    'sortable_form' => $sortableForm,
                ]
            )
        );
        $responseParameters->set('fields', $this->configureFields('index'));
        $event = new AfterCrudActionEvent($context, $responseParameters);
        $this->get('event_dispatcher')->dispatch($event);
        if ($event->isPropagationStopped()) {
            return $event->getResponse();
        }

        return $responseParameters;
    }

    public function duplicate(
        AdminContext           $context,
        EntityComponent        $entityComponent,
        TranslatorAdmin        $translatorAdmin,
        EntityManagerInterface $em
    )
    {
        if (!$this->isGranted(
            Permission::EA_EXECUTE_ACTION,
            ['action' => ActionDefinition::DUPLICATE, 'entity' => $context->getEntity()]
        )) {
            throw new ForbiddenActionException($context);
        }

        if (!$context->getEntity()->isAccessible()) {
            throw new InsufficientEntityPermissionException($context);
        }

        $newEntity = $entityComponent->duplicateEntity($context->getEntity()->getInstance());
        $em->create($newEntity, false);
        $em->flush();

        $url = $this->get(AdminUrlGenerator::class)
            ->setAction(ActionDefinition::EDIT)
            ->setEntityId($newEntity->getId())
            ->generateUrl();

        $this->addFlashTranslator('success', ActionDefinition::DUPLICATE);

        return $this->redirect($url);
    }

    public function isRepositoryQueryFiltered(): bool
    {
        if (($this->filtersForm && $this->filtersForm->isSubmitted()) || $this->isRepositoryQueryFiltered) {
            return true;
        } else {
            return false;
        }
    }

    public function createIndexRepositoryQuery(
        SearchDto        $searchDto,
        EntityDto        $entityDto,
        FieldCollection  $fields,
        FilterCollection $filters
    ): RepositoryQueryInterface
    {
        $repositoryQuery = $this->get(EntityRepository::class)->createRepositoryQuery(
            $this->getRepositoryQuery(),
            $searchDto,
            $entityDto,
            $fields,
            $filters
        );

        // TODO : déplacer dans EntotyRepository
        if ($this->isInstanceOf(TreeInterface::class)) {
            if ($entityDto->getInstance()) {
                $repositoryQuery->filterByParent($entityDto->getInstance());
            } else {
                $repositoryQuery->filterIsParent();
            }
        }
        if ($this->isInstanceOf(StatusInterface::class)) {
            $repositoryQuery->filterIsOnlineAndOffline();
        }

        $this->filtersForm = $this->createForm(
            FiltersFormType::class,
            null,
            array(
                'fields' => $fields,
                'entity_dto' => $entityDto,
                'entity_class' => $this->getEntityFqcn(),
                'entity_name' => $entityDto->getName(),
            )
        );

        $filterManager = $this->get(FilterManager::class);

        $this->filtersForm->handleRequest($searchDto->getRequest());
        $this->isRepositoryQueryFiltered = $filterManager->handleFiltersForm($repositoryQuery, $this->filtersForm, $fields, $entityDto);
        return $repositoryQuery;
    }


    public function createSortRepositoryQuery(
        SearchDto        $searchDto,
        EntityDto        $entityDto,
        FieldCollection  $fields,
        FilterCollection $filters
    ): RepositoryQueryInterface
    {
        $repositoryQuery = $this->createIndexRepositoryQuery($searchDto, $entityDto, $fields, $filters);
        if ($this->isInstanceOf(StatusInterface::class)) {
            $repositoryQuery->filterIsOnline();
        }
        $repositoryQuery->orderBy('position', 'asc');
        return $repositoryQuery;
    }

    public function createIndexQueryBuilder(
        SearchDto        $searchDto,
        EntityDto        $entityDto,
        FieldCollection  $fields,
        FilterCollection $filters
    ): QueryBuilder
    {
        $repositoryQuery = $this->createIndexRepositoryQuery($searchDto, $entityDto, $fields, $filters);
        return $repositoryQuery->getQueryBuilder();
    }

    public function createSortQueryBuilder(
        SearchDto        $searchDto,
        EntityDto        $entityDto,
        FieldCollection  $fields,
        FilterCollection $filters
    ): QueryBuilder
    {
        $repositoryQuery = $this->createSortRepositoryQuery($searchDto, $entityDto, $fields, $filters);
        return $repositoryQuery->getQueryBuilder();
    }

    public function edit(AdminContext $context)
    {
        $response = parent::edit($context);;

        // on vide le flash bag si édition en ajax (notification déjà affichée en Javascript)
        if ($context->getRequest()->isXmlHttpRequest()) {
            $this->get('session')->getFlashBag()->clear();
        }

        return $response;
    }

    public function getControllerFqcnByInterface(string $interface): string
    {
        $context = $this->get(AdminContextProvider::class)->getContext();

        return $context->getCrudControllers()->findCrudFqcnByEntityFqcn(
            $this->get(EntityManagerInterface::class)->getEntityName($interface)
        );
    }

    public function updateEntity(EntityManagerInterface $entityManager, $entityInstance): void
    {
        $entityManager->update($entityInstance);
        $entityManager->flush();
        $this->get(FlashBagTranslator::class)->add('success', 'updated', $this->getTranslationEntityName());
    }

    public function persistEntity(EntityManagerInterface $entityManager, $entityInstance): void
    {
        $entityManager->create($entityInstance);
        $entityManager->flush();
        $this->get(FlashBagTranslator::class)->add('success', 'created', $this->getTranslationEntityName());
    }

    public function deleteEntity(EntityManagerInterface $entityManager, $entityInstance): void
    {
        if ($this->isInstanceOf(StatusInterface::class)) {
            $entityInstance->setStatus(-1);
            $entityManager->update($entityInstance);
        } else {
            $entityManager->delete($entityInstance);
        }
        $entityManager->flush();
        $this->get(FlashBagTranslator::class)->add('success', 'deleted', $this->getTranslationEntityName());
    }

    public function configureActions(Actions $actions): Actions
    {
        $this->buildIndexActions($actions);
        $this->buildEditActions($actions);
        $this->buildDetailActions($actions);
        $this->buildNewActions($actions);

        $this->handleTranslatableEntityActions($actions);
        $this->handleSortableEntityActions($actions);
        $this->handleTreeEntityActions($actions);

        /*$actions->reorder(Crud::PAGE_EDIT, [ActionDefinition::INDEX, ActionDefinition::SAVE_AND_RETURN, ActionDefinition::SAVE_AND_CONTINUE, ActionDefinition::DELETE]);
        $actions->reorder(Crud::PAGE_NEW, [ActionDefinition::INDEX, ActionDefinition::SAVE_AND_RETURN, ActionDefinition::SAVE_AND_ADD_ANOTHER]);*/

        return $actions;
    }

    public function getDuplicateAction(): Action
    {
        $duplicateAction = Action::new(
            ActionDefinition::DUPLICATE,
            $this->get(TranslatorAdmin::class)->transAction(ActionDefinition::DUPLICATE),
            'fa fa-fw fa-copy'
        )
            ->linkToCrudAction(ActionDefinition::DUPLICATE)
            ->setLabel($this->get(TranslatorAdmin::class)->transAction(ActionDefinition::DUPLICATE))
            ->setCssClass('in-dropdown text-info action-confirm');

        return $duplicateAction;
    }

    public function buildIndexActions(Actions $actions): void
    {
        $actions->add(Crud::PAGE_INDEX, $this->getDuplicateAction());

        $this->actionUpdate(
            $actions,
            Crud::PAGE_INDEX,
            ActionDefinition::NEW,
            [
                'icon' => 'plus',
                'label' => $this->get(TranslatorAdmin::class)->transAction('create'),
                'add_class' => 'btn-sm',
            ]
        );

        $this->actionUpdate(
            $actions,
            Crud::PAGE_INDEX,
            ActionDefinition::EDIT,
            [
                'class' => 'btn btn-sm btn-primary',
                'icon' => 'edit',
                'label' => false,
                'html_attributes' => array(
                    'data-toggle' => 'tooltip',
                    'title' => $this->get(TranslatorAdmin::class)->transAction('edit'),
                ),
            ]
        );

        $this->actionUpdate(
            $actions,
            Crud::PAGE_INDEX,
            ActionDefinition::DETAIL,
            [
                'icon' => 'eye',
                'add_class' => 'btn btn-sm btn-success',
                'label' => false,
                'html_attributes' => array(
                    'data-toggle' => 'tooltip',
                    'title' => $this->get(TranslatorAdmin::class)->transAction('detail'),
                ),
            ]
        );

        $this->actionUpdate(
            $actions,
            Crud::PAGE_INDEX,
            ActionDefinition::DELETE,
            [
                'icon' => 'trash',
                'dropdown' => true,
                'label' => $this->get(TranslatorAdmin::class)->transAction('delete'),
                'class' => 'dropdown-item text-danger in-dropdown action-delete',
            ]
        );

        $this->actionUpdate(
            $actions,
            Crud::PAGE_INDEX,
            ActionDefinition::BATCH_DELETE,
            [
                'class' => 'btn btn-sm btn-danger',
                'icon' => 'trash',
                'label' => $this->get(TranslatorAdmin::class)->transAction('delete'),
            ]
        );
    }


    public function buildEditActions(Actions $actions): void
    {
        $actions->add(Crud::PAGE_EDIT, ActionDefinition::INDEX);
        $actions->add(Crud::PAGE_EDIT, ActionDefinition::DELETE);


        $this->actionUpdate(
            $actions,
            Crud::PAGE_EDIT,
            ActionDefinition::SAVE_AND_RETURN,
            [
                'add_class' => 'float-right ',
                'icon' => 'check',
                'label' => $this->get(TranslatorAdmin::class)->transAction('save_and_return'),
            ]
        );

        $this->actionUpdate(
            $actions,
            Crud::PAGE_EDIT,
            ActionDefinition::INDEX,
            [
                'icon' => 'chevron-left',
                'class' => 'btn btn-link',
                'label' => $this->get(TranslatorAdmin::class)->transAction('back_index'),
            ]
        );


        $this->actionUpdate(
            $actions,
            Crud::PAGE_EDIT,
            ActionDefinition::SAVE_AND_CONTINUE,
            [
                'class' => 'btn btn-info float-right action-save-continue',
                'label' => $this->get(TranslatorAdmin::class)->transAction('save_and_continue'),
            ]
        );

        $this->actionUpdate(
            $actions,
            Crud::PAGE_EDIT,
            ActionDefinition::DELETE,
            [
                'icon' => 'trash',
                'class' => 'btn btn-outline-danger action-delete',
                'label' => $this->get(TranslatorAdmin::class)->transAction('delete'),
            ]
        );
    }

    public function buildDetailActions(Actions $actions): void
    {
    }

    public function buildNewActions(Actions $actions): void
    {
        $actions->add(Crud::PAGE_NEW, ActionDefinition::INDEX);

        $this->actionUpdate(
            $actions,
            Crud::PAGE_NEW,
            ActionDefinition::SAVE_AND_RETURN,
            [
                'add_class' => 'float-right',
                'icon' => 'check',
                'label' => $this->get(TranslatorAdmin::class)->transAction('save_and_return'),
            ]
        );

        $this->actionUpdate(
            $actions,
            Crud::PAGE_NEW,
            ActionDefinition::INDEX,
            [
                'icon' => 'chevron-left',
                'class' => 'btn btn-link',
                'label' => $this->get(TranslatorAdmin::class)->transAction('back_index'),
            ]
        );

        $this->actionUpdate(
            $actions,
            Crud::PAGE_NEW,
            ActionDefinition::SAVE_AND_ADD_ANOTHER,
            [
                'class' => 'btn btn-info float-right',
                'label' => $this->get(TranslatorAdmin::class)->transAction('save_and_add_another'),
            ]
        );
    }

    public function handleTranslatableEntityActions(Actions $actions): void
    {
        if ($this->isInstanceOf(TranslatableInterface::class)) {
            $actions->update(
                Crud::PAGE_INDEX,
                ActionDefinition::EDIT,
                function (Action $action) {
                    $action->setTemplatePath('@LcSov/adminlte/crud/action/translatable.html.twig');

                    return $action;
                }
            );
        }
    }

    public function handleSortableEntityActions(Actions $actions): void
    {
        if ($this->isInstanceOf(SortableInterface::class)) {
            $sortAction = Action::new(
                ActionDefinition::SORT,
                $this->get(TranslatorAdmin::class)->transAction(ActionDefinition::SORT),
                'fa fa-sort'
            )
                ->linkToCrudAction(ActionDefinition::SORT)
                ->setCssClass('btn btn-sm btn-success')
                ->createAsGlobalAction();

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

    public function handleTreeEntityActions(Actions $actions): void
    {
        if ($this->isInstanceOf(TreeInterface::class)) {
            $indexChildAction = Action::new(
                ActionDefinition::INDEX_CHILDREN,
                $this->get(TranslatorAdmin::class)->transAction(ActionDefinition::INDEX_CHILDREN),
                'fa fa-list'
            )
                ->linkToCrudAction(ActionDefinition::INDEX)
                ->setLabel('')
                ->setHtmlAttributes(array('data-toggle' => 'tooltip', 'title' => 'Afficher les enfants'))
                ->setTemplatePath('@LcSov/adminlte/crud/action/index_children.html.twig')
                ->setCssClass('btn btn-sm btn-success');

            $backParentAction = Action::new(
                ActionDefinition::INDEX_PARENT,
                $this->get(TranslatorAdmin::class)->transAction(ActionDefinition::INDEX_PARENT),
                'fa fa-chevron-left'
            )
                ->linkToCrudAction(ActionDefinition::INDEX)
                ->setCssClass('btn btn-sm btn-info')
                ->createAsGlobalAction();

            $actions->add(Crud::PAGE_INDEX, $backParentAction);
            $actions->add(Crud::PAGE_INDEX, $indexChildAction);
        }
    }

    public function actionUpdate($actions, $crudActionName, $actionName, array $button): void
    {
        if ($actions->getAsDto('actions')->getAction($crudActionName, $actionName)) {
            $actions->update(
                $crudActionName,
                $actionName,
                function (Action $action) use ($button) {
                    if (isset($button['add_class'])) {
                        $action->addCssClass($button['add_class']);
                    }

                    if (isset($button['class'])) {
                        $action->setCssClass($button['class']);
                    }

                    if (isset($button['icon'])) {
                        $action->setIcon('fa fa-' . $button['icon']);
                    }

                    if (isset($button['label'])) {
                        $action->setLabel($button['label']);
                    }

                    if (isset($button['dropdown']) && $button['dropdown']) {
                        $action->addCssClass('in-dropdown');
                    }

                    if (isset($button['html_attributes']) && $button['html_attributes']) {
                        $action->setHtmlAttributes($button['html_attributes']);
                    }

                    return $action;
                }
            );
        }
    }

    public function autocompleteFilter(AdminContext $context): JsonResponse
    {
        $repositoryQuery = $this->get(EntityRepository::class)->createRepositoryQuery(
            $this->getRepositoryQuery(),
            $context->getSearch(),
            $context->getEntity(),
            FieldCollection::new([]),
            FilterCollection::new()
        );

        if ($this->isInstanceOf(StatusInterface::class)) {
            $repositoryQuery->filterIsOnlineAndOffline();
        }

        $autocompleteContext = $context->getRequest()->get(AssociationField::PARAM_AUTOCOMPLETE_CONTEXT);

        /** @var CrudControllerInterface $controller */
        $controller = $this->get(ControllerFactory::class)->getCrudControllerInstance(
            $autocompleteContext[EA::CRUD_CONTROLLER_FQCN],
            ActionDefinition::INDEX,
            $context->getRequest()
        );
        /** @var FieldDto $field */
        $field = FieldCollection::new(
            $controller->configureFields($autocompleteContext['originatingPage'])
        )->getByProperty($autocompleteContext['propertyName']);

        $filterManager = $this->get(FilterManager::class);
        $filteredValue = ['value' => $context->getRequest()->query->get('q')];
        $filterManager->applyFilter($repositoryQuery, $field, $filteredValue);
        $repositoryQuery->select('.' . $autocompleteContext['propertyName']);

        $responses = array();
        foreach ($repositoryQuery->find() as $result) {
            $responses[] = array_values($result)[0];
        }

        return JsonResponse::fromJsonString(json_encode($responses));
    }

    public function createCustomForm($class, $action, $controller, $entity, $dataInOption = true, $options = array())
    {
        if ($dataInOption) {
            $data = $entity;
        } else {
            $data = null;
        }

        $options['action'] = $this->get(AdminUrlGenerator::class)
            ->setAction($action)
            ->setController($controller)
            ->setEntityId($entity->getId())
            ->generateUrl();

        return $this->createForm($class, $data, $options);
    }

    public function eaBeforeCrudActionEventDelete(AdminContext $context): ?Response
    {
        $event = new BeforeCrudActionEvent($context);
        $this->container->get('event_dispatcher')->dispatch($event);
        if ($event->isPropagationStopped()) {
            return $event->getResponse();
        }

        if (!$this->isGranted(Permission::EA_EXECUTE_ACTION, ['action' => Action::DELETE, 'entity' => $context->getEntity()])) {
            throw new ForbiddenActionException($context);
        }
        if (!$context->getEntity()->isAccessible()) {
            throw new InsufficientEntityPermissionException($context);
        }

        $csrfToken = $context->getRequest()->request->get('token');

        if (!$this->isCsrfTokenValid('ea-delete', $csrfToken)) {
            return $this->redirectToRoute($context->getDashboardRouteName());
        }
        return null;
    }

}

