<?php

/*
 * This file is part of the Serenity package.
 *
 * (c) CP Creation <web@cpcreation.fr>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Serenity\CoreBundle\Search;

use Symfony\Component\Validator\Constraints as Assert;

class SearchDTO implements SearchInterface
{
    #[Assert\Length(max: 64)]
    protected ?string $query = null;

    /**
     * Liste des options de tri disponibles pour une entité.
     *
     * Chaque clé représente un identifiant de tri (ex. : "date", "name").
     * Chaque valeur est un tableau associatif optionnel contenant :
     *
     * - 'property' (string, optionnel) :
     *   La propriété de l'entité ou de la jointure à utiliser pour effectuer le tri.
     *   Exemple : 'createdAt'.
     *
     * - 'join' (string, optionnel) :
     *   Le nom de l'association (relation Doctrine) à utiliser pour effectuer une jointure avant d'appliquer le tri.
     *   Laisser vide si aucune jointure n'est nécessaire.
     *   Exemple : 'comments' pour trier selon une propriété des commentaires liés.
     *
     * - 'method' (string, optionnel) :
     *   Détermine la manière de trier les résultats :
     *     - 'property' (valeur par défaut implicite) : tri direct sur la valeur de la propriété.
     *     - 'count' : effectue un tri basé sur le nombre d’éléments liés via une jointure.
     *
     * - 'sorter' (string, optionnel) :
     *    Détermine la manière de trier les résultats de A-Z ou Z-A . Ne fonctionne que si le choix de sorter n'est pas multiple
     *      - 'ASC' de A-Z
     *      - 'DESC' : de Z-A
     *
     * 📌 Exemple avec jointure :
     *    Si vous voulez trier des articles par le nombre de commentaires qu'ils ont :
     *      'comments_count' => [
     *          'property' => 'id',       // on compte les IDs de la relation
     *          'join' => 'comments',     // jointure sur la relation "comments"
     *          'method' => 'count'       // on trie par le nombre de commentaires
     *      ]
     *
     * Exemple d’utilisation :
     *   self::SORTER['date'] permet de trier par date de création.
     *   self::SORTER['name'] pourrait trier en fonction du nombre d'éléments liés selon la propriété.
     */
    /**
     * @var array<string, string|array{property: string}>|string|null
     */
    protected array|string|null $sorter = null;

    #[Assert\Choice(choices: self::DIRECTION)]
    protected ?string $direction = null;

    public function __construct(?string $query = null, ?string $direction = null, mixed $sorter = null)
    {
        $this->query = $query;
        $this->direction = $direction;
        $this->sorter = $sorter;
    }

    public function getQuery(): ?string
    {
        return $this->query;
    }

    /**
     * @return array<string, string|array{property: string}>
     */
    public function getSorter(): array
    {
        if (null === $this->sorter) {
            return [];
        }
        if (\is_string($this->sorter)) {
            return ['default' => $this->sorter]; // ✅ Clé string = OK pour PHPStan
        }

        return $this->sorter;
    }

    public function getDirection(): ?string
    {
        return $this->direction;
    }

    public static function fromArray(array $data): SearchInterface
    {
        return new self(
            $data['query'] ?? null,
            $data['direction'] ?? null,
            $data['sorter'] ?? null
        );
    }

    public function toArray(): array
    {
        return [
            'query' => $this->query,
            'sorter' => $this->sorter,
            'direction' => $this->direction,
        ];
    }
}
