<?php

namespace Modules\Stock\Trait\Validator;

use Entity\Model\Codecomp;
use Entity\Model\Paravrac;
use Entity\Model\SdsLign;
use Entity\Model\Sectimpu;
use Entity\Model\Sscptana;
use Exception;
use Helpers\Trad\Trad;
use Modules\Stock\Enum\CodeParametreVracEnum;
use Modules\Stock\Enum\TypeParametreVracEnum;
use Modules\Stock\Helper\NumberHelper;
use Modules\Stock\Service\ParametrageService;
use PDO;

trait LigneValidatorTrait
{
    /**
     * @param array<string,mixed> $ligneEntity
     * @param array<string,mixed> $enteteEntity
     * @param string $key
     * @return self
     */
    public function validateCodeArt(array $ligneEntity, array $enteteEntity, string $key = 'CODE_ART'): self
    {
        $codArticles = $this->listes->listeStocksLocaux(['filter_egal_STO#point#SITE' => $enteteEntity['SITE']], false);
        $this->contentInArray($this->trad->t('Code article'), $ligneEntity[$key], array_column($codArticles, null, 'CODE_ART'));

        return $this;
    }

    /**
     * @param array<string,mixed> $ligneEntity
     * @param null|CodeParametreVracEnum $codeParametreVracEnum
     * @param null|string $codeSte
     * @param string $property
     * @return self
     */
    public function validateSectimp(array $ligneEntity, ?CodeParametreVracEnum $codeParametreVracEnum, ?string $codeSte, string $property = 'SECTIMP'): self
    {
        $isSectimpFacultative = true;
        $configAxeImp = $this->paravrac->getCommandeAxeImpConfig($codeSte);

        if ($codeParametreVracEnum) {
            $isSectimpFacultative = (new ParametrageService($this->getPdo()))->isImputationFacultative($codeParametreVracEnum);
        }

        $this->zoom(
            'Sectimpu',
            $ligneEntity[$property],
            $this->trad->t('Section d\'imputation'),
            $this->pdo,
            $isSectimpFacultative,
            ($configAxeImp->SectImp->isSecto ? ['filter_egal_CODE_STE' => $codeSte] : [])
        );

        return $this;
    }

    /**
     * @param array<string,mixed> $ligneEntity
     * @param null|CodeParametreVracEnum $codeParametreVracEnum
     * @param null|string $codeSte
     * @param string $property
     * @return self
    */
    public function validateCodeComp(array $ligneEntity, ?CodeParametreVracEnum $codeParametreVracEnum, ?string $codeSte, string $property = 'CODE_COMP'): self
    {
        $isCodeCompFacultatif = true;
        $configAxeImp = $this->paravrac->getCommandeAxeImpConfig($codeSte);

        if ($codeParametreVracEnum) {
            $isCodeCompFacultatif = (new ParametrageService($this->getPdo()))->isImputationFacultative($codeParametreVracEnum);
        }

        $this->zoom(
            'Codecomp',
            $ligneEntity[$property],
            $this->trad->t('Code complémentaire'),
            $this->pdo,
            $isCodeCompFacultatif,
            ($configAxeImp->CodeCompl->isSecto ? ['filter_egal_CODE_STE' => $codeSte] : [])
        );

        return $this;
    }

    /**
     * @param array<string,mixed> $ligneEntity
     * @param null|CodeParametreVracEnum $codeParametreVracEnum
     * @param null|string $codeSte
     * @param string $property
     * @return self
     */
    public function validateSscpteana(array $ligneEntity, ?CodeParametreVracEnum $codeParametreVracEnum, ?string $codeSte, string $property = 'SSCPTEANA'): self
    {
        $isScaFacultatif = true;
        $configAxeImp = $this->paravrac->getCommandeAxeImpConfig($codeSte);

        if ($codeParametreVracEnum) {
            $isScaFacultatif = (new ParametrageService($this->getPdo()))->isImputationFacultative($codeParametreVracEnum);
        }

        $this->zoom(
            'Sscptana',
            $ligneEntity[$property],
            $this->trad->t('Sous compte d\'analyse'),
            $this->pdo,
            $isScaFacultatif,
            ($configAxeImp->SousCompteAna->isSecto ? ['filter_egal_CODE_STE' => $codeSte] : [])
        );

        return $this;
    }

