<?php

namespace Lc\SovBundle\Field;

use Doctrine\ORM\EntityRepository;
use EasyCorp\Bundle\EasyAdminBundle\Contracts\Field\FieldInterface;
use EasyCorp\Bundle\EasyAdminBundle\Field\FieldTrait;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;

final class AssociationField implements FieldInterface
{
    use FieldTrait;

    public const OPTION_AUTOCOMPLETE = 'autocomplete';
    public const OPTION_CRUD_CONTROLLER = 'crudControllerFqcn';
    public const OPTION_WIDGET = 'widget';
    public const OPTION_QUERY_BUILDER_CALLABLE = 'queryBuilderCallable';
    /** @internal this option is intended for internal use only */
    public const OPTION_RELATED_URL = 'relatedUrl';
    /** @internal this option is intended for internal use only */
    public const OPTION_DOCTRINE_ASSOCIATION_TYPE = 'associationType';

    public const WIDGET_AUTOCOMPLETE = 'autocomplete';
    public const WIDGET_NATIVE = 'native';

    /** @internal this option is intended for internal use only */
    public const PARAM_AUTOCOMPLETE_CONTEXT = 'autocompleteContext';

    protected $queryBuilderParameters = array();

    /**
     * @param string|false|null $label
     */
    public static function new(string $propertyName, $label = null): self
    {
        return (new self())
                ->setProperty($propertyName)
                ->setLabel($label)
                ->setTemplatePath('@LcSov/adminlte/crud/field/association.html.twig')
                ->setFormType(EntityType::class)
                ->addCssClass('field-association')
                ->setCustomOption(self::OPTION_AUTOCOMPLETE, false)
                ->setCustomOption(self::OPTION_CRUD_CONTROLLER, null)
                ->setCustomOption(self::OPTION_WIDGET, self::WIDGET_AUTOCOMPLETE)
                ->setCustomOption(self::OPTION_QUERY_BUILDER_CALLABLE, null)
                ->setCustomOption(self::OPTION_RELATED_URL, '')
                ->setCustomOption(self::OPTION_DOCTRINE_ASSOCIATION_TYPE, null);
    }

    public function setFilterOnDevAlias(string $devAlias): self
    {
        $this->queryBuilderParameters['devAlias'] = $devAlias;

        return $this;
    }

    public function setFilterIsOnline(): self
    {
        $this->queryBuilderParameters['status'] = 1;

        return $this;
    }

    public function setLeftJoin($entityName): self
    {
        $this->queryBuilderParameters['leftJoin'][] = $entityName;

        return $this;
    }

    public function addAndWhere($whereClause, $key, $value): self
    {
        $this->queryBuilderParameters['andWhere'][] = [
                'whereClause' => $whereClause,
                'key' => $key,
                'value' => $value
        ];

        return $this;
    }

    public function addOrderBy($field, $direction = 'ASC'): self
    {
        $this->queryBuilderParameters['orderBy'][] = $field;
        $this->queryBuilderParameters['orderByDirection'][] = $direction;

        return $this;
    }

    /**
     * @deprecated Utiliser setFormTypeOption('choices', $choices) avec $choices issu d'un Store.
     */
    public function initQueryBuilder(): self
    {
        $param = $this->queryBuilderParameters;
        $this->setFormTypeOption(
                'query_builder',
                function (EntityRepository $er) use ($param) {
                    $qb = $er->createQueryBuilder('e');

                    if (isset($param['status'])) {
                        $qb->andWhere('e.status = :status')->setParameter('status', $param['status']);
                    }

                    if (isset($param['orderBy'])) {
                        foreach ($param['orderBy'] as $i => $field) {
                            $qb->addOrderBy('e.' . $param['orderBy'][$i], $param['orderByDirection'][$i]);
                        }
                    }

                    if (isset($param['leftJoin'])) {
                        foreach ($param['leftJoin'] as $i => $entityName) {
                            $qb->leftJoin('e.' . $entityName, $entityName)->addSelect($entityName);
                        }
                    }

                    if (isset($param['andWhere'])) {
                        foreach ($param['andWhere'] as $i => $whereClause) {
                            $qb->andWhere($whereClause['whereClause'])->setParameter($whereClause['key'], $whereClause['value']);
                        }
                    }

                    return $qb;
                }
        );
        return $this;
    }

    public function autocomplete(): self
    {
        $this->setCustomOption(self::OPTION_AUTOCOMPLETE, true);

        return $this;
    }

    public function renderAsNativeWidget(bool $asNative = true): self
    {
        $this->setCustomOption(self::OPTION_WIDGET, $asNative ? self::WIDGET_NATIVE : self::WIDGET_AUTOCOMPLETE);

        return $this;
    }

    public function setCrudController(string $crudControllerFqcn): self
    {
        $this->setCustomOption(self::OPTION_CRUD_CONTROLLER, $crudControllerFqcn);

        return $this;
    }
}
