<?php

namespace Modules\Stock\Controller;

use Entity\Model\Articles;
use Entity\Model\Codecomp;
use Entity\Model\Docatt;
use Entity\Model\Paravrac;
use Entity\Model\Sarticle;
use Entity\Model\Sectimpu;
use Entity\Model\Societe;
use Entity\Model\Sscptana;
use Entity\Model\SSiteSto;
use Entity\Model\Sstocklo;
use Exception;
use GuzzleHttp\Psr7\Response;
use Helpers\Ariane\Ariane;
use Helpers\ChampsSupplementaire\ChampSupp;
use Helpers\ExportTo\Outils;
use Helpers\Filter\FiltreAvance\Generator;
use Helpers\Outil\Roles;
use Helpers\Outil\Sql;
use Helpers\Pagination\PaginatorGestion;
use Modules\Stock\Enum\TypeEnteteEnum;
use Modules\Stock\Helper\RulesHelper;
use Modules\Stock\Helper\GestionFiltreHelper;
use Modules\Stock\MenuContextuel\StockLocalContextuel;
use Modules\Stock\Repository\MouvementRepo;
use Modules\Stock\Repository\StockLocalRepo;
use Modules\Stock\Service\CsInitializerService;
use Modules\Stock\Service\Export\StockLocalExportService;
use Modules\Stock\Service\ListManagerService;
use Modules\Stock\Trait\Controller\StockContollerTrait;
use Modules\Stock\Trait\Controller\WebserviceTrait;
use Modules\Stock\Validator\StockLocalValidator;
use Skeleton\Controller\Controller;

class StockLocalController extends Controller
{
    use WebserviceTrait;
    use StockContollerTrait;

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

        if (Sql::toBool($currentUser['FILT_SIT'])) {
            GestionFiltreHelper::initialiseSiteStockFiltre($post, 'filter_egal_STO#point#SITE', $currentUser['SIT_STO']);
        }

        Ariane::generate(
            $post['niveau'] ?? 0,
            $trad->t($post['ariane_title'] ?? 'Gestion'),
            [],
            null,
            $this->router->generateUri('Stock.StockLocal.gestion')
        );

        (new PaginatorGestion())->generate(20, 'CODE_ART');
        $stockLocaux = (new StockLocalRepo($this->pdo))->listStocksLocaux($post);
        $infoPagination = PaginatorGestion::getInfoPagination();

        (new StockLocalContextuel($this->pdo, $this->router, $trad))->addMenuContextuelToEntities($stockLocaux);

        $filtreAvance = new Generator($post);
        $filtreAvance->setFiltre('STO.QTE_PHYS', 'numeric', $trad->t('Quantité physique'));
        $filtreAvance->setFiltre('STO.QTE_RES', 'numeric', $trad->t('Quantité réservée'));
        $filtreAvance->setFiltre('STO.QTE_INDIS', 'numeric', $trad->t('Quantité indisponible'));
        $filtreAvance->setFiltre('S.QTE_DISPO', 'numeric', $trad->t('Quantité disponible'));

