<?php

namespace Modules\Stock\Controller;

use Entity\Model\Articles;
use Entity\Model\Memos;
use Entity\Model\Sarticle;
use Entity\Model\Societe;
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\Ajax\Repository\Listes;
use Modules\Stock\Helper\SwitchDataHelper;
use Modules\Stock\MenuContextuel\StockArticleContextuel;
use Modules\Stock\Repository\StockArticleRepo;
use Modules\Stock\Repository\MouvementRepo;
use Modules\Stock\Repository\StockLocalRepo;
use Modules\Stock\Repository\StockGlobalSocieteRepo;
use Modules\Stock\Service\Export\StockArticleExportService;
use Modules\Stock\Service\Form\StockArticleFormService;
use Modules\Stock\Service\ListManagerService;
use Modules\Stock\Trait\Controller\StockArticleControllerTrait;
use Modules\Stock\Validator\StockArticleValidator;
use Skeleton\Controller\Controller;

class StockArticleController extends Controller
{
    use StockArticleControllerTrait;

    /**
     * @throws Exception
     */
    public function gestionAction(): string
    {
        $post = $this->request->getParsedBody();
        $trad = $this->getTranslationService();
        $listManagerService = new ListManagerService($this->getTranslationService());
        Ariane::generate(0, $trad->t('Gestion'), [], null, $this->router->generateUri('Stock.StockArticle.gestion'));

        (new PaginatorGestion())->generate(20, 'CODE_ART');
        $stockArticles = (new StockArticleRepo($this->pdo))->listStocksArticles($post);
        $infoPagination = PaginatorGestion::getInfoPagination();

        (new StockArticleContextuel($this->pdo, $this->router, $trad))->addMenuContextuelToEntities($stockArticles);

        $filtreAvance = new GeneratorCs($post, 'SARTICLE', 'SM.NO_MVT', $this->pdo, $trad);
        $filtreAvance->setFiltre('SA.QTE_PHY', 'numeric', $trad->t('Quantité physique'));
        $filtreAvance->setFiltre('SA.VALEUR', 'numeric', $trad->t('Valeur'));
        $filtreAvance->setFiltre('SA.ART_ACH', 'bool', $trad->t('Article Acheté ?'), '', null, null, 'bdd');
        $filtreAvance->setFiltre('SA.TRACABLE', 'bool', $trad->t('Traçabilité ?'), '', null, null, 'bdd');
        $filtreAvance->setFiltre('SA.UNITE_ACH', 'text', $trad->t('Unité d\'achat'));
        $filtreAvance->setFiltre('SA.CONVER', 'numeric', $trad->t('Conversion UA-US'));
        $filtreAvance->setFiltre('ART.CODEFAB', 'text', $trad->t('Code fabricant'));
        $filtreAvance->setFiltre('ART.CODEGAM', 'text', $trad->t('Code gamme'));
        $filtreAvance->setFiltre('ART.REFARTFAB', 'text', $trad->t('Réf article/fabricant'));
        $filtreAvance->setFiltre('ART.CLASSE', 'text', $trad->t('Classe ABC'));
        $filtreAvance->setFiltre('SA.ART_LOUE', 'bool', $trad->t('Article loué ?'), '', null, null, 'bdd');
        $filtreAvance->setFiltre('SA.TX_LOCAT', 'numeric', $trad->t('Taux de location'));
        $filtreAvance->setFiltre('SA.DTE_CREAT', 'date', $trad->t('Date de création'));
        $filtreAvance->setFiltre('SA.DTE_MAJ', 'date', $trad->t('Date MAJ'));
        $filtreAvance->setFiltre('SA.DTE_FERM', 'date', $trad->t('Date de fermeture'));
        $filtreAvance->setFiltre('SA.DIMENSION', 'numeric', $trad->t('Dimension'));
        $filtreAvance->setFiltre('ART.SSFAM', 'liste', $trad->t('Sous-famille'), '', 'Ajax.liste.sousFamille', 'SousFamille');
        $filtreAvance->setFiltre('SA.RUBRIQUE', 'text', $trad->t('Rubrique'));

        return $this->renderer->render('@Stock/StockArticle/gestion', [
            'post'                => $post,
            'menuActive'          => 'Stock',
            'infoPagination'      => $infoPagination,
            'stockArticles'       => $stockArticles,
            'initFiltreAvance'    => $filtreAvance->getInit(),
            'filtreAvance'        => $filtreAvance->getFiltres(),
            'devise'              => $_SESSION['parametrage']['DEVISE_BASE'],
            'listeFiltreBool'     => $listManagerService->getChoixBoolList(),
            'listeFiltreTypeValo' => $listManagerService->getchoixTypeValoList(),
        ]);
    }

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

