<?php

declare(strict_types=1);

namespace App\Module\Commercial\Domain\Repository;

use App\Module\Commercial\Domain\Entity\Supplier;
use Doctrine\ORM\QueryBuilder;

interface SupplierRepositoryInterface
{
    public function findById(int $id): ?Supplier;

    public function save(Supplier $supplier): void;

    /**
     * Construit un QueryBuilder de liste pour le repertoire fournisseurs.
     * - Exclut toujours les fournisseurs soft-deletes (deleted_at IS NOT NULL, RG-2.17).
     * - Archivage (RG-2.17) :
     *     - $archivedOnly = true  -> uniquement les archives (is_archived = true) ;
     *     - sinon $includeArchived = true -> actifs + archives (echappatoire) ;
     *     - sinon (defaut) -> uniquement les actifs (is_archived = false).
     *   $archivedOnly a la priorite sur $includeArchived.
     * - Tri par defaut : companyName ASC (RG-2.17).
     * - $search : recherche fuzzy insensible a la casse sur companyName + les
     *   contacts lies (firstName / lastName / email) via sous-requete (D1,
     *   refonte-contact §4.1). Metacaracteres LIKE echappes. Ignore si null/vide.
     * - $categoryCodes : restreint aux fournisseurs possedant au moins une
     *   categorie dont le code est dans la liste (OR). Liste vide = pas de filtre.
     * - $siteIds : restreint aux fournisseurs ayant au moins une adresse rattachee
     *   a l'un des sites donnes (OR — RG-2.06). Liste vide = pas de filtre.
     *
     * Filtrage centralise ICI (et non dans le provider/controller) pour que la
     * liste paginee (SupplierProvider) et l'export (SupplierExportController)
     * partagent strictement la meme logique de selection.
     *
     * Contrat = SELECTION uniquement (filtres + tri). Aucun fetch-join to-many :
     * l'hydratation des collections affichees est deleguee a
     * {@see self::hydrateListCollections()} pour ne pas imposer le cout d'un
     * produit cartesien aux chemins non pagines (cf. M1/ERP-100).
     *
     * @param list<string> $categoryCodes
     * @param list<int>    $siteIds
     */
    public function createListQueryBuilder(
        bool $includeArchived = false,
        ?string $search = null,
        array $categoryCodes = [],
        array $siteIds = [],
        bool $archivedOnly = false,
    ): QueryBuilder;

    /**
     * Hydrate en lot les collections affichees par le repertoire (categories,
     * adresses et leurs sites) sur un jeu de fournisseurs DEJA charges, via
     * l'identity map Doctrine (memes instances). A appeler apres une selection
     * bornee (page courante ou jeu d'export) pour eviter le N+1 a la
     * serialisation, sans imposer de fetch-join au QueryBuilder de selection
     * (anti N+1, § 2.12).
     *
     * Charge les categories et les adresses/sites en DEUX requetes distinctes
     * (et non un triple fetch-join) pour ne pas multiplier categories x adresses
     * x sites en un seul produit cartesien.
     *
     * @param list<Supplier> $suppliers
     */
    public function hydrateListCollections(array $suppliers): void;

    /**
     * Hydrate en lot la collection `contacts` sur un jeu de fournisseurs DEJA
     * charges (memes instances via l'identity map). Reservee a l'export XLSX
     * (§ 4.6) qui a besoin du contact principal : la LISTE paginee n'embarque
     * pas les contacts (§ 2.12), d'ou une methode dediee plutot qu'une passe
     * supplementaire dans {@see self::hydrateListCollections()} — on n'impose pas
     * le cout du chargement des contacts au chemin liste.
     *
     * @param list<Supplier> $suppliers
     */
    public function hydrateContacts(array $suppliers): void;
}
