<?php

declare(strict_types=1);

namespace App\Filter;

use ApiPlatform\Doctrine\Orm\Filter\AbstractFilter;
use ApiPlatform\Doctrine\Orm\Util\QueryNameGeneratorInterface;
use ApiPlatform\Metadata\Operation;
use App\Entity\ConstructeurTelephone;
use Doctrine\ORM\QueryBuilder;

/**
 * Search filter pour Constructeur : LIKE insensible à la casse sur name, email
 * + LEFT JOIN sur la collection telephones pour matcher aussi sur telephone.numero.
 * Param query : ?search=...
 */
final class ConstructeurSearchFilter extends AbstractFilter
{
    public function getDescription(string $resourceClass): array
    {
        return [
            'search' => [
                'property'    => null,
                'type'        => 'string',
                'required'    => false,
                'description' => 'Recherche dans le nom, l\'email et les numéros de téléphone du fournisseur.',
                'openapi'     => [
                    'allowEmptyValue' => true,
                ],
            ],
        ];
    }

    protected function filterProperty(string $property, mixed $value, QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, ?Operation $operation = null, array $context = []): void
    {
        if ('search' !== $property || !is_string($value) || '' === trim($value)) {
            return;
        }

        $alias       = $queryBuilder->getRootAliases()[0];
        $telAlias    = $queryNameGenerator->generateJoinAlias('phoneSearch');
        $paramName   = $queryNameGenerator->generateParameterName('search');
        $likePattern = '%'.mb_strtolower(trim($value)).'%';

        $em            = $queryBuilder->getEntityManager();
        $phoneSubQuery = $em->createQueryBuilder()
            ->select('1')
            ->from(ConstructeurTelephone::class, $telAlias)
            ->where(sprintf('%1$s.constructeur = %2$s', $telAlias, $alias))
            ->andWhere(sprintf('LOWER(%s.numero) LIKE :%s', $telAlias, $paramName))
            ->getDQL()
        ;

        $queryBuilder
            ->andWhere(sprintf(
                'LOWER(%1$s.name) LIKE :%2$s OR LOWER(%1$s.email) LIKE :%2$s OR EXISTS (%3$s)',
                $alias,
                $paramName,
                $phoneSubQuery,
            ))
            ->setParameter($paramName, $likePattern)
        ;
    }
}
