<?php

namespace Modules\Stock\Controller;

use DateTime;
use Entity\Model\CsDon;
use Entity\Model\Hastutil;
use Entity\Model\SbtEnte;
use Entity\Model\SbtLign;
use Entity\Model\SbtLots;
use Entity\Model\SdsLign;
use Entity\Model\Societe;
use Entity\Model\SSiteSto;
use Exception;
use GuzzleHttp\Psr7\Response;
use Helpers\Ariane\Ariane;
use Helpers\ChampsSupplementaire\ChampSupp;
use Helpers\ExportTo\Outils;
use Helpers\Filter\FiltreAvance\GeneratorCs;
use Helpers\Pagination\PaginatorGestion;
use Helpers\Trad\Trad;
use Modules\Stock\Enum\Operation;
use Modules\Stock\Enum\TypeEnteteEnum;
use Modules\Stock\Helper\GestionFiltreHelper;
use Modules\Stock\Helper\NumberHelper;
use Modules\Stock\MenuContextuel\BonTransfertContextuel;
use Modules\Stock\MenuContextuel\LigneBonTransfertContextuel;
use Modules\Stock\Repository\BonTransfertRepo;
use Modules\Stock\Repository\LigneBonTransfertRepo;
use Modules\Stock\Service\Export\BonTransfertExportService;
use Modules\Stock\Service\Form\BonTransfertFormService;
use Modules\Stock\Service\Form\LigneBonTransfertFormService;
use Modules\Stock\Service\ListManagerService;
use Modules\Stock\Service\ParametrageService;
use Modules\Stock\Service\SoldeManuelService;
use Modules\Stock\Trait\Controller\StockContollerTrait;
use Modules\Stock\Trait\Controller\WebserviceTrait;
use Modules\Stock\Validator\BonTransfertValidator;
use Skeleton\Controller\Controller;

class BonTransfertController extends Controller
{
    use WebserviceTrait;
    use StockContollerTrait;

    /**
     * @throws Exception
     */
    public function gestionAction(): string
    {
        $post = $this->request->getParsedBody();
        $trad = $this->getTranslationService();
        $currentUser = $this->getCurrentUser();
        $listManagerService = new ListManagerService($trad);

        GestionFiltreHelper::initialiseCodeSocieteFiltre($post, 'filter_egal_SE#point#CODE_STE');
        GestionFiltreHelper::initialiseMagasinierFiltre($post, 'filter_egal_SE#point#MAG', $currentUser['CODE']);
        Ariane::generate(0, $trad->t('Gestion'), [], null, $this->router->generateUri('Stock.BonTransfert.gestion'));

        (new PaginatorGestion())->generate(20, 'NO_BT');
        $bonsTransfert = (new BonTransfertRepo($this->pdo))->listBonsTransfert($post);
        $infoPagination = PaginatorGestion::getInfoPagination();

        (new BonTransfertContextuel($this->pdo, $this->router, $trad))->addMenuContextuelToEntities($bonsTransfert);

        $filtreAvance = new GeneratorCs($post, 'SBT_ENTE', 'SE.NO_BT', $this->pdo, $trad);
        $filtreAvance->setFiltre('SE.DTE_CREAT', 'date', $trad->t('Date création'));
        $filtreAvance->setFiltre('SE.DTE_VAL_S', 'date', $trad->t('Date validation sortie'));
        $filtreAvance->setFiltre('SE.DTE_VAL_E', 'date', $trad->t('Date validation entrée'));
        $filtreAvance->setFiltre('SL.CODE_ART', 'liste', $trad->t('Code article'), '', 'Ajax.liste.stockArticles', 'Articles');

        return $this->renderer->render('@Stock/BonTransfert/gestion', [
            'post'             => $post,
            'menuActive'       => 'Stock',
            'bonsTransfert'    => $bonsTransfert,
            'infoPagination'   => $infoPagination,
            'listeFiltreEtat'  => $listManagerService->getEtatsList(),
            'filtreAvance'     => $filtreAvance->getFiltres(),
            'initFiltreAvance' => $filtreAvance->getInit(),
            'socUsrProfil'     => $_SESSION['Session_SocUsrProfil']
        ]);
    }

