<?php

declare(strict_types=1);

namespace App\Module\Catalog\Infrastructure\Doctrine;

use App\Module\Catalog\Domain\Entity\Category;
use App\Module\Catalog\Domain\Repository\CategoryRepositoryInterface;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\ORM\QueryBuilder;
use Doctrine\Persistence\ManagerRegistry;

/**
 * @extends ServiceEntityRepository<Category>
 */
class DoctrineCategoryRepository extends ServiceEntityRepository implements CategoryRepositoryInterface
{
    public function __construct(ManagerRegistry $registry)
    {
        parent::__construct($registry, Category::class);
    }

    public function findById(int $id): ?Category
    {
        return $this->find($id);
    }

    public function save(Category $category): void
    {
        $this->getEntityManager()->persist($category);
        $this->getEntityManager()->flush();
    }

    public function existsActiveByCode(string $code, ?int $excludeId = null): bool
    {
        $qb = $this->createQueryBuilder('c')
            ->select('1')
            ->andWhere('c.code = :code')
            ->andWhere('c.deletedAt IS NULL')
            ->setParameter('code', $code)
            ->setMaxResults(1)
        ;

        if (null !== $excludeId) {
            $qb->andWhere('c.id != :excludeId')->setParameter('excludeId', $excludeId);
        }

        return [] !== $qb->getQuery()->getResult();
    }

    public function createListQueryBuilder(bool $includeDeleted = false, ?string $typeCode = null): QueryBuilder
    {
        $qb = $this->createQueryBuilder('c')
            ->orderBy('c.name', 'ASC')
        ;

        if (!$includeDeleted) {
            $qb->andWhere('c.deletedAt IS NULL');
        }

        // Filtre `?typeCode=` : jointure sur le CategoryType pour ne garder que
        // les categories du type demande (ex. FOURNISSEUR). La jointure reste
        // compatible avec le Paginator ORM (fetchJoinCollection) du provider.
        if (null !== $typeCode) {
            $qb->join('c.categoryType', 'ct')
                ->andWhere('ct.code = :typeCode')
                ->setParameter('typeCode', $typeCode)
            ;
        }

        return $qb;
    }
}
