<?php

namespace Modules\Reception\Service;

use Entity\Model\BrLigne;
use Entity\Model\SbrLots;
use Helpers\Outil\ArrayHelper;
use Helpers\Outil\Date;
use Helpers\Outil\Sql;
use Helpers\Trad\ITrad;

use Helpers\Trad\Trad;
use Modules\Reception\Repository\CreationBR;
use Modules\Reception\Repository\Lot;
use PDO;
use Skeleton\Renderer\RendererInterface;

class LotService
{
    private PDO $pdo;
    private Lot $repository;
    private CreationBR $repositoryCreation;
    // private Sql $sql;
    private ITrad $trad;

    /**
     * __construct
     *
     * @param  PDO $pdo
     * @param  ITrad $trad
     * @return void
     */
    public function __construct(PDO $pdo, ITrad $trad)
    {
        $this->pdo                = $pdo;
        $this->trad               = $trad;
        $this->repository         = new Lot($this->pdo);
        $this->repositoryCreation = new CreationBR($this->pdo);
        // $this->sql          = new Sql();
    }

    /**
     * initOxaBrLigneLot
     *
     * @param  string $order
     * @return array<mixed>
     */
    public function initOxaBrLigneLot(string $order): array
    {
        // on supprime les données de oxa_br_ligne_lots liées au user connecté
        $this->repository->resetOxaBrLigneLot();

        // on initialise les données de oxa_br_ligne_lots avec les lignes de commande qui attendent une répartition par lots
        $this->repository->initOxaBrLigneLot($order);

        return [];
    }
    
    /**
     * getBatchLines
     *
     * @return array<mixed>
     */
    public function getBatchLines(): array
    {
        $selectedLines = $this->repositoryCreation->getSelectedLines();

        if (!empty($selectedLines)) {
            $batchLines = $this->repository->getBatchLines();
            $batchLines = ArrayHelper::indexBy($batchLines, 'NO_LIG_BR');

            if (!empty($batchLines)) {
                $selectedLinesTmp = [];
                foreach ($selectedLines as $key => $selectedLine) {
                    if (isset($batchLines[$selectedLine['no_ligne_br']])) {
                        $selectedLinesTmp[$key] = $selectedLine;
                        $selectedLinesTmp[$key]['LOTS'] = $batchLines[$selectedLine['no_ligne_br']];
                        // on récupère la somme des quantités réparties pour calculer le reste à répartir
                        $sum = 0;
                        $decimal = 1;
                        foreach ($batchLines[$selectedLine['no_ligne_br']] as $batchLine) {
                            $batchLine = (array)$batchLine;
                            $sum += floatval($batchLine['QTE_LOT']??'');
                            $decimal = $batchLine['NB_DECIM'] ?? '';
                        }
                        $selectedLinesTmp[$key]['resteARepartir'] = floatval($selectedLinesTmp[$key]['qte_a']) - $sum;
                        $selectedLinesTmp[$key]['NB_DECIM'] = $decimal;
                    }
                }

                return $selectedLinesTmp;
            }
        }

        return [];
    }

    public function addBatch(string $line): bool
    {
        // on vérifie qu'il n'y a pas déjà une ligne de lot avec NO_LOT = '' (en création)
        $check = $this->repository->getBatchLines($line);

        foreach ($check as $batch) {
            if (isset($batch['NO_LOT']) && $batch['NO_LOT'] == '0') {
                return false;
            }
        }

        return $this->repository->addBatch($line);
    }

    /**
     * updateBatch
     *
     * @param  string $line
     * @param  string $field
     * @param  string $batch
     * @param  string $value
     * @return mixed
     */
    public function updateBatch(string $line, string $field, string $batch, string $value)
    {
        // si le numéro de lot sélectionné existe déjà dans la table des lots globale on désactive la modification de la table de péremption
        $disabledExpirationDate = false;

        if ($field == 'NO_LOT') {
            // on vérifie que le lot n'existe pas déjà ou n'est pas périmé et SLOTGLOB.QTE_REST > 0
            $restrictedBatch = $this->repository->getRestrictedBatch($value);
            if (!empty($restrictedBatch)) {
                return $this->trad->t('Ce numéro de lot existe déjà et n\'est pas disponible pour cet article.');
            }

            $existingBatch = $this->repository->listeLots(['filter_egal_NO_LOT' => $value]);

            $this->repository->updateOxaBrLot($line, $batch, $field, $value);

            $batch = $value;

            // si le lot existe déjà et est disponible, on met aussi à jour la date de péremption
            if (!empty($existingBatch)) {
                $this->repository->updateOxaBrLot($line, $batch, 'DTE_PEREM', $existingBatch[0]['DTE_PEREM']);
                $disabledExpirationDate = true;
            }
        } else {
            $this->repository->updateOxaBrLot($line, $batch, $field, $value);
        }

        $oxaBrBatch = $this->repository->getOxaBrLigneLot($line, $batch);
        $toBeDistributed = $this->repository->getStillToBeDistributed($line, '');

        return [
            'batch'                     => $oxaBrBatch,
            'disabledExpirationDate'    => $disabledExpirationDate,
            'toBeDistributed'           => $toBeDistributed
        ];
    }