    /**
     * @throws Exception
     */
    public function ligneAction(): string
    {
        $ssitesto = new SsiteSto($this->pdo);
        $noBt = $this->request->getAttribute('noBt');
        $bonTransfert = (new SbtEnte($this->pdo))->find(['NO_BT' => $noBt]);
        $lignesBonTransfert =  (new LigneBonTransfertRepo($this->pdo))->findAllFromNoBt($noBt);
        $siteStock = $ssitesto->find(['SITE' => $bonTransfert['SITE']], ['DESIGN']);
        $destinataire = $ssitesto->find(['SITE' => $bonTransfert['SITE_DEST']], ['DESIGN']);

        return $this->renderer->render('@Stock/BonTransfert/ligne', [
            'id' => $noBt,
            'bonTransfert' => $bonTransfert,
            'siteStock' => $siteStock,
            'destinataire' => $destinataire,
            'lignesBonTransfert' => $lignesBonTransfert,
        ]);
    }

    public function popupExportAction() : string
    {
        $tables = ['Entête' => 'SBT_ENTE', 'Ligne' => 'SBT_LIGN'];
        $tab = (new BonTransfertExportService($this->pdo, $this->getTranslationService()))->getTab($tables);
        asort($tab);

        return $this->renderer->render('@GlobalApplication/Popup/popupExport', [
            'pathExport' => $this->router->generateUri('Stock.BonTransfert.exporter'),
            'tabObli' => ['SE.NO_BT', 'SL.NO_LIG'],
            'formFilter' => 'filtres_bon_transfert',
            'coloneExport' => $tab,
            'post' => [
                'multiSelectexportFacOBLI1' => 'SE.NO_BT',
                'multiSelectexportFacOBLI2' => 'SL.NO_LIG',
            ],
        ]);
    }

    /**
     * @throws Exception
     */
    public function exporterAction(): Response
    {
        $post = $this->request->getParsedBody();
        $postFilters = !empty($this->request->getParsedBody()['okFilter']) ? $post: [];
        $bonTransfertExportService = new BonTransfertExportService($this->pdo, $this->getTranslationService());

        $arrayMultiSelect = $bonTransfertExportService->getArrayMultiSelect($post);
        $listeCS = $bonTransfertExportService->getListeCS($arrayMultiSelect);

        $bonsTransfert = (new BonTransfertRepo($this->pdo))->listBonsTransfertExport($postFilters, implode(',', $arrayMultiSelect));

        $entete = $bonTransfertExportService->getTableEntete($arrayMultiSelect, $listeCS, 'SBT_ENTE', 'SBT_LIGN');
        $champsDate = $bonTransfertExportService->getChampsParType('DATE');
        $champsBool = $bonTransfertExportService->getChampsParType('BOOL');

        foreach ($bonsTransfert as &$bonTransfert) {
            /** @var array<int,array<string,string>> $listeCS */
            $bonTransfertExportService->addChampsSupplementaireValeur($listeCS, $bonTransfert, 'NO_BT', 'NO_LIG', 'SBT_LIGN');
            $bonTransfertExportService->convertirDates($champsDate, $bonTransfert);
            $bonTransfertExportService->convertirBool($champsBool, $bonTransfert);
        }

        Outils::gestionEmailAsync2(
            'export_BT_'.date('Ymd'),
            $bonsTransfert,
            $this->JWTKEY,
            $this->router,
            $this->getTranslationService(),
            $entete
        );

        return $this->createJsonResponse(['statut' => 'OK']);
    }

    /**
     * @throws Exception
     */
    public function visualiserAction(): string|Response
    {
        $trad = $this->getTranslationService();
        $noBt = $this->request->getAttribute('noBt');

        if (!$bonTransfert = (new SbtEnte($this->pdo))->find(['NO_BT' => $noBt])) {
            return $this->create404Response(Trad::strBuild($trad->t('Le bon de transfert N°@1@ n\'existe pas'), $noBt));
        }

        Ariane::generate(
            1,
            $trad->t('Visualisation de bon de transfert'),
            [],
            null,
            $this->router->generateUri('Stock.BonTransfert.visualiser', ['noBt' => $noBt])
        );

        return $this->renderer->render('@Stock/BonTransfert/visualiser', params: [
            'bonTransfert' => $bonTransfert,
            'initImputations' => $this->request->getQueryParams(),
            'siteStock' => (new SSiteSto($this->pdo))->find(['SITE' => $bonTransfert['SITE']]),
            'utilisateur' => (new Hastutil($this->pdo))->find(['CODE' => $bonTransfert['MAG']]),
            'societe' => (new Societe($this->pdo))->find(['CODE_STE' => $bonTransfert['CODE_STE']]),
            'lignesBonTransfert' => (new LigneBonTransfertRepo($this->pdo))->findAllFromNoBt($noBt),
            'siteStockDestinataire' => (new SSiteSto($this->pdo))->find(['SITE' => $bonTransfert['SITE_DEST']]),
        ]);
    }