    /**
     * @param array<string,mixed> $ligneEntity
     * @return $this
     * @throws Exception
     */
    public function validateSectimpDate(array $ligneEntity, CodeParametreVracEnum $codeParametreVracEnum): self
    {
        if (!$sectionImputation = (new Sectimpu($this->pdo))->find(['CODE_SI' => $ligneEntity['SECTIMP']])) {
            return $this;
        }

        $this->validateDateImputations($sectionImputation, $codeParametreVracEnum, 'SI');

        return $this;
    }

    /**
     * @param array<string,mixed> $ligneEntity
     * @return $this
     * @throws Exception
     */
    public function validateCodeCDCDate(array $ligneEntity, CodeParametreVracEnum $codeParametreVracEnum): self
    {
        if (!$codeComplementaire = (new Codecomp($this->pdo))->find(['CODE_CDC' => $ligneEntity['CODE_COMP']])) {
            return $this;
        }

        $this->validateDateImputations($codeComplementaire, $codeParametreVracEnum, 'CDC');

        return $this;
    }

    /**
     * @param array<string,mixed> $ligneEntity
     * @return $this
     * @throws Exception
     */
    public function validateSCADate(array $ligneEntity, CodeParametreVracEnum $codeParametreVracEnum): self
    {
        if (!$sousCompteAnalyse = (new Sscptana($this->pdo))->find(['CODE_SCA' => $ligneEntity['SSCPTEANA']])) {
            return $this;
        }

        $this->validateDateImputations($sousCompteAnalyse, $codeParametreVracEnum, 'SCA', 'DATE_MINI', 'DATE_MAXI');

        return $this;
    }

    /**
     * @param PDO $pdo
     * @param array<string,mixed> $ligneEntity
     * @param float $previousQteSorti
     * @return float|null
     * @throws Exception
     */
    public static function getMaxQteSortie(PDO $pdo, array $ligneEntity, float $previousQteSorti): ?float
    {
        if (!$ligneEntity['NO_DS']) {
            return null;
        }

        $reste = (new SdsLign($pdo))->find(['NO_DS' => $ligneEntity['NO_DS'], 'NO_LIG_DS' => $ligneEntity['NO_LIG_DS']], ['RESTE'])['RESTE'];

        return NumberHelper::toFloat($reste) + $previousQteSorti;
    }

    /**
     * @param array<string,mixed> $imputationEntity
     * @param CodeParametreVracEnum $codeParametreVracEnum
     * @param string $codeImputation
     * @param string $colonneDebut
     * @param string $colonneFin
     * @return void
     * @throws Exception
     */
    private function validateDateImputations(
        array                 $imputationEntity,
        CodeParametreVracEnum $codeParametreVracEnum,
        string                $codeImputation,
        string                $colonneDebut = 'DATE_DEB',
        string                $colonneFin = 'DATE_FIN'
    ): void {
        if (!$parametre = (new Paravrac($this->pdo))->find(['TYPEPARV' => TypeParametreVracEnum::PARASTOGEN->name, 'CODEPARV' => $codeParametreVracEnum->name])) {
            return;
        }

        $dateValiditeMin = $parametre['LIB01PARV'][0];
        $dateValiditeMax = $parametre['LIB01PARV'][1];

        if ($imputationEntity[$colonneDebut] > date('Ymd')) {
            $message = Trad::strBuild($this->trad->t('Date Validité Minimum @1@ Incorrecte'), $codeImputation);
            match ($dateValiditeMin) {
                'B' => $this->setError($message),
                'N' => $this->setErrorNonBloquant($message),
                default => null,
            };
        }
        if ($imputationEntity[$colonneFin] != '0000000' && $imputationEntity[$colonneFin] < date('Ymd')) {
            $message = Trad::strBuild($this->trad->t('Date Validité Maximum @1@ Incorrecte'), $codeImputation);
            match ($dateValiditeMax) {
                'B' => $this->setError($message),
                'N' => $this->setErrorNonBloquant($message),
                default => null,
            };
        }
    }
}