    /**
     * saveBatchDistribution
     *
     * @param  int $brNumber
     * @param  string $type
     * @return string|bool
     */
    public function saveBatchDistribution(int $brNumber, string $type = 'R')
    {
        // on commence par s'assurer que la quantité reçue et la quantité répartie sont les mêmes
        $batchLines = $this->repository->getBatchLines();
        $receivedLines = $this->repositoryCreation->getOxaBrLigne($_SESSION['Session_Login']);
        $distributedQuantity = [];
        $receivedQuantity = [];
        $error = '';

        if ($type == 'R') {
            $this->saveBatchDistributionReception($receivedLines, $receivedQuantity, $batchLines, $distributedQuantity, $error);
        } else {
            $this->saveBatchDistributionReturn($receivedLines, $receivedQuantity, $batchLines, $distributedQuantity, $error);
        }

        // on enregistre sur BR_LIGNE.QTEREPLO la quantité répartie en lots
        $this->repositoryCreation->updateBrLigneQteRep($brNumber, $type);
        // puis on enregistre dans SBR_LOTS la répartition
        $this->repository->saveBatch($brNumber);

        return true;
    }
    
    /**
     * checkDistributionForValidation
     *
     * @param  array<mixed> $lines
     * @return string
     */
    public function checkDistributionForValidation(array $lines)
    {
        // on vérifie que la répartition correspond à la quantité acceptée/retournée si répartition par lots
        $error = '';
        $batchedQuantities = array();

        foreach ($lines as $line) {
            if (isset($line['batchReturn'])) {
                foreach ($line['batchReturn'] as $batch) {
                    $batchedQuantities[$batch['NO_LIG_BR']] = (float)($batchedQuantities[$batch['NO_LIG_BR']] ?? 0) + (float)$batch['QTE_LOT_RETOUR'];
                }

                if ($line['QTE_ANNULE'] != $batchedQuantities[$line['no_ligne_br']]) {
                    $error .= Trad::strBuild(
                        $this->trad->t('Ligne @1@ : La quantité retournée est différente de la quantité répartie par lots.'),
                        $line['no_ligne_br']
                    ) . '</br>';
                }
                // TODO à tester quand gitlab de retour
            } elseif (isset($line['LOTS'])) {
                foreach ($line['LOTS'] as $batch) {
                    if ($line['resteARepartir'] > 0) {
                        $error .= Trad::strBuild(
                            $this->trad->t('Ligne @1@ : La quantité acceptée est différente de la quantité répartie par lots.'),
                            $line['no_ligne_br']
                        ) . '</br>';
                    }
                }
            }
        }

        return $error;
    }
    
    /**
     * saveBatchDistributionReception
     *
     * @param  array<mixed> $receivedLines
     * @param  array<mixed> $receivedQuantity
     * @param  array<mixed> $batchLines
     * @param  array<mixed> $distributedQuantity
     * @param  string $error
     * @return void
     */
    public function saveBatchDistributionReception($receivedLines, $receivedQuantity, $batchLines, $distributedQuantity, &$error): void
    {
        foreach ($receivedLines as $receivedLine) {
            if (Sql::toBool($receivedLine['is_reception'])) {
                if (isset($receivedQuantity[$receivedLine['no_ligne_cde']])) {
                    $receivedQuantity[$receivedLine['no_ligne_cde']] += $receivedLine['qte_a'];
                } else {
                    $receivedQuantity[$receivedLine['no_ligne_cde']] = $receivedLine['qte_a'];
                }
            }
        }
        foreach ($batchLines as $batch) {
            if (isset($distributedQuantity[$batch['NO_LIG_BR']])) {
                $distributedQuantity[$batch['NO_LIG_BR']] += $batch['QTE_LOT'];
            } else {
                $distributedQuantity[$batch['NO_LIG_BR']] = $batch['QTE_LOT'];
            }
        }

        foreach ($receivedQuantity as $key => $value) {
            if ($distributedQuantity[$key] < $value) {
                $error = $this->trad->t('La quantité saisie sur le lot est inférieure à la quantité reçue sur le bon.');
            }
        }
    }
    