    /**
     * @throws Exception
     */
    public function supprimerAction(): Response
    {
        $csDon = new CsDon($this->pdo);
        $sbtEnte = new SbtEnte($this->pdo);
        $sbtLign = new SbtLign($this->pdo);
        $noBt = $this->request->getAttribute('noBt');

        if (!$bonTransfert = $sbtEnte->find(['NO_BT' => $noBt])) {
            return $this->createJsonResponse(['statut' => 'Not found', 'message' => Trad::strBuild($this->getTranslationService()->t('Le bon de transfert N°@1@ n\'existe pas'), $noBt)], 404);
        }

        $lignesBonTransfert = (new LigneBonTransfertRepo($this->pdo))->findAllFromNoBt($noBt);
        $ligneBonTransfertFormService = new LigneBonTransfertFormService($this->pdo);

        $this->pdo->beginTransaction();

        foreach ($lignesBonTransfert as $ligneBonTransfert) {
            $codeEnrSbtLign = ChampSupp::autoCompletCodeEnr($noBt, $ligneBonTransfert['NO_LIG'], 'SBT_LIGN');
            $csDon->delete(['COD_TAB' => 'SBT_LIGN', 'COD_ENR' => $codeEnrSbtLign]);
            $sbtLign->delete(['NO_BT' => $noBt, 'NO_LIG' => $ligneBonTransfert['NO_LIG']]);

            $qteVar = NumberHelper::toFloat($ligneBonTransfert['QTE_TRF']);
            $ligneBonTransfertFormService->updateResteLigneDemandeService($ligneBonTransfert, $qteVar);
            $ligneBonTransfertFormService->updateQteReserveeStockLocal($ligneBonTransfert, $qteVar, $bonTransfert['SITE'], 'CODE_ART');
        }

        $sbtEnte->delete(['NO_BT' => $noBt]);
        (new SbtLots($this->pdo))->delete(['NO_BT' => $noBt]);
        $csDon->delete(['COD_TAB' => 'SBT_ENTE', 'COD_ENR' => ChampSupp::autoCompletCodeEnr($noBt, null, 'SBT_ENTE')]);

        $this->pdo->commit();

        return $this->createJsonResponse(['statut' => 'OK']);
    }

    /**
     * @throws Exception
     */
    public function nouveauFormAction(): string
    {
        $trad = $this->getTranslationService();
        $post = $this->request->getParsedBody();
        [$magasinier, $currentUser, $site, $dest] = $this->getInitDataFromUser($post);
        $parametreNumerotation = (new ParametrageService($this->pdo))->getParametreNumerotation(TypeEnteteEnum::BT, $_SESSION['Session_SocUsrProfil']);

        Ariane::generate(
            1,
            $trad->t('Création de bon de transfert'),
            [],
            null,
            $this->router->generateUri('Stock.BonTransfert.nouveauForm')
        );

        return $this->renderer->render('@Stock/BonTransfert/nouveau_form', [
            'post' => $post,
            'dest' =>  $dest,
            'site' =>  $site,
            'magasinier' => $magasinier,
            'utilisateur' => $currentUser,
            'dateJour' => date("Ymd"),
            'login' => $_SESSION['Session_Login'],
            'parametreNumerotation' => $parametreNumerotation,
            'dateCreation' => (new DateTime('now'))->format('d/m/Y')
        ]);
    }