        return $this->renderer->render('@Stock/StockLocal/gestion', [
            'post'                  => $post,
            'menuActive'            => 'Stock',
            'stockLocaux'           => array_map(
                fn($item) => $item + [
                    'idDoc' => Docatt::getCodeEnr('SSTOCKLO', $item),
                ],
                $stockLocaux
            ),
            'infoPagination'        => $infoPagination,
            'initFiltreAvance'      => $filtreAvance->getInit(),
            'filtreAvance'          => $filtreAvance->getFiltres(),
            'hasCreateAccessRights' => (bool) Roles::droitsUtilisateur($this->pdo, 'ST_STL_CRE')
        ]);
    }

    /**
     * @throws Exception
     */
    public function visualiserAction(): string|Response
    {
        $trad = $this->getTranslationService();
        $post = $this->request->getParsedBody();
        $mouvementRepo = new MouvementRepo($this->pdo);
        $site = $this->request->getAttribute('site');
        $codeArt = $this->request->getAttribute('codeArt');

        if (!$stockLocal = (new Sstocklo($this->pdo))->find(['CODE_ART' => $codeArt, 'SITE' => $site])) {
            return $this->create404Response('Cet article de stock n\'existe pas');
        }

        Ariane::generate(
            array_key_exists('ariane', $post) ? (int) $post['ariane'] : 1,
            $trad->t('Visualisation du stock local'),
            [],
            null,
            $this->router->generateUri('Stock.StockLocal.stock')
        );

        $stockArticle = (new Sarticle($this->pdo))->find(['CODE_ART' => $codeArt]);
        $stockArticle['STRATEG'] = Sql::toBool($stockArticle['STRATEG']);

        return $this->renderer->render('@Stock/StockLocal/visualiser', [
            'menuActive' => 'Stock',
            'stockArticle' => $stockArticle,
            'stockLocal' => $stockLocal,
            'siteStock' => (new SSiteSto($this->pdo))->find(['SITE' => $site]),
            'article' => (new Articles($this->pdo))->find(['CODE_ART' => $codeArt]),
            'hasSmouvemeAccessRights' => RulesHelper::hasMouvementAccessRights($this->pdo),
            'listeTypeReappro' => (new ListManagerService($trad))->getChoixTypeReapproList(),
            'societe' => (new Societe($this->pdo))->find(['CODE_STE' => $stockLocal['CODE_STE']]),
            'sectionImputation' => (new Sectimpu($this->pdo))->find(['CODE_SI' => $stockLocal['STKLO_SI']]),
            'codeComplementaire' => (new Codecomp($this->pdo))->find(['CODE_CDC' => $stockLocal['STKLO_CDC']]),
            'sousCompteAnalyse' => (new Sscptana($this->pdo))->find(['CODE_SCA' => $stockLocal['STKLO_SCA']]),
            'configAxeImp' => (new Paravrac($this->pdo))->getCommandeAxeImpConfig($stockLocal['CODE_STE']),
            'dernierEntreeData' => $mouvementRepo->getLastMouvement(TypeEnteteEnum::BE, TypeEnteteEnum::BR, $codeArt, $site),
            'dernierSortieData' => $mouvementRepo->getLastMouvement(TypeEnteteEnum::BS, TypeEnteteEnum::BT, $codeArt, $site),
        ]);
    }

    /**
     * @throws Exception
     */
    public function nouveauFormAction(): string
    {
        $trad = $this->getTranslationService();
        $post = $this->request->getParsedBody();
        $niveau = $post['niveau'] ?? 1;

        Ariane::generate(
            $niveau,
            $trad->t('Ajouter un article'),
            [],
            null,
            $this->router->generateUri('Stock.StockLocal.nouveauForm')
        );

        $codeEnr = '';
        if ($post['SSTOCKLO']['CODE_ART'] && $post['SSTOCKLO']['SITE']) {
            $codeEnr = $post['SSTOCKLO']['SITE'] . $post['SSTOCKLO']['CODE_ART'];
            (new CsInitializerService($this->pdo))->initializeCs($post, 'SSTOCKLO', $codeEnr, [
                ['SARTICLE', $post['SSTOCKLO']['CODE_ART']],
            ]);
        }

        return $this->renderer->render('@Stock/StockLocal/nouveau_form', [
            'post' => $post,
            'codeEnr' => $codeEnr,
            'menuActive' => 'Stock',
            'dateJour' => date("Ymd"),
            'previousPath' => $_SESSION['ariane'][$niveau - 1]['path'],
            'configAxeImp' => (new Paravrac($this->pdo))->getCommandeAxeImpConfig(),
            'listeTypeReappro' => (new ListManagerService($trad))->getChoixTypeReapproList()
        ]);
    }

    /**
     * @throws Exception
     */
    public function nouveauAction(): Response
    {
        $trad = $this->getTranslationService();
        $post = $this->request->getParsedBody();
        $validator = new StockLocalValidator($this->pdo, $trad);

        $stockLocal = $post['SSTOCKLO'];
        $siteStock = (new SSiteSto($this->pdo))->find(['SITE' => $stockLocal['SITE']]);

        $validator
            ->validateSite($stockLocal)
            ->validateEmplac($stockLocal)
            ->validateCodeArt($stockLocal)
            ->validatePerioInv($stockLocal)
            ->validateDteInv($stockLocal)
            ->validateDteFerm($stockLocal)
            ->validateDelaiAppro($stockLocal)
            ->validateConsoPrevue($stockLocal)
            ->validateQteEconomique($stockLocal)
            ->validateStockProtection($stockLocal)
            ->validateQteMaxiStockable($stockLocal)
            ->validateSectimp($stockLocal, null, $siteStock['CODE_STE'])
            ->validateCodeComp($stockLocal, null, $siteStock['CODE_STE'])
            ->validateSscpteana($stockLocal, null, $siteStock['CODE_STE'])
            ->validatorCS('SSTOCKLO', $stockLocal['SITE'] . $stockLocal['CODE_ART'], $post, $this->pdo)
        ;

        if ($validator->isValid(true)) {
            $stockLocal['CODE_STE'] = $siteStock['CODE_STE'];

            $this->pdo->beginTransaction();
            (new Sstocklo($this->pdo))->processAndMerge($stockLocal);
            ChampSupp::updateCS($post, $this->pdo);
            $this->pdo->commit();

            return $this->createJsonResponse(['redirectRoute' => $post['previous_path']]);
        } else {
            return $this->createBloquantJsonErrorResponse([], $validator->getError());
        }
    }

    /**
     * @throws Exception
     */
    public function modifierFormAction(): string|Response
    {
        $mouvementRepo = new MouvementRepo($this->pdo);
        $site = $this->request->getAttribute('site');
        $codeArt = $this->request->getAttribute('codeArt');

        if (!$stockLocal = (new Sstocklo($this->pdo))->find(['CODE_ART' => $codeArt, 'SITE' => $site])) {
            return $this->create404Response('Cet article de stock n\'existe pas');
        }

        Ariane::generate(
            1,
            $this->getTranslationService()->t('Modifier stock local'),
            [],
            null,
            $this->router->generateUri('Stock.StockLocal.modifierForm')
        );

        $stockArticle = (new Sarticle($this->pdo))->find(['CODE_ART' => $stockLocal['CODE_ART']]);

        return $this->renderer->render('@Stock/StockLocal/modifier_form', [
            'menuActive' => 'Stock',
            'stockLocal' => $stockLocal,
            'stockArticle' => $stockArticle,
            'isTracable' => Sql::toBool($stockArticle['TRACABLE']),
            'codeEnr' => $stockLocal['SITE'] . $stockLocal['CODE_ART'],
            'siteStock' => (new Ssitesto($this->pdo))->find(['SITE' => $site]),
            'articleEntity' => (new Articles($this->pdo))->find(['CODE_ART' => $codeArt]),
            'configAxeImp' => (new Paravrac($this->pdo))->getCommandeAxeImpConfig($stockLocal['CODE_STE']),
            'listeTypeReappro' => (new ListManagerService($this->getTranslationService()))->getChoixTypeReapproList(),
            'devise' => (new SSiteSto($this->pdo))->find(['SITE' => $stockLocal['SITE']], ['DEVISE'])['DEVISE'],
            'dernierEntreeData' => $mouvementRepo->getLastMouvement(TypeEnteteEnum::BE, TypeEnteteEnum::BR, $codeArt, $site),
            'dernierSortieData' => $mouvementRepo->getLastMouvement(TypeEnteteEnum::BS, TypeEnteteEnum::BT, $codeArt, $site),
        ]);
    }

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

        if (!$stockLocal = (new Sstocklo($this->pdo))->find(['CODE_ART' => $codeArt, 'SITE' => $site])) {
            return $this->create404Response('Cet article de stock n\'existe pas');
        }

        $stockLocal = array_merge($stockLocal, $post['SSTOCKLO']);

        $validator
            ->validateEmplac($stockLocal)
            ->validatePerioInv($stockLocal)
            ->validateDteInv($stockLocal)
            ->validateDteFerm($stockLocal)
            ->validateDelaiAppro($stockLocal)
            ->validateConsoPrevue($stockLocal)
            ->validateQteEconomique($stockLocal)
            ->validateStockProtection($stockLocal)
            ->validateQteMaxiStockable($stockLocal)
            ->validateSectimp($stockLocal, null, $stockLocal['CODE_STE'])
            ->validateCodeComp($stockLocal, null, $stockLocal['CODE_STE'])
            ->validateSscpteana($stockLocal, null, $stockLocal['CODE_STE'])
            ->validatorCS('SSTOCKLO', $stockLocal['SITE'] . $stockLocal['CODE_ART'], $post, $this->pdo);

        if ($validator->isValid(true)) {
            $this->pdo->beginTransaction();
            (new Sstocklo($this->pdo))->processAndMerge($stockLocal);
            ChampSupp::updateCS($post, $this->pdo);
            $this->pdo->commit();

            return $this->createJsonResponse(['redirectRoute' => $this->router->generateUri('Stock.StockLocal.gestion')]);
        } else {
            return $this->createBloquantJsonErrorResponse([], $validator->getError());
        }
    }

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

        return $this->renderer->render('@GlobalApplication/Popup/popupExport', [
            'pathExport' => $this->router->generateUri('Stock.StockLocal.exporter'),
            'tabObli' => ['STO.SITE', 'STO.CODE_ART'],
            'formFilter' => 'filtres_stock_local',
            'coloneExport' => $tab,
            'post' => [
                'multiSelectexportFacOBLI1' => 'STO.SITE',
                'multiSelectexportFacOBLI2' => 'STO.CODE_ART',
            ],
        ]);
    }

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

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

        $stockLocaux = (new StockLocalRepo($this->pdo))->listeStocksLocauxExport($postFilters, implode(',', $arrayMultiSelect));

        $entete = $stockLocalExportService->getTableEntete($arrayMultiSelect, $listeCS, 'SSTOCKLO');
        $champsDate = $stockLocalExportService->getChampsParType('DATE');
        $champsBool = $stockLocalExportService->getChampsParType('BOOL');

        foreach ($stockLocaux as &$stockLocal) {
            /** @var array<int,array<string,string>> $listeCS */
            $stockLocal['COD_ENR'] = $stockLocal['SITE'] . $stockLocal['CODE_ART'];
            $stockLocalExportService->addChampsSupplementaireValeur($listeCS, $stockLocal, 'COD_ENR');
            unset($stockLocal['COD_ENR']);
            $stockLocalExportService->convertirDates($champsDate, $stockLocal);
            $stockLocalExportService->convertirBool($champsBool, $stockLocal);
        }

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

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

    /**
     * @throws Exception
     */
    public function ligneAction(): string
    {
        $site = $this->request->getAttribute('site');
        $codeArt = $this->request->getAttribute('codeArt');
        $stockLocal = (new StockLocalRepo($this->pdo))->findStockLocal($codeArt, $site);

        return $this->renderer->render('@Stock/StockLocal/ligne', [
            'stockLocal' => $stockLocal,
            'devise' => (new SSiteSto($this->pdo))->find(['SITE' => $site])['DEVISE']
        ]);
    }

    /**
     * @throws Exception
     */
    public function getInformationAction() :Response
    {
        $sStocklo = new Sstocklo($this->pdo);
        $post = $this->request->getParsedBody();
        $stockloRepo = new StockLocalRepo($this->pdo);

        if (!$sStocklo->find(['SITE' => $post['site'], 'CODE_ART' => $post['codeArt']])) {
            return $this->create404Response($this->getTranslationService()->t('Le stock local n\'existe pas'));
        }

        $stockLocal = $stockloRepo->findFromId($post['site'], $post['codeArt']);
        $stockLocal['GLOBAL'] = $stockloRepo->findGlobal($post['codeArt']);

        return $this->createJsonResponse($stockLocal);
    }


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

        if (!(new Sstocklo($this->pdo))->find(['SITE' => $site, 'CODE_ART' => $codeArt])) {
            return $this->create404Response($this->getTranslationService()->t('Le stock local n\'existe pas'));
        }

        $xml = '<EtiqSTLIn LngUtilisation="'.htmlspecialchars($_SESSION['Session_Langue']).'"> 
                    <CodeSite>'.$site.'</CodeSite>
                    <CodeArticleMin>'.$codeArt.'</CodeArticleMin>
                    <CodeArticleMax>'.$codeArt.'</CodeArticleMax>
                </EtiqSTLIn>';

        return $this->webserviceImpressionResponse($xml, 'OXAPRC_IMPRIME_ETIQ_STL', 'Etiquette_stock_local_'.$site.'_'.$codeArt);
    }
}
