<?php

declare(strict_types=1);

namespace App\Module\Commercial\Application\Validator;

use ApiPlatform\Validator\Exception\ValidationException;
use App\Module\Commercial\Domain\Entity\Supplier;
use Symfony\Component\Validator\ConstraintViolation;
use Symfony\Component\Validator\ConstraintViolationList;

/**
 * Validator metier RG-2.03 (completude Information cote fournisseur) :
 * pour un utilisateur portant le role metier Commerciale, TOUS les champs de
 * l'onglet Information sont obligatoires sur POST comme sur tout PATCH,
 * independamment des champs reellement envoyes.
 *
 * Invoque par le SupplierProcessor des que l'utilisateur courant porte le role
 * Commerciale (detection du role cote back). Pour les autres roles, ces champs
 * restent optionnels — le validator n'est pas appele.
 *
 * NEW vs Client : ajoute le champ `volumeForecast` (volume previsionnel),
 * specifique fournisseur.
 *
 * Leve une ValidationException (HTTP 422) listant chaque champ manquant, chaque
 * violation portant son propertyPath (consommable par extractApiViolations,
 * ERP-101), par coherence avec les violations Symfony rendues par API Platform.
 */
final class SupplierInformationCompletenessValidator
{
    public function validate(Supplier $supplier): void
    {
        // Map champ -> valeur courante de l'onglet Information.
        $fields = [
            'description'    => $supplier->getDescription(),
            'competitors'    => $supplier->getCompetitors(),
            'foundedAt'      => $supplier->getFoundedAt(),
            'employeesCount' => $supplier->getEmployeesCount(),
            'revenueAmount'  => $supplier->getRevenueAmount(),
            'directorName'   => $supplier->getDirectorName(),
            'profitAmount'   => $supplier->getProfitAmount(),
            'volumeForecast' => $supplier->getVolumeForecast(),
        ];

        $violations = new ConstraintViolationList();

        foreach ($fields as $property => $value) {
            if ($this->isMissing($value)) {
                $violations->add(new ConstraintViolation(
                    // Pas de nom de champ technique dans le message : la violation est
                    // deja rattachee au bon champ via son propertyPath (mappe inline
                    // cote front par useFormErrors).
                    'Ce champ est obligatoire pour le rôle Commerciale.',
                    null,
                    [],
                    $supplier,
                    $property,
                    $value,
                ));
            }
        }

        if (count($violations) > 0) {
            throw new ValidationException($violations);
        }
    }

    /**
     * Une valeur est manquante si null ou, pour une chaine, vide apres trim. Les
     * zeros numeriques (employeesCount = 0, profitAmount = "0.00",
     * volumeForecast = 0) sont des valeurs valides : on ne les considere pas
     * manquants.
     */
    private function isMissing(mixed $value): bool
    {
        if (null === $value) {
            return true;
        }

        return is_string($value) && '' === trim($value);
    }
}
