<?php

namespace Modules\Stock\Service\Form;

use Entity\Model\Sarticle;
use Entity\Model\SbeEnte;
use Entity\Model\SbeLign;
use Entity\Model\SbentLo;
use Entity\Model\Sstocklo;
use Exception;
use Helpers\ChampsSupplementaire\ChampSupp;
use Helpers\Outil\Sql;
use Modules\Stock\Enum\LigneOperationEnum;
use Modules\Stock\Helper\NumberHelper;
use Modules\Stock\Helper\StringHelper;
use Modules\Stock\Interface\FormServiceInterface;
use Modules\Stock\Interface\FormTotalEnteteInterface;
use Modules\Stock\Interface\TracableStockArticleInterface;
use Modules\Stock\Repository\LigneBonEntreeRepo;
use Modules\Stock\Trait\FormTrait;
use PDO;

readonly class LigneBonEntreeFormService implements FormServiceInterface, TracableStockArticleInterface, FormTotalEnteteInterface
{
    use FormTrait;

    public function __construct(private PDO $pdo)
    {
    }

    /**
     * @param array<string,mixed> $post
     * @param array<string,mixed> $data
     * @return array<string,mixed>
     * @throws Exception
     */
    public function initEntity(array $post, array $data = []): array
    {
        $post['NO_BE'] = $data['NO_BE'];
        $this->gererCodgestPropriete($post);
        $post['NO_LIG_BE'] = (new LigneBonEntreeRepo($this->pdo))->getNouveauNoLigne($data['NO_BE'], 'NO_LIG_BE', 'SBE_LIGN', 'NO_BE');

        return $post;
    }

    /**
     * @param array<string,mixed> $entity
     * @param array<string,mixed> $post
     * @return void
     * @throws Exception
     */
    public function flushData(array $entity, array $post = []): void
    {
        $sbeEnte = new SbeEnte($this->pdo);
        $sArticle = new Sarticle($this->pdo);
        $sStockLo = new Sstocklo($this->pdo);
        $stockArticle = $sArticle->find(['CODE_ART' => $entity['CODE_ART']]);
        $previousQteBonEntree = array_key_exists('PREV_QTE_ENT', $post) ? $post['PREV_QTE_ENT'] : 0;

        $this->pdo->beginTransaction();

        (new SbeLign($this->pdo))->processAndMerge($entity);
        ChampSupp::updateCS($post, $this->pdo);
        self::updateStockArticle($sArticle, $post['BON_ENTREE'], $entity, $post['operation'], $previousQteBonEntree);
        self::updateStockLocal($sStockLo, $post['BON_ENTREE'], $entity, $post['operation'], $previousQteBonEntree);
        $sbeEnte->merge($post['BON_ENTREE']);
        $this->updateLotsCollection($stockArticle, $entity, $post);

        $this->pdo->commit();
    }

    /**
     * @param array<string,mixed> $enteteEntity
     * @param array<string,mixed> $ligneEntity
     * @param LigneOperationEnum $ligneOperationEnum
     * @param float|null $previousLigneTotalValue
     * @return void
     */
    public function updateTotalEntete(
        array &$enteteEntity,
        array $ligneEntity,
        LigneOperationEnum $ligneOperationEnum,
        ?float $previousLigneTotalValue = null
    ): void {
        $totalBonEntree = NumberHelper::toFloat($enteteEntity['TOT_BE']);
        $qteEntree = NumberHelper::toFloat($ligneEntity['QTE_ENT']);
        $prix = NumberHelper::toFloat($ligneEntity['PRIX_ENT']);

        match ($ligneOperationEnum) {
            LigneOperationEnum::ADD => $enteteEntity['TOT_BE'] = $totalBonEntree + ($qteEntree * $prix),
            LigneOperationEnum::EDIT => $enteteEntity['TOT_BE'] = $totalBonEntree + ($qteEntree * $prix) - $previousLigneTotalValue,
            LigneOperationEnum::DELETE => $enteteEntity['TOT_BE'] = $totalBonEntree - ($qteEntree * $prix)
        };
    }

    /**
     * @param Sstocklo $sstocklo
     * @param array<string,mixed> $bonEntree
     * @param array<string,mixed> $ligneBonEntree
     * @param LigneOperationEnum $ligneOperationEnum
     * @param float|null $previousQteBonEntree
     * @return void
     * @throws Exception
     */
    public static function updateStockLocal(
        Sstocklo $sstocklo,
        array $bonEntree,
        array $ligneBonEntree,
        LigneOperationEnum $ligneOperationEnum,
        ?float $previousQteBonEntree = null
    ): void {
        if ((int) $bonEntree['BE_NOPR'] === 0) {
            $stockLocal = $sstocklo->find(['SITE' => $bonEntree['SITE'], 'CODE_ART' => $ligneBonEntree['CODE_ART']]);
            $stockLocalQteReap = NumberHelper::toFloat($stockLocal['QTE_REAP']);
            $ligneBonEntreeQteReap = NumberHelper::toFloat($ligneBonEntree['QTE_ENT']);

            match ($ligneOperationEnum) {
                LigneOperationEnum::DELETE => $stockLocal['QTE_REAP'] = $stockLocalQteReap - $ligneBonEntreeQteReap,
                default => $stockLocal['QTE_REAP'] = $stockLocalQteReap + $ligneBonEntreeQteReap - $previousQteBonEntree
            };

            $sstocklo->processAndMerge($stockLocal);
        }
    }

    /**
     * @param Sarticle $sarticle
     * @param array<string,mixed> $bonEntree
     * @param array<string,mixed> $ligneBonEntree
     * @param LigneOperationEnum $ligneOperationEnum
     * @param float|null $previousQteBonEntree
     * @return void
     * @throws Exception
     */
    public static function updateStockArticle(
        Sarticle $sarticle,
        array $bonEntree,
        array $ligneBonEntree,
        LigneOperationEnum $ligneOperationEnum,
        ?float $previousQteBonEntree = null
    ): void {
        if ((int) $bonEntree['BE_NOPR'] === 0) {
            $stockArticle = $sarticle->find(['CODE_ART' => $ligneBonEntree['CODE_ART']]);
            $stockArticleQteReap = NumberHelper::toFloat($stockArticle['QTE_REAP']);
            $ligneBonEntreeQteReap = NumberHelper::toFloat($ligneBonEntree['QTE_ENT']);

            match ($ligneOperationEnum) {
                LigneOperationEnum::DELETE => $stockArticle['QTE_REAP'] = $stockArticleQteReap - $ligneBonEntreeQteReap,
                default => $stockArticle['QTE_REAP'] = $stockArticleQteReap + $ligneBonEntreeQteReap - $previousQteBonEntree
            };

            $sarticle->processAndMerge($stockArticle);
        }
    }



    /**
     * @param array<string,mixed> $stockArticle
     * @param array<string,mixed> $entity
     * @param array<string,mixed> $post
     * @return void
     */
    public function updateLotsCollection(array $stockArticle, array $entity, array $post = []): void
    {
        if (Sql::toBool($stockArticle['TRACABLE'])) {
            $sBentLo = new SbentLo($this->pdo);
            $sBentLo->delete(['NO_BE' => $entity['NO_BE'], 'NO_LIG' => $entity['NO_LIG_BE']]);

            foreach ($post['SBENT_LO'] as $lotBonEntree) {
                $lotBonEntree['NO_BE'] = $entity['NO_BE'];
                $lotBonEntree['NO_LIG'] = $entity['NO_LIG_BE'];
                $lotBonEntree['CODE_ART'] = $entity['CODE_ART'];
                $lotBonEntree['DTE_PEREM'] = $lotBonEntree['DTE_PEREM'] === '' ? '00000000':$lotBonEntree['DTE_PEREM'];
                StringHelper::toFloat($lotBonEntree, ['QTE_LOT']);
                $sBentLo->merge($lotBonEntree);
            }
        }
    }
}