    /**
     * saveBatchDistributionReception
     *
     * @param  array<mixed> $receivedLines
     * @param  array<mixed> $receivedQuantity
     * @param  array<mixed> $batchLines
     * @param  array<mixed> $distributedQuantity
     * @param  string $error
     * @return void
     */
    public function saveBatchDistributionReturn($receivedLines, $receivedQuantity, $batchLines, $distributedQuantity, &$error): void
    {
        foreach ($receivedLines as $receivedLine) {
            if ($receivedLine['IS_ANNULE'] === '1') {
                if (isset($receivedQuantity[$receivedLine['no_ligne_cde']])) {
                    $receivedQuantity[$receivedLine['no_ligne_cde']] += $receivedLine['QTE_ANNULE'];
                } else {
                    $receivedQuantity[$receivedLine['no_ligne_cde']] = $receivedLine['QTE_ANNULE'];
                }
            }
        }
        foreach ($batchLines as $batch) {
            if (isset($distributedQuantity[$batch['NO_LIG_BR']])) {
                $distributedQuantity[$batch['NO_LIG_BR']] += $batch['QTE_LOT'];
            } else {
                $distributedQuantity[$batch['NO_LIG_BR']] = $batch['QTE_LOT'];
            }
        }

        foreach ($receivedQuantity as $key => $value) {
            if ($distributedQuantity[$key] < $value) {
                $error = $this->trad->t('La quantité saisie sur le lot est inférieure à la quantité retournée sur le bon.');
            }
        }
    }
    
    /**
     * getBatchReturn
     *
     * @param  string $brNumber
     * @param  array<mixed> $linesReturn
     * @return array<mixed>
     */
    public function getBatchReturn(string $brNumber, array &$linesReturn, string $mode = 'C'): array
    {
        // on commence par récupérer les lignes avec les taux de conversion unité achat vers unité stock pour exprimer les quantités en unités de la ligne de commande
        if ($mode == 'C') {
            $batchLines = $this->repository->getBatchLinesForReturn($brNumber);
        // si on est en modification de bon de retour, les lignes de lots ne sont pas à récupérer sur le numéro de BR modifié mais sur la numéro du BR annulé
        } else {
            $intialBrNumber = $this->repositoryCreation->getInfoBrEntete($_SESSION['Session_Login'])['NUM_BR_ANNULE'];
            $batchLines = $this->repository->getBatchLinesForReturn($intialBrNumber);
        }

        foreach ($linesReturn as $line) {
            $linesReturntmp[$line['no_ligne_br']] = $line;
        }

        $linesReturn = $linesReturntmp ?? $linesReturn;

        foreach ($batchLines as &$line) {
            $line['QTE_DISPO'] = ($line['QTE_LOC'] - $line['QTE_INDIS'] - $line['QTE_TRF']) / floatval($line['CONVER'] != '0' ? $line['CONVER'] : 1) / floatval($line['CONV_ART_1_2']) / floatval($line['CONVERS_1_2']);
            $linesReturn[$line['NO_LIG_BR']]['batchReturn'][$line['NO_LOT']] = $line;
        }
        
        return $linesReturn;
    }

    public function updateBatchReturn(string $brNumber, string $line, string $batch, string $field, string $value): bool
    {
        if ($field == 'selected') {
            if ($value == 'true') {
                return $this->repository->insertBatchReturn($brNumber, $line, $batch);
            } else {
                return $this->repository->deleteBatchReturn($line, $batch);
            }
        } else {
            return $this->repository->updateBatchReturn($line, $batch, 'QTE_LOT', $value);
        }
    }


    public function initOxaBrLigneLotModif(string $brNumber, string $order): void
    {
        // on commence par initialiser les lignes de oxa_br_ligne_lots à partir de la commande du numéro de BR en modif
        $this->initOxaBrLigneLot($order);

        // on vérifie ensuite s'il y a déjà des données enregistrées dans SBR_LOTS pour le BR en cours de modif
        $sbrLots = new SbrLots($this->pdo);
        $existingBatchLines = $sbrLots->fetchAll([], ['filter_egal_NO_BR' => $brNumber], 2);

        // if (!empty($existingBatchLines)) {
        //     $this->repository->deleteBatchReturn();
        //     $this->repository->initOxaBrLigneLotRetour($brNumber);
        // }
    }
    
    /**
     * removeBatch
     *
     * @param  string $line
     * @param  string $batch
     * @return array<mixed>
     */
    public function removeBatch(string $line, string $batch): array
    {
        // s'il s'agit du seul lot de la ligne, on le remet seulement à zéro
        if (count($this->repository->getBatchLines($line)) < 2) {
            $this->repository->updateOxaBrLot($line, $batch, 'QTE_LOT', '0');
            $this->repository->updateOxaBrLot($line, $batch, 'DTE_PEREM', '00000000');
            $this->repository->updateOxaBrLot($line, $batch, 'NO_LOT', '0');
            $onlyOneBatch = true;
        } else {
            $this->repository->removeBatch($line, $batch);
            $onlyOneBatch = false;
        }

        $oxaBrBatch = $this->repository->getOxaBrLigneLot($line, $batch);
        $toBeDistributed = $this->repository->getStillToBeDistributed($line, '');

        return [
            'batch'             => $oxaBrBatch,
            'toBeDistributed'   => $toBeDistributed,
            'onlyOneBatch'      => $onlyOneBatch
        ];
    }
}
