<?php

namespace Lc\CaracoleBundle\Controller;

use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\QueryBuilder;
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\Context\AdminContext;
use EasyCorp\Bundle\EasyAdminBundle\Exception\ForbiddenActionException;
use EasyCorp\Bundle\EasyAdminBundle\Exception\InsufficientEntityPermissionException;
use EasyCorp\Bundle\EasyAdminBundle\Router\AdminUrlGenerator;
use EasyCorp\Bundle\EasyAdminBundle\Security\Permission;
use Lc\CaracoleBundle\Container\Address\AddressContainer;
use Lc\CaracoleBundle\Container\Config\TaxRateContainer;
use Lc\CaracoleBundle\Container\Config\UnitContainer;
use Lc\CaracoleBundle\Container\Credit\CreditHistoryContainer;
use Lc\CaracoleBundle\Container\File\DocumentContainer;
use Lc\CaracoleBundle\Container\Merchant\MerchantContainer;
use Lc\CaracoleBundle\Container\Order\OrderPaymentContainer;
use Lc\CaracoleBundle\Container\Order\OrderProductContainer;
use Lc\CaracoleBundle\Container\Order\OrderProductReductionCatalogContainer;
use Lc\CaracoleBundle\Container\Order\OrderProductRefundContainer;
use Lc\CaracoleBundle\Container\Order\OrderReductionCartContainer;
use Lc\CaracoleBundle\Container\Order\OrderReductionCreditContainer;
use Lc\CaracoleBundle\Container\Order\OrderRefundContainer;
use Lc\CaracoleBundle\Container\Order\OrderShopContainer;
use Lc\CaracoleBundle\Container\Order\OrderStatusContainer;
use Lc\CaracoleBundle\Container\Order\OrderStatusHistoryContainer;
use Lc\CaracoleBundle\Container\PointSale\PointSaleContainer;
use Lc\CaracoleBundle\Container\Product\ProductCategoryContainer;
use Lc\CaracoleBundle\Container\Product\ProductContainer;
use Lc\CaracoleBundle\Container\Product\ProductFamilyContainer;
use Lc\CaracoleBundle\Container\Reduction\ReductionCartContainer;
use Lc\CaracoleBundle\Container\Reduction\ReductionCatalogContainer;
use Lc\CaracoleBundle\Container\Reduction\ReductionCreditContainer;
use Lc\CaracoleBundle\Container\Section\OpeningContainer;
use Lc\CaracoleBundle\Container\Section\SectionContainer;
use Lc\CaracoleBundle\Container\Setting\MerchantSettingContainer;
use Lc\CaracoleBundle\Container\Setting\SectionSettingContainer;
use Lc\CaracoleBundle\Container\User\UserMerchantContainer;
use Lc\CaracoleBundle\Container\User\UserPointSaleContainer;
use Lc\CaracoleBundle\Container\User\VisitorContainer;
use Lc\CaracoleBundle\Doctrine\Extension\FilterMerchantInterface;
use Lc\CaracoleBundle\Doctrine\Extension\FilterMultipleMerchantsInterface;
use Lc\CaracoleBundle\Doctrine\Extension\FilterSectionInterface;
use Lc\CaracoleBundle\Form\Merchant\DuplicateToOtherMerchantFormType;
use Lc\CaracoleBundle\Form\Section\DuplicateToOtherSectionFormType;
use Lc\CaracoleBundle\Resolver\MerchantResolver;
use Lc\CaracoleBundle\Resolver\SectionResolver;
use EasyCorp\Bundle\EasyAdminBundle\Dto\EntityDto;
use EasyCorp\Bundle\EasyAdminBundle\Dto\SearchDto;
use Lc\SovBundle\Component\EntityComponent;
use Lc\SovBundle\Translation\TranslatorAdmin;
use Symfony\Component\HttpFoundation\Response;

trait AdminControllerTrait
{

