<?php

declare(strict_types=1);

namespace App\Module\Technique\Application\Validator;

use ApiPlatform\Validator\Exception\ValidationException;
use App\Module\Technique\Domain\Entity\Provider;
use Symfony\Component\Validator\ConstraintViolation;
use Symfony\Component\Validator\ConstraintViolationList;

/**
 * Validator metier (spec-front M3 § Onglet Comptabilite — jumeau de
 * SupplierAccountingCompletenessValidator M2) : a la soumission complete de
 * l'onglet Comptabilite, les six champs scalaires obligatoires doivent etre
 * renseignes (SIREN, Numero de compte, Mode de TVA, N de TVA, Delai de reglement,
 * Type de reglement). La banque reste conditionnelle (RG-3.07) et les RIB aussi
 * (RG-3.08) : ils ne sont pas couverts ici (Assert\Callback sur l'entite Provider
 * — validatePaymentTypeConsistency).
 *
 * Parti pris (miroir M1/M2) : colonnes nullable en base + validateur contextuel,
 * plutot qu'un Assert\NotBlank sur l'entite (qui casserait le POST de l'onglet
 * principal, lequel n'envoie aucun champ comptable).
 *
 * Invoque par le ProviderProcessor uniquement quand le payload porte les six
 * champs (= une validation d'onglet), jamais sur un PATCH ciblant un seul champ.
 *
 * Leve une ValidationException (HTTP 422) listant chaque champ manquant, par
 * coherence avec les violations Symfony rendues par API Platform (mapping inline
 * front via useFormErrors, ERP-101).
 */
final class ProviderAccountingCompletenessValidator
{
    public function validate(Provider $provider): void
    {
        // Map champ -> valeur courante des champs obligatoires de l'onglet.
        $fields = [
            'siren'         => $provider->getSiren(),
            'accountNumber' => $provider->getAccountNumber(),
            'tvaMode'       => $provider->getTvaMode(),
            'nTva'          => $provider->getNTva(),
            'paymentDelay'  => $provider->getPaymentDelay(),
            'paymentType'   => $provider->getPaymentType(),
        ];

        $violations = new ConstraintViolationList();

        foreach ($fields as $property => $value) {
            if ($this->isMissing($value)) {
                $violations->add(new ConstraintViolation(
                    'Ce champ est obligatoire.',
                    null,
                    [],
                    $provider,
                    $property,
                    $value,
                ));
            }
        }

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

    /**
     * Une valeur est manquante si null ou, pour une chaine, vide apres trim. Les
     * references (TvaMode / PaymentDelay / PaymentType) ne sont manquantes que
     * lorsqu'elles valent null.
     */
    private function isMissing(mixed $value): bool
    {
        if (null === $value) {
            return true;
        }

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