    /**
     * @throws Exception
     */
    public function nouveauAction(): Response
    {
        $trad = $this->getTranslationService();
        $post = $this->request->getParsedBody();
        $bonTransfert = $post['SBT_ENTE'];
        $validator = new BonTransfertValidator($this->pdo, $trad);
        $siteStock = (new SSiteSto($this->pdo))->find(['SITE' => $post['SBT_ENTE']['SITE']]);
        $parametreNumerotation = (new ParametrageService($this->pdo))->getParametreNumerotation(TypeEnteteEnum::BT, $siteStock['CODE_STE']);

        $validator
            ->validateMag($bonTransfert)
            ->validateSite($bonTransfert)
            ->validateNoDs($bonTransfert)
            ->validateSiteDestinataire($bonTransfert)
            ->validateDateCreation($bonTransfert)
            ->validateLignes($post, 'SBT_LIGNS', $bonTransfert['NO_DS'])
            ->validateNo($bonTransfert, $parametreNumerotation, TypeEnteteEnum::BT, 'bon de transfert')
        ;

        if ($validator->isNonBloquant() && !isset($post['confirm'])) {
            return $this->createNonBloquantJsonErrorResponse('Confirmez-vous la création de ce bon de transfert', $validator->getErrorNonBloquant(), $parametreNumerotation);
        }
        if ($validator->isValid(true)) {
            $bonTransfertFormService = new BonTransfertFormService($this->pdo);
            $bonTransfert = $bonTransfertFormService->initEntity($bonTransfert, ['SITE_STOCK' => $siteStock, 'PARAMETRE_NUMEROTATION' => $parametreNumerotation]);
            $bonTransfertFormService->flushData($bonTransfert, [...$post, 'operation' => Operation::CREATE]);

            return $this->createJsonResponse([
                'statut' => 'OK',
                'redirectRoute' => $this->router->generateUri('Stock.BonTransfert.modifierForm', ['noBt' => $bonTransfert['NO_BT']]),
            ]);
        } else {
            return $this->createBloquantJsonErrorResponse($parametreNumerotation, $validator->getError());
        }
    }

    /**
     * @throws Exception
     */
    public function modifierFormAction(): string|Response
    {
        $trad = $this->getTranslationService();
        $noBt = $this->request->getAttribute('noBt');

        if (!$bonTransfert = (new SbtEnte($this->pdo))->find(['NO_BT' => $noBt])) {
            return $this->create404Response('Ce bon de transfert n\'existe pas');
        }

        Ariane::generate(
            1,
            $trad->t('Modification de bon de transfert'),
            [],
            null,
            $this->router->generateUri('Stock.BonTransfert.modifierForm', ['noBt' => $noBt])
        );

        $menuContextuel = new LigneBonTransfertContextuel($this->pdo, $this->router, $trad);
        $lignesBonTransfert = (new LigneBonTransfertRepo($this->pdo))->findAllFromNoBt($noBt);

        foreach ($lignesBonTransfert as $key => $ligneBonTransfert) {
            $lignesBonTransfert[$key]['DELETE_POPUP'] = $menuContextuel->getDeletePopupConfirm($ligneBonTransfert['NO_BT'], $ligneBonTransfert['NO_LIG']);
        }

        return $this->renderer->render('@Stock/BonTransfert/modifier_form', [
            'bonTransfert' => $bonTransfert,
            'lignesBonTransfert' => $lignesBonTransfert,
            'utilisateur' => (new Hastutil($this->pdo))->find(['CODE' => $bonTransfert['MAG']]),
            'siteStock' => (new SSiteSto($this->pdo))->find(['SITE' => $bonTransfert['SITE']]),
            'societe' => (new Societe($this->pdo))->find(['CODE_STE' => $bonTransfert['CODE_STE']]),
            'siteStockDestinataire' => (new SSiteSto($this->pdo))->find(['SITE' => $bonTransfert['SITE_DEST']]),
        ]);
    }