    public static function getSubscribedServices()
    {
        return array_merge(
                parent::getSubscribedServices(),
                [
                        MerchantResolver::class => MerchantResolver::class,
                        SectionResolver::class=> SectionResolver::class,
                        AddressContainer::class => AddressContainer::class,
                        TaxRateContainer::class => TaxRateContainer::class,
                        UnitContainer::class => UnitContainer::class,
                        CreditHistoryContainer::class => CreditHistoryContainer::class,
                        DocumentContainer::class => DocumentContainer::class,
                        MerchantContainer::class => MerchantContainer::class,
                        OrderPaymentContainer::class => OrderPaymentContainer::class,
                        OrderProductContainer::class => OrderProductContainer::class,
                        OrderProductReductionCatalogContainer::class => OrderProductReductionCatalogContainer::class,
                        OrderProductRefundContainer::class => OrderProductRefundContainer::class,
                        OrderReductionCartContainer::class => OrderReductionCartContainer::class,
                        OrderReductionCreditContainer::class => OrderReductionCreditContainer::class,
                        OrderRefundContainer::class => OrderRefundContainer::class,
                        OrderShopContainer::class => OrderShopContainer::class,
                        OrderStatusContainer::class => OrderStatusContainer::class,
                        OrderStatusHistoryContainer::class => OrderStatusHistoryContainer::class,
                        PointSaleContainer::class => PointSaleContainer::class,
                        ProductCategoryContainer::class => ProductCategoryContainer::class,
                        ProductContainer::class => ProductContainer::class,
                        ProductFamilyContainer::class => ProductFamilyContainer::class,
                        ReductionCartContainer::class => ReductionCartContainer::class,
                        ReductionCatalogContainer::class => ReductionCatalogContainer::class,
                        ReductionCreditContainer::class => ReductionCreditContainer::class,
                        OpeningContainer::class => OpeningContainer::class,
                        SectionContainer::class => SectionContainer::class,
                        MerchantSettingContainer::class => MerchantSettingContainer::class,
                        SectionSettingContainer::class => SectionSettingContainer::class,
                        UserMerchantContainer::class => UserMerchantContainer::class,
                        UserPointSaleContainer::class => UserPointSaleContainer::class,
                        VisitorContainer::class => VisitorContainer::class
                ]
        );
    }

    public function configureResponseParameters(KeyValueStore $responseParameters): KeyValueStore
    {
        $responseParameters = parent::configureResponseParameters($responseParameters);

        // affichage du filtre sur section
        if ($this->isInstanceOf(FilterSectionInterface::class)) {
            $responseParameters->set('display_switch_section', true);
        }

        return $responseParameters;
    }

    public function createIndexQueryBuilder(
            SearchDto $searchDto,
            EntityDto $entityDto,
            FieldCollection $fields,
            FilterCollection $filters
    ): QueryBuilder {
        $queryBuilder = parent::createIndexQueryBuilder(
                $searchDto,
                $entityDto,
                $fields,
                $filters
        );

        //TODO Gérer depuis les événements

        if ($this->isInstanceOf(FilterMerchantInterface::class)) {
            $queryBuilder->andWhereMerchant('entity', $this->get(MerchantResolver::class)->getCurrent());
        }

        if ($this->isInstanceOf(FilterMultipleMerchantsInterface::class)) {
            $queryBuilder->andWhere(':merchant MEMBER OF entity.merchants');
            $queryBuilder->setParameter('merchant', $this->get(MerchantResolver::class)->getCurrent());
        }

        if ($this->isInstanceOf(FilterSectionInterface::class)) {
            $queryBuilder->andWhereSection('entity', $this->get(SectionResolver::class)->getCurrent());
        }

        return $queryBuilder;
    }


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

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

        if (!$this->isInstanceOf(FilterMerchantInterface::class)) {
            throw new \ErrorException('L\entité n\'est pas lié à un merchant.');
        }
        $duplicateOtherMerchantForm = $this->createForm(
                DuplicateToOtherMerchantFormType::class,
                null,
                array(
                        'entityClass' => $context->getEntity()->getFqcn(),
                        'entityId' => $context->getEntity()->getInstance()->getId(),
                        'action' => $context->getRequest()->getUri(),
                        'attr' => ['id' => 'duplicate-other-merchant-form'],

                )
        );

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

