<?php

declare(strict_types=1);

namespace App\Module\Catalog\Domain\Repository;

use App\Module\Catalog\Domain\Entity\Category;
use Doctrine\ORM\QueryBuilder;

interface CategoryRepositoryInterface
{
    public function findById(int $id): ?Category;

    public function save(Category $category): void;

    /**
     * Vrai si une categorie active (deleted_at IS NULL) porte deja ce code.
     * `$excludeId` exclut une categorie precise du test (cas PATCH). Sert a
     * garantir l'unicite du code generee par le CategoryCodeGenerator (ERP-78).
     */
    public function existsActiveByCode(string $code, ?int $excludeId = null): bool;

    /**
     * Construit un QueryBuilder de liste avec filtre soft-delete et tri par defaut.
     * - $includeDeleted = false : exclut les categories soft-deleted (RG-1.08)
     * - $typeCode non null : ne garde que les categories PORTANT ce code de type
     *   (filtre `?typeCode=`, ex. FOURNISSEUR / CLIENT). Sert au multi-select
     *   Categorie du fournisseur (M2, RG-2.10).
     * - $nameSearch non null : recherche partielle case-insensitive sur le nom
     *   (filtre `?name=` de la liste admin).
     * - $typeIds non vide : ne garde que les categories portant AU MOINS UN des
     *   types (OR, filtre `?typeId[]=` de la liste admin).
     * - Tri : name ASC (RG-1.10).
     *
     * Les categories etant en ManyToMany avec leurs types, la collection
     * `categoryTypes` est eager-loadee (addSelect) pour eviter un N+1 a la
     * serialisation, et `distinct` est applique des qu'un filtre type joint la
     * table de jonction (evite les lignes dupliquees).
     *
     * @param list<int> $typeIds
     */
    public function createListQueryBuilder(
        bool $includeDeleted = false,
        ?string $typeCode = null,
        ?string $nameSearch = null,
        array $typeIds = [],
    ): QueryBuilder;
}
