<?php

namespace Lc\SovBundle\Field\Filter;

use Doctrine\ORM\EntityManagerInterface;

use DoctrineExtensions\Query\Mysql\Field;
use EasyCorp\Bundle\EasyAdminBundle\Config\Crud;
use EasyCorp\Bundle\EasyAdminBundle\Contracts\Field\FieldInterface;
use EasyCorp\Bundle\EasyAdminBundle\Dto\EntityDto;
use EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto;
use Lc\SovBundle\Repository\RepositoryQueryInterface;
use Lc\SovBundle\Translation\TranslatorAdmin;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\DateTimeType;
use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\IntegerType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Form;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Session\SessionInterface;


/**
 * @author La clic ! <contact@laclic.fr>
 */
class FilterManager
{
    protected $em;
    protected bool $isFiltered = false;
    protected $translatorAdmin;

    use FilterTrait;

    public function __construct(
        SessionInterface $session,
        EntityManagerInterface $entityManager,
        TranslatorAdmin $translatorAdmin
    ) {
        $this->session = $session;
        $this->em = $entityManager;
        $this->translatorAdmin = $translatorAdmin;
    }


    public function handleFiltersForm(
        RepositoryQueryInterface $repositoryQuery,
        Form $filtersForm,
        $fields,
        EntityDto $entityDto
    ): bool {
        foreach ($fields as $field) {
            $filteredValue = array();
            if ($field instanceof FieldInterface) {
                $fieldDto = $field->getAsDto();
            } else {
                $fieldDto = $field;
            }
            if ($fieldDto->isDisplayedOn(Crud::PAGE_INDEX)) {
                if ($filtersForm->has($this->getFieldPropertySnake($fieldDto->getProperty()))) {
                    if ($fieldDto->getFormType() === DateTimeType::class || $fieldDto->getFormType(
                        ) === DateType::class) {
                        $filteredValue['dateStart'] = $this->getFilteredValue(
                            $filtersForm,
                            $entityDto->getFqcn(),
                            $fieldDto->getProperty(),
                            'dateStart'
                        );
                        $filteredValue['dateEnd'] = $this->getFilteredValue(
                            $filtersForm,
                            $entityDto->getFqcn(),
                            $fieldDto->getProperty(),
                            'dateEnd'
                        );
                        if ($filteredValue['dateStart'] || $filteredValue['dateEnd']) {
                            $this->isFiltered = true;
                        }
                    } else {
                        $filteredValue['value'] = $this->getFilteredValue(
                            $filtersForm,
                            $entityDto->getFqcn(),
                            $fieldDto->getProperty()
                        );
                        if ($filteredValue['value']) {
                            $this->isFiltered = true;
                        }
                    }

                    $this->applyFilter($repositoryQuery, $fieldDto, $filteredValue);
                }
            }
        }
        return $this->isFiltered;
    }


    public function applyFilter(RepositoryQueryInterface $repositoryQuery, FieldDto $fieldDto, array $filteredValue)
    {
        if ($fieldDto->getCustomOption('filter_fqcn')) {
            $filterFqcn = $fieldDto->getCustomOption('filter_fqcn');
            $customFilter = new $filterFqcn($this->translatorAdmin);

            $customFilter->applyFilter($repositoryQuery, $fieldDto, $filteredValue['value']);
        } else {
            switch ($fieldDto->getFormType()) {
                case CheckboxType::class:
                    $checkboxFilter = new CheckboxFilter();
                    $checkboxFilter->applyFilter($repositoryQuery, $fieldDto, $filteredValue['value']);
                    break;
                case ChoiceType::class:
                    $choiceFilter = new ChoiceFilter();
                    $choiceFilter->applyFilter($repositoryQuery, $fieldDto, $filteredValue['value']);
                    break;
                case IntegerType::class:
                    $integerFilter = new IntegerFilter();
                    $integerFilter->applyFilter($repositoryQuery, $fieldDto, $filteredValue['value']);
                    break;
                case TextareaType::class:
                case TextType::class:
                case EmailType::class:
                    $textFilter = new TextFilter();
                    $textFilter->applyFilter($repositoryQuery, $fieldDto, $filteredValue['value']);
                    break;
                case EntityType::class:
                    $textFilter = new AssociationFilter();
                    $textFilter->applyFilter($repositoryQuery, $fieldDto, $filteredValue['value']);
                    break;
                case DateTimeType::class:
                case DateType::class:
                    $textFilter = new DateFilter();
                    $textFilter->applyFilter(
                        $repositoryQuery,
                        $fieldDto,
                        $filteredValue['dateStart'],
                        $filteredValue['dateEnd']
                    );
                    break;
            }
        }
    }

    public function getFilteredValue(
        Form $filtersForm,
        string $entityFqcn,
        string $field,
        string $dateExtraField = null
    ) {
        $field = $this->getFieldPropertySnake($field);
        $sessionParam = "_filter/" . $entityFqcn . $field . $dateExtraField;
        $formField = $this->getFormField($filtersForm, $field, $dateExtraField);

        $value = $formField->getData();

        //Il existe une valeur posté dans le formulaire
        if ($value !== null) {
            $this->session->set($sessionParam, $value);
            return $value;
        }
        // pas de valeur et le form est envoyé, on supprimer le filtre correspondant
        elseif($formField->isSubmitted()) {
            $this->session->remove($sessionParam);
        }

        //action reset
        if ($filtersForm->get('reset')->getData() == 'clearAll') {
            $this->session->remove($sessionParam);
            return null;
        }

        //Récupération des valeurs stocké en sessions si le forrmFilters n'a pas été posté
        if ($this->session->get($sessionParam) && !$filtersForm->isSubmitted() && $formField) {
            $value = $this->session->get($sessionParam);

            //Champ date
            if ($formField->getConfig()->getOption('input') == 'datetime') {
                $filtersForm->get($field)->get($dateExtraField)->setData($value);
                //Champ association
            } elseif ($formField->getConfig()->getOption('class')) {
                $valFormated = $this->em->getRepository(
                    $formField->getConfig()->getOption('class')
                )->find($value);
                $filtersForm->get($field)->setData($valFormated);
            } else {
                //Champ noramux
                $filtersForm->get($field)->setData($value);
            }

            return $value;
        }
    }

    public function getFormField(Form $filtersForm, string $field, string $extraField = null): Form
    {
        if ($extraField) {
            return $filtersForm->get($field)->get($extraField);
        } else {
            return $filtersForm->get($field);
        }
    }

}
