<?php

namespace Modules\Stock\Service\Form;

use Entity\Model\Sarticle;
use Entity\Model\Sindispo;
use Entity\Model\Slotglob;
use Entity\Model\Slotindi;
use Entity\Model\Slotloc;
use Entity\Model\Snoreser;
use Entity\Model\Sstocklo;
use Exception;
use Helpers\Outil\Sql;
use Modules\Stock\Helper\NumberHelper;
use Modules\Stock\Interface\FormServiceInterface;
use Modules\Stock\Interface\TracableStockArticleInterface;
use Modules\Stock\Repository\IndisponibiliteRepo;
use Modules\Stock\Trait\FormTrait;
use PDO;

class IndisponibiliteFormService implements FormServiceInterface, TracableStockArticleInterface
{
    use FormTrait;

    public function __construct(private readonly PDO $pdo, private readonly bool $isRemise = false)
    {
    }

    /**
     * @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['QTE_REST'] = $post['QTE'];
        $post['DTE_MISE'] = date('Ymd');
        $post['NO_INDISP'] = (new IndisponibiliteRepo($this->pdo))->getAutomatiqueNo($data['PARAMETRAGE_NUMEROTATION']);

        return $post;
    }

    /**
     * @throws Exception
     * @param array<string,mixed> $entity
     */
    public function flushData(array $entity, array $post = []): void
    {
        $this->pdo->beginTransaction();

        (new Sindispo($this->pdo))->merge($entity);
        (new Sstocklo($this->pdo))->processAndMerge($post['STOCK_LOCAL']);
        (new Sarticle($this->pdo))->processAndMerge($post['STOCK_ARTICLE']);
        (new Snoreser($this->pdo))->delete(['NO_INDIS' => $entity['NO_INDISP']]);
        $this->updateLotsCollection($post['STOCK_ARTICLE'], $entity, $post);

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

    /**
     * @param array<string,mixed> $indisponibilite
     * @return array<string,mixed>
     * @throws Exception
     */
    public function getStockLocalUpdated(array $indisponibilite, bool $isMiseEnIndisponibilite = true, string|int|null $qteRem = null): array
    {
        $stockLocal = (new Sstocklo($this->pdo))->find(['SITE' => $indisponibilite['SITE'], 'CODE_ART' => $indisponibilite['ART']]);
        $isMiseEnIndisponibilite ? $stockLocal['QTE_INDIS'] += $indisponibilite['QTE']: $stockLocal['QTE_INDIS'] -= $qteRem;

        return $stockLocal;
    }

    /**
     * @param array<string,mixed> $indisponibilite
     * @return array<string,mixed>
     * @throws Exception
     */
    public function getStockArticleUpdated(array $indisponibilite, bool $isMiseEnIndisponibilite = true, string|int|null $qteRem = null): array
    {
        $stockArticle = (new Sarticle($this->pdo))->find(['CODE_ART' => $indisponibilite['ART']]);
        $isMiseEnIndisponibilite ? $stockArticle['QTE_INDIS'] += $indisponibilite['QTE']: $stockArticle['QTE_INDIS'] -= $qteRem;

        return $stockArticle;
    }

    /**
     * @param array<string,mixed> $stockArticle
     * @param array<string,mixed> $entity indisponibilité
     * @param array<string,mixed> $post
     * @return void
     * @throws Exception
     */
    public function updateLotsCollection(array $stockArticle, array $entity, array $post = []): void
    {
        if (Sql::toBool($stockArticle['TRACABLE'])) {
            $slotloc = new Slotloc($this->pdo);
            $slotindi = new Slotindi($this->pdo);
            $slotglob = new Slotglob($this->pdo);

            $slotindi->delete(['NO_INDISP' => $entity['NO_INDISP']]);

            foreach ($post['SLOTINDI'] as $lotIndisponible) {
                $lotIndisponible['NO_INDISP'] = $entity['NO_INDISP'];
                $lotIndisponible['CODE_ART'] = $entity['ART'];

                $lotGlobal = $slotglob->find(['NO_LOT' => $lotIndisponible['NO_LOT'], 'CODE_ART' => $entity['ART']]);
                $lotLocal = $slotloc->find(['NO_LOT' => $lotIndisponible['NO_LOT'], 'SITE' => $post['STOCK_LOCAL']['SITE'], 'CODE_ART' => $entity['ART']]);

                $this->updateLotQteIndis($lotLocal, $lotIndisponible);
                $this->updateLotQteIndis($lotGlobal, $lotIndisponible);

                if (!$this->isRemise) {
                    $lotIndisponible['RESTE'] = $lotIndisponible['QTE_INDIS'];
                } else {
                    unset($lotIndisponible['QTE_REM']);
                }

                $slotloc->merge($lotLocal);
                $slotglob->merge($lotGlobal);
                $slotindi->merge($lotIndisponible);
            }
        }
    }


    /**
     * @param array<string,mixed> $lotEntity lot local ou lot global
     * @param array<string,mixed> $lotIndisponible
     * @return void
     */
    private function updateLotQteIndis(array &$lotEntity, array $lotIndisponible): void
    {
        if (!$this->isRemise) {
            $lotEntity['QTE_INDIS'] += NumberHelper::toFloat($lotIndisponible['QTE_INDIS']);
        } else {
            $lotEntity['QTE_INDIS'] -= NumberHelper::toFloat($lotIndisponible['QTE_REM']);
        }
    }
}