        if ($duplicateOtherMerchantForm->isSubmitted() && $duplicateOtherMerchantForm->isValid()) {
            $newEntity = $entityComponent->duplicateEntity($context->getEntity()->getInstance());
            $em->create($newEntity);
            $merchant = $duplicateOtherMerchantForm->get('merchants')->getData();
            $newEntity->setMerchant($merchant);
            $em->update($newEntity);
            $em->flush();

            $url = $this->get(AdminUrlGenerator::class)
                    ->setAction(Action::EDIT)
                    ->setEntityId($newEntity->getId())
                    ->generateUrl();
            $this->addFlash(
                    'success',
                    $translatorAdmin->transFlashMessage(
                            'duplicateToOtherMerchant',
                            ['%merchant%' => $merchant->getTitle()]
                    ),
                    array()
            );

            //TODO switch merchant route
            return $this->redirect($url);
        }


        if ($context->getRequest()->isXmlHttpRequest()) {
            $response['data'] = $this->renderView(
                    '@LcCaracole/admin/merchant/modal/duplicate_entity_to_other_merchant.html.twig',
                    array(
                            'form_duplicate_entity_to_other_merchant' => $duplicateOtherMerchantForm->createView(),
                    )
            );

            return new Response(json_encode($response));
        } else {
            throw new \ErrorException('La requête doit être effectué en ajax');
        }
    }

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

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

        if (!$this->isInstanceOf(FilterSectionInterface::class)) {
            throw new \ErrorException('L\entité n\'est pas lié à un merchant.');
        }
        $duplicateOtherSectionForm = $this->createForm(
                DuplicateToOtherSectionFormType::class,
                null,
                array(
                        'entityClass' => $context->getEntity()->getFqcn(),
                        'entityId' => $context->getEntity()->getInstance()->getId(),
                        'action' => $context->getRequest()->getUri(),
                        'attr' => ['id' => 'duplicate-other-section-form'],
                )
        );

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

        if ($duplicateOtherSectionForm->isSubmitted() && $duplicateOtherSectionForm->isValid()) {
            $newEntity = $entityComponent->duplicateEntity($context->getEntity()->getInstance());
            $em->create($newEntity);
            $section = $duplicateOtherSectionForm->get('sections')->getData();
            $newEntity->setSection($section);
            $em->update($newEntity);
            $em->flush();

            $url = $this->get(AdminUrlGenerator::class)
                    ->setAction(Action::EDIT)
                    ->setEntityId($newEntity->getId())
                    ->generateUrl();
            $this->addFlash(
                    'success',
                    $translatorAdmin->transFlashMessage(
                            'duplicateToOtherSection',
                            ['%section%' => $section->getTitle()]
                    ),
                    array()
            );

            //TODO switch merchant route
            return $this->redirect($url);
        }


        if ($context->getRequest()->isXmlHttpRequest()) {
            $response['data'] = $this->renderView(
                    '@LcCaracole/admin/merchant/modal/duplicate_entity_to_other_section.html.twig',
                    array(
                            'form_duplicate_entity_to_other_section' => $duplicateOtherSectionForm->createView(),
                    )
            );

            return new Response(json_encode($response));
        } else {
            throw new \ErrorException('La requête doit être effectué en ajax');
        }
    }


    public function buildIndexActions(Actions $actions): void
    {
        parent::buildIndexActions($actions);
        if ($this->isInstanceOf(FilterMerchantInterface::class)) {
            $actions->add(Crud::PAGE_INDEX, $this->getDuplicateToOhterMerchantAction());
        }

        if ($this->isInstanceOf(FilterSectionInterface::class)) {
            $actions->add(Crud::PAGE_INDEX, $this->getDuplicateToOhterSectionAction());
        }
    }

    public function getDuplicateToOhterMerchantAction(): Action
    {
        $duplicateAction = Action::new(
                'duplicateToOtherMerchant',
                $this->get(TranslatorAdmin::class)->transAction('duplicateToOtherMerchant'),
                'fa fa-fw fa-copy'
        )
                ->linkToCrudAction('duplicateToOtherMerchant')
                ->setCssClass('text-info in-dropdown duplicate-to-other-merchant duplicate-modal-action');

        return $duplicateAction;
    }

    public function getDuplicateToOhterSectionAction(): Action
    {
        $duplicateAction = Action::new(
                'duplicateToOtherSection',
                $this->get(TranslatorAdmin::class)->transAction('duplicateToOtherSection'),
                'fa fa-fw fa-copy'
        )
                ->linkToCrudAction('duplicateToOtherSection')
                ->setCssClass('text-info in-dropdown duplicate-to-other-section duplicate-modal-action');

        return $duplicateAction;
    }
}