<?php

declare(strict_types=1);

namespace App\Module\Reporting\Infrastructure\ApiPlatform\State;

use DateTimeImmutable;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;

/**
 * Validation stricte des filtres query-param partages par les providers de reporting.
 *
 * Toutes les valeurs validees ici sont destinees a etre passees en bound params
 * (jamais interpolees dans le SQL). On rejette en 400 explicite tout input
 * malforme plutot que de laisser PostgreSQL lever une 500.
 */
trait ReportFilterTrait
{
    /**
     * Valide une date au format strict YYYY-MM-DD.
     *
     * @param mixed $value valeur brute issue des query-params
     *
     * @return null|string la date validee, ou null si absente/vide
     */
    private function validateDate(mixed $value, string $paramName): ?string
    {
        if (null === $value || '' === $value) {
            return null;
        }

        if (!is_string($value)) {
            throw new BadRequestHttpException(sprintf('Filtre "%s" invalide : date YYYY-MM-DD attendue.', $paramName));
        }

        $date = DateTimeImmutable::createFromFormat('!Y-m-d', $value);

        if (false === $date || $date->format('Y-m-d') !== $value) {
            throw new BadRequestHttpException(sprintf('Filtre "%s" invalide : date YYYY-MM-DD attendue (recu: "%s").', $paramName, $value));
        }

        return $value;
    }

    /**
     * Valide un identifiant entier strictement positif.
     *
     * @param mixed $value valeur brute issue des query-params
     *
     * @return null|int l'identifiant valide, ou null si absent/vide
     */
    private function validatePositiveInt(mixed $value, string $paramName): ?int
    {
        if (null === $value || '' === $value) {
            return null;
        }

        // Les query-params arrivent sous forme de chaine : on valide donc le
        // format decimal positif via regex (rejette "1.5", "abc", "-3", "01"...)
        // plutot qu'une comparaison de type juggling sensible au cs-fixer.
        if ((!is_string($value) && !is_int($value)) || 1 !== preg_match('/^[1-9][0-9]*$/', (string) $value)) {
            throw new BadRequestHttpException(sprintf('Filtre "%s" invalide : entier positif attendu.', $paramName));
        }

        return (int) $value;
    }

    /**
     * Resout la plage [from, to[ avec defaut = mois courant si les deux bornes sont absentes.
     *
     * @param array<string, mixed> $filters
     *
     * @return array{0: string, 1: string} [from inclus, to exclus] au format YYYY-MM-DD
     */
    private function resolveDateRange(array $filters): array
    {
        $from = $this->validateDate($filters['from'] ?? null, 'from');
        $to   = $this->validateDate($filters['to'] ?? null, 'to');

        if (null === $from) {
            $from = new DateTimeImmutable('first day of this month')->format('Y-m-d');
        }
        if (null === $to) {
            $to = new DateTimeImmutable('first day of next month')->format('Y-m-d');
        }

        return [$from, $to];
    }
}