    /**
     * @throws Exception
     */
    public function modifierAction(): Response
    {
        $sbtEnte = new SbtEnte($this->pdo);
        $trad = $this->getTranslationService();
        $post = $this->request->getParsedBody();
        $noBt = $this->request->getAttribute('noBt');
        $validator = new BonTransfertValidator($this->pdo, $trad);

        if (!$bonTransfert = $sbtEnte->find(['NO_BT' => $noBt])) {
            return $this->createJsonResponse(['message' => Trad::strBuild($trad->t('Le bon de transfert portant le numéro @1@ n\'existe pas'), $noBt)], 404);
        }

        $bonTransfert = array_merge($bonTransfert, $post['SBT_ENTE']);
        $bonTransfert['NO_BT'] = $noBt;
        $siteStock = (new SSiteSto($this->pdo))->find(['SITE' => $bonTransfert['SITE']]);
        $parametreNumerotation = (new ParametrageService($this->pdo))->getParametreNumerotation(TypeEnteteEnum::BT, $siteStock['CODE_STE']);

        $validator
            ->validateSiteDestinataire($bonTransfert)
            ->validateCs('SBT_ENTE', [$bonTransfert['NO_BT'], null], $post)
        ;

        if ($validator->isNonBloquant() && !isset($post['confirm'])) {
            return $this->createNonBloquantJsonErrorResponse('Confirmez-vous la modification de ce bon de transfert', $validator->getErrorNonBloquant(), $parametreNumerotation);
        }
        if ($validator->isValid(true)) {
            (new BonTransfertFormService($this->pdo))->flushData($bonTransfert, $post);

            return $this->createJsonResponse($this->getSuccessDataWithValidation(
                'ST_BT_VAL',
                ['noBt' => $noBt],
                'BonTransfert',
                'Voulez vous valider ce bon de transfert ?',
                $_SESSION['ariane'][0]['path']
            ));
        } else {
            return $this->createBloquantJsonErrorResponse($parametreNumerotation, $validator->getError());
        }
    }

    /**
     * @throws Exception
     */
    public function impressionAction(): string|Response
    {
        $noBt = $this->request->getAttribute('noBt');
        $type = $this->request->getAttribute('type');

        $nonChiffre = null;
        $fileNamePrefix = '';
        $pourExpedition = null;

        if ($type === 'valorisee') {
            $nonChiffre = 'false';
            $pourExpedition = 'false';
            $fileNamePrefix = 'Impression_valorisee_';
        }
        if ($type === 'nonValorisee') {
            $nonChiffre = 'true';
            $pourExpedition = 'false';
            $fileNamePrefix = 'Impression_non_valorisee_';
        }
        if ($type === 'pourExpedition') {
            $pourExpedition = 'true';
            $fileNamePrefix = 'Impression_pour_expedition_';
        }

        $xml = '<BTIn LngUtilisation="'.htmlspecialchars($_SESSION['Session_Langue']).'">
                    <NumeroBT>'.$noBt.'</NumeroBT>
                    <NonChiffre>'.$nonChiffre.'</NonChiffre>
                    <PourExpedition>'.$pourExpedition.'</PourExpedition>
                </BTIn>';

        return $this->webserviceImpressionResponse($xml, 'OXAPRC_IMPRIMEBT', $fileNamePrefix.$noBt);
    }

    /**
     * @throws Exception
     */
    public function etiquetteAction(): string|Response
    {
        $noBt = $this->request->getAttribute('noBt');

        $xml = '<BTIn LngUtilisation="'.htmlspecialchars($_SESSION['Session_Langue']).'">
                    <NumeroBT>'.$noBt.'</NumeroBT>
                    <Utilisateur></Utilisateur>
                </BTIn>';

        return $this->webserviceImpressionResponse($xml, 'OXAPRC_IMPRIME_ETIQ_BT', 'Etiquette_bon_de_transfert_'.$noBt);
    }

    /**
     * @throws Exception
     */
    public function validerAction(): Response
    {
        $sbsEnte = new SbtEnte($this->pdo);
        $noBt = $this->request->getAttribute('noBt');
        $bonTransfert = $sbsEnte->find($noBt);
        $post = $this->request->getParsedBody();
        $confirm = $post['confirm'] ?? false;

        if ($bonTransfert['DTE_VAL_S'] !== '00000000') {
            return $this->createJsonResponse(['statut' => 'Forbidden'], 403);
        }

        $xml = '<BTIn LngUtilisation="'.htmlspecialchars($_SESSION['Session_Langue']).'">
                    <Confirmation>'.$confirm.'</Confirmation>
                    <NumeroBT>'.$noBt.'</NumeroBT>
                </BTIn>';

        return $this->webserviceValidationResponse(
            $xml,
            $confirm,
            'OXAPRC_VALID_BT',
            'Confirmez-vous la validation de ce bon de transfert ?',
            'Ce bon de transfert ne peux pas être validée',
            $_SESSION['ariane'][0]['path'],
            (new SoldeManuelService($this->pdo))->getSoldeAutoCallback($noBt, 'SBT_LIGN'),
        );
    }
}