        return $this->renderer->render('@Stock/StockArticle/ligne', [
            'id' => $this->request->getAttribute('codeArt'),
            'idCs' => ChampSupp::encodeCodeEnr('SARTICLE', $codeArt),
            'stockArticle' => (new StockArticleRepo($this->pdo))->findFromCodeArt($codeArt),
            'listeChoixTypeValo' => (new ListManagerService($this->getTranslationService()))->getChoixTypeValoList(false)
        ]);
    }

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

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

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

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

        $stockArticles = (new StockArticleRepo($this->pdo))->listStocksArticlesExport($postFilters, implode(',', $arrayMultiSelect));

        $entete = $stockArticleExportService->getTableEntete($arrayMultiSelect, $listeCS, 'SARTICLE');
        $champsDate = $stockArticleExportService->getChampsParType('DATE');

        foreach ($stockArticles as &$stockArticle) {
            /** @var array<int,array<string,string>> $listeCS */
            $stockArticleExportService->addChampsSupplementaireValeur($listeCS, $stockArticle, 'CODE_ART');
            $stockArticleExportService->convertirDates($champsDate, $stockArticle);
        }

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

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


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

        if (!$stockArticle = (new StockArticleRepo($this->pdo))->findFromCodeArt($codeArt)) {
            return $this->create404Response('Cet article n\'existe pas');
        }

        Ariane::generate(
            1,
            $trad->t('Modification d\'article'),
            [],
            null,
            $this->router->generateUri('Stock.StockArticle.modifierForm', ['codeArt' => $codeArt])
        );

        return $this->renderer->render('@Stock/StockArticle/modifier_form', [
            'dateJour' => date("Ymd"),
            'stockArticle' => $stockArticle,
            'post' => $this->request->getParsedBody(),
            'articleEntity' => (new Articles($this->pdo))->find(['CODE_ART' => $codeArt]),
            'memos' => (new Memos($this->pdo))->find(['NODEMEMO' => $stockArticle['NM_DESCR']]),
            'listeChoixTypeValo' => (new ListManagerService($trad))->getChoixTypeValoList()
        ]);
    }

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

        if (!$stockArticle = $sarticle->find(['CODE_ART' => $codeArt])) {
            return $this->createJsonResponse(['message' => Trad::strBuild($trad->t('L\'article portant le code @1@ n\'existe pas'), $codeArt)], 404);
        }

        $memos = $post['MEMOS'];
        SwitchDataHelper::initEmptySwitch($post['SARTICLE'], ['TRACABLE', 'ART_ACH', 'ART_LOUE', 'EXISTREEL', 'STRATEG']);
        $stockArticle = array_merge($stockArticle, $post['SARTICLE']);

        $validator
            ->validateDescription($memos)
            ->validateSousFamille($stockArticle)
            ->validateRubrique($stockArticle)
            ->validateDimension($stockArticle)
            ->validateTypeValo($stockArticle)
            ->validateUniteAch($stockArticle)
            ->validateTxLocat($stockArticle)
            ->validateDteFerm($stockArticle)
            ->validateDteCreat($stockArticle)
            ->validateDteMaj($stockArticle)
            ->validateDtDernca($stockArticle)
            ->validateConver($stockArticle)
            ->validateCs('SARTICLE', $stockArticle['CODE_ART'], $post)
        ;

        if ($validator->isValid()) {
            $stockArticleFormService = new StockArticleFormService($this->pdo);
            $post['MEMOS_ENTITY'] = $stockArticleFormService->updateMemos($memos);
            $stockArticle['DTE_MAJ'] = date('Ymd');
            $stockArticle['NM_DESCR'] = $post['MEMOS_ENTITY']['NODEMEMO'];
            $stockArticleFormService->flushData($stockArticle, $post);

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

    /**
     * @throws Exception
     */
    public function stockGlobalAction() : string|Response
    {
        $sarticle = new Sarticle($this->pdo);
        $trad = $this->getTranslationService();
        $codeArt = $this->request->getAttribute('codeArt');

        if (!$stockArticle = $sarticle->find(['CODE_ART' => $codeArt])) {
            return $this->createJsonResponse(['message' => Trad::strBuild($trad->t('L\'article portant le code @1@ n\'existe pas'), $codeArt)], 404);
        }

        return $this->renderer->render('@Stock/StockArticle/stock_global', [
            'stockArticle' => $stockArticle,
            'stockGlobal' => (new StockLocalRepo($this->pdo))->findGlobal($codeArt),
            'societe' => (new Societe($this->pdo))->find(['CODE_STE' => $_SESSION['Session_SocUsrProfil']]),
        ]);
    }

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

        Ariane::generate(1, $trad->t('Mouvements'), [], null, $this->router->generateUri('Stock.StockArticle.mouvements'));

        $post['filter_egal_CODE_ART'] = $codeArt;
        (new PaginatorGestion())->generate(10, 'NO_MVT');
        $mouvements = (new MouvementRepo($this->pdo))->listMouvements($post);
        $infoPagination = PaginatorGestion::getInfoPagination();

        return $this->renderer->render('@Stock/StockArticle/mouvements', [
            'post' => $post,
            'codeArt' => $codeArt,
            'infoPagination' => $infoPagination,
            'mouvements' => $mouvements,
            'listeChoixTypeEntete' => (new ListManagerService($trad))->getTypeEnteteList(),
            'listeChoixTypesMvt' => (new ListManagerService($trad))->getChoixTypeMouvementList()
        ]);
    }

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

        Ariane::generate(
            1,
            $trad->t('Sites de stockage'),
            [],
            null,
            $this->router->generateUri('Stock.StockArticle.stockArticleParSite', ['codeArt' => $codeArt]),
        );

        (new PaginatorGestion())->generate(20, 'SITE');
        $post['filter_egal_STO#point#CODE_ART'] = $codeArt;
        $stockLocaux = (new StockLocalRepo($this->pdo))->listSites($post);
        $infoPagination = PaginatorGestion::getInfoPagination();

        return $this->renderer->render('@Stock/StockArticle/stock_article_par_site', [
            'post' => $post,
            'codeArt' => $codeArt,
            'infoPagination' => $infoPagination,
            'stockLocaux' => $stockLocaux,
            'design' => (new Sarticle($this->pdo))->find(['CODE_ART' => $codeArt])['DESIGN'],
        ]);
    }

    /**
     * @throws Exception
     */
    public function articlesDeRemplacementFormAction() : string|Response
    {
        $sarticle = new Sarticle($this->pdo);
        $trad = $this->getTranslationService();
        $codeArt = $this->request->getAttribute('codeArt');

        if (!$stockArticle = $sarticle->find(['CODE_ART' => $codeArt])) {
            return $this->createJsonResponse(['message' => Trad::strBuild($trad->t('L\'article portant le code @1@ n\'existe pas'), $codeArt)], 404);
        }

        Ariane::generate(
            1,
            $trad->t('Articles de remplacement'),
            [],
            null,
            $this->router->generateUri('Stock.StockArticle.articlesDeRemplacementForm', ['codeArt' => $codeArt]),
        );

        return $this->renderer->render('@Stock/StockArticle/articles_de_remplacement_form', ['stockArticle' => $stockArticle]);
    }

    /**
     * @throws Exception
     */
    public function articlesDeRemplacementAction() : Response
    {
        $post = $this->request->getParsedBody();
        $sarticle = new Sarticle($this->pdo);
        $trad = $this->getTranslationService();
        $codeArt = $this->request->getAttribute('codeArt');

        if (!$stockArticle = $sarticle->find(['CODE_ART' => $codeArt])) {
            return $this->createJsonResponse(['message' => Trad::strBuild($trad->t('L\'article portant le code @1@ n\'existe pas'), $codeArt)], 404);
        }

        $stockArticle = array_merge($stockArticle, $post['SARTICLE']);
        $validator = new StockArticleValidator($this->pdo, $trad);

        $validator
            ->validateArtRemp($stockArticle)
            ->validateArtRemp($stockArticle, 2)
            ->validateArtRemp($stockArticle, 3)
            ->validateConvArtRemp($stockArticle)
            ->validateConvArtRemp($stockArticle, 2)
            ->validateConvArtRemp($stockArticle, 3)
        ;

        return $this->saveStockArticle($stockArticle, $validator);
    }

    /**
     * @throws Exception
     */
    public function fournisseursPreferentielsFormAction() : string|Response
    {
        $sarticle = new Sarticle($this->pdo);
        $trad = $this->getTranslationService();
        $codeArt = $this->request->getAttribute('codeArt');

        if (!$stockArticle = $sarticle->find(['CODE_ART' => $codeArt])) {
            return $this->createJsonResponse(['message' => Trad::strBuild($trad->t('L\'article portant le code @1@ n\'existe pas'), $codeArt)], 404);
        }

        Ariane::generate(
            1,
            $trad->t('Fournisseurs préférentiels'),
            [],
            null,
            $this->router->generateUri('Stock.StockArticle.fournisseursPreferentielsForm', ['codeArt' => $codeArt]),
        );

        return $this->renderer->render('@Stock/StockArticle/fournisseurs_preferentiels_form', ['stockArticle' => $stockArticle]);
    }

    /**
     * @throws Exception
     */
    public function fournisseursPreferentielsAction() : Response
    {
        $sarticle = new Sarticle($this->pdo);
        $trad = $this->getTranslationService();
        $post = $this->request->getParsedBody();
        $codeArt = $this->request->getAttribute('codeArt');

        if (!$stockArticle = $sarticle->find(['CODE_ART' => $codeArt])) {
            return $this->createJsonResponse(['message' => Trad::strBuild($trad->t('L\'article portant le code @1@ n\'existe pas'), $codeArt)], 404);
        }

        $stockArticle = array_merge($stockArticle, $post['SARTICLE']);

        $validator = new StockArticleValidator($this->pdo, $trad);
        $validator->validateFou($stockArticle)->validateFou($stockArticle, 2)->validateFou($stockArticle, 3);

        return $this->saveStockArticle($stockArticle, $validator);
    }

    /**
     * @throws Exception
     */
    public function getStockArticleAction() :Response
    {
        $post = $this->request->getParsedBody();
        if (!$stockArticle = (new Sarticle($this->pdo))->find($post['codeArt'])) {
            return $this->create404Response($this->getTranslationService()->t('Cet article de stock n\'existe pas'));
        }

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

    public function nouveauFormAction(): string
    {
        $trad = $this->getTranslationService();

        Ariane::generate(
            1,
            $trad->t('Création d\'un article'),
            [],
            null,
            $this->router->generateUri('Stock.StockArticle.nouveauForm')
        );

        return $this->renderer->render('@Stock/StockArticle/nouveau_form', [
            'dateJour' => date('Ymd'),
            'listeChoixTypeValo' => (new ListManagerService($this->getTranslationService()))->getChoixTypeValoList()
        ]);
    }

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

        $memos = $post['MEMOS'];
        $stockArticle = $post['SARTICLE'];

        SwitchDataHelper::initEmptySwitch($stockArticle, ['TRACABLE', 'ART_ACH', 'ART_LOUE', 'EXISTREEL', 'STRATEG']);

        $validator
            ->validateCodeArt($stockArticle)
            ->validateDescription($memos)
            ->validateSousFamille($stockArticle)
            ->validateRubrique($stockArticle)
            ->validateDimension($stockArticle)
            ->validateTypeValo($stockArticle)
            ->validateUniteAch($stockArticle)
            ->validateTxLocat($stockArticle)
            ->validateDteFerm($stockArticle)
            ->validateDteCreat($stockArticle)
            ->validateDteMaj($stockArticle)
            ->validateDtDernca($stockArticle)
            ->validateConver($stockArticle)
            ->validateCs('SARTICLE', $stockArticle['CODE_ART'], $post, null, true)
        ;

        if ($validator->isValid()) {
            $stockArticleFormService = new StockArticleFormService($this->pdo);
            $memos = $stockArticleFormService->updateMemos($memos);
            $stockArticle = $stockArticleFormService->initEntity($stockArticle, ['MEMOS' => $memos]);
            $post['MEMOS'] = $memos;

            $stockArticleFormService->flushData($stockArticle, $post);

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

    /**
     * @throws Exception
     */
    public function getInformationOnArticleAction(): Response
    {
        $articles = new Articles($this->pdo);
        $post = $this->request->getParsedBody();

        if (!$articleEntity = $articles->find(['CODE_ART' => $post['codeArt']])) {
            return $this->create404Response($this->getTranslationService()->t('L\'article n\'existe pas'));
        }

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

    /**
     * @throws Exception
     */
    public function stockParSocieteAction(): string
    {
        $trad = $this->getTranslationService();
        $codeArt = $this->request->getAttribute('codeArt');

        Ariane::generate(
            1,
            $trad->t('Stock par société'),
            [],
            null,
            $this->router->generateUri('Stock.StockArticle.stockParSociete')
        );

        return $this->renderer->render('@Stock/StockArticle/stock_par_societe', params: [
            'codeArt' => $codeArt,
            'stocksGlobaux' => (new StockGlobalSocieteRepo($this->pdo))->findAllFromCodeArt($codeArt),
            'designationStockArticle' => (new Sarticle($this->pdo))->find(['CODE_ART' => $codeArt])['DESIGN'],
        ]);
    }

    /**
     * @throws Exception
     */
    public function popupAjoutStockLocalAction(): string
    {
        $post = $this->request->getParsedBody();
        $codeArt = $this->request->getAttribute('codeArt');

        (new PaginatorGestion())->generate(10);
        $post['exclude_code_art'] = $codeArt;
        $sitesStock = (new Listes($this->pdo))->listSitesStockAccessibles($post);

        return $this->renderer->render('@Stock/StockArticle/Popup/ajout_stock_local', [
            'post' => $post,
            'codeArt' => $codeArt,
            'sitesStock' => $sitesStock,
            'infoPagination' => PaginatorGestion::getInfoPagination(),
        ]);
    }
}
