<?php
namespace Modules\Catalogue\Controller;

use _PHPStan_1f608dc6a\Nette\Schema\Elements\Structure;
use Entity\Model\CFormats;
use Entity\Model\CrossRefFmt;
use Entity\Model\FmtMapp;
use Entity\Model\FValDef;
use Entity\Model\MultiMapp;
use Entity\Model\PFormats;
use Entity\Model\RegValid;
use Entity\Model\StruCata;
use Entity\Model\Transcod;
use GuzzleHttp\Psr7\Response;
use Helpers\Ariane\Ariane;
use Helpers\Ariane\ArianeSub;
use Helpers\Fichier\Fichier;
use Helpers\Outil\ArrayHelper;
use Helpers\Outil\Sql;
use Helpers\Pagination\PaginatorGestion;
use Helpers\Session\ParseBase1;
use Helpers\Trad\ITrad;
use Helpers\Trad\Trad;
use Modules\Catalogue\MenuContextuel\FormatMenuContextuel;
use Modules\Catalogue\Repository\FormatRepository;
use Modules\Catalogue\Service\MappingDefaultService;
use Modules\Catalogue\Service\UpdateValueParamMappageService;
use Modules\Catalogue\Validator\FormatValidator;
use Modules\Catalogue\Validator\MultiMappingValidator;
use Modules\Catalogue\Validator\ParametrageValidator;
use Modules\Catalogue\Validator\TranscodageValidator;
use Modules\Catalogue\Validator\UpdateValueParametrageValidator;
use Modules\Catalogue\Validator\ValidationValidator;
use PhpOffice\PhpSpreadsheet\Reader\Csv;
use PHPStan\Type\ArrayType;
use Skeleton\Controller\Controller;

class ParametrageFormatController extends Controller
{
    /**
     * Summary of listeLigneRubrique
     * @var array<int>
     */
    public static $listeLigneRubrique = [38];
    /**
     * Summary of listeLigneRubrique
     * @var array<int>
     */
    public static $listeLigneTab = [32, 33, 34, 35, 36, 37];

    //_____________________________ MAPPAGE _____________________________

    public function paramMappageAction():string
    {
        $idFormat = $this->request->getAttribute('IdFormat');
        $trad = $this->getTranslationService();

        Ariane::generate(1, $trad->t('Paramétrage formats'));
        $blocEntete = $this->generateSubAriane($trad, $idFormat);

        $listeStructure = (new FormatRepository($this->pdo))->getStructure($idFormat);
        $infoFormat = (new CFormats($this->pdo))->find($idFormat, ['TYPDATAS']);

        return $this->renderer->render('@catalogue/ParametrageFormat/mappage/mappage', [
            'menuActive'        => 'Catalogue',
            'idFormat'          => $idFormat,
            'listeStructure'    => $listeStructure,
            'blocEntete'        => $blocEntete,
            'mappingExist'      => in_array($infoFormat['TYPDATAS'], [MappingDefaultService::OCI, MappingDefaultService::CXML]),
            'typeFormat'        => $infoFormat['TYPDATAS'],
            'listeTypeFormat'   => $this->listeTypeFormat(),
        ]);
    }

    public function resetMappingAction():Response
    {
        $idFormat = $this->request->getAttribute('IdFormat');
        //$post = $this->request->getParsedBody();

        $infoFormat = (new CFormats($this->pdo))->find($idFormat, ['TYPDATAS']);

        $mappingService = new MappingDefaultService(
            (new Csv()),
            (new ParseBase1()),
            (new ArrayHelper()),
            (new FmtMapp($this->pdo)),
            (new MultiMapp($this->pdo)),
            (new Transcod($this->pdo)),
            (new FValDef($this->pdo)),
            (new RegValid($this->pdo)),
        );
        $mappingService->setTypeMapping($infoFormat['TYPDATAS'] == 'OCI'? $mappingService::OCI:$mappingService::CXML);
        $mappingService->initializeMapping($idFormat);

        return new Response(200, [], (string) json_encode([
            'statut' => 'O',
        ]));
    }

    public function popupMultiMappAction():string
    {
        $idFormat = $this->request->getAttribute('IdFormat');
        $idLigne = $this->request->getAttribute('IdLigne');
        $trad = $this->getTranslationService();

        $listeMultiMapp = (new MultiMapp($this->pdo))->findAll(['IDFORMAT' => $idFormat, 'LIGNE' => $idLigne]);

        return $this->renderer->render('@catalogue/ParametrageFormat/mappage/popupMultiMapping', [
            'IdFormat'          => $idFormat,
            'IdLigne'           => $idLigne,
            'element'           => (new FmtMapp($this->pdo))->find(['IDFORMAT' => $idFormat, 'LIGNE' => $idLigne]),
            'listeMultiMapp'    => $listeMultiMapp,
            'listeTypeContenu'  => [
                'N' => $trad->t('Normal'),
                'L' => $trad->t('Liste'),
                'C' => $trad->t('Couple'),
            ],
            'listeRubrique'     => [
                'QUANTITE'      => $trad->t('QUANTITE'),
                'REMISE'        => $trad->t('REMISE'),
                'PRIX'          => $trad->t('PRIX'),
            ],
            'listeAction'       => $this->listeActionMultiMapping($idLigne),
            'listeLigneRubrique' => self::$listeLigneRubrique,
            'listeLigneTab'      => self::$listeLigneTab,
        ]);
    }

    public function ajaxAjoutLigneAction():string
    {
        $idLigne = $this->request->getAttribute('IdLigne');
        $trad = $this->getTranslationService();
        
        return $this->renderer->render('@catalogue/ParametrageFormat/mappage/_ligneMultiMapping', [
            'random'            => rand(),
            'IdLigne'           => $idLigne,
            'listeAction'       => $this->listeActionMultiMapping($idLigne),
            'listeLigneRubrique' => self::$listeLigneRubrique,
            'listeLigneTab'      => self::$listeLigneTab,
            'listeRubrique'     => [
                'QUANTITE'      => $trad->t('QUANTITE'),
                'REMISE'        => $trad->t('REMISE'),
                'PRIX'          => $trad->t('PRIX'),
            ],
        ]);
    }

    public function validateMultiMappingAction():Response
    {
        $post = $this->request->getParsedBody();

        $idFormat = $this->request->getAttribute('IdFormat');
        $idLigne = $this->request->getAttribute('IdLigne');

        $validator = new MultiMappingValidator($this->pdo, $this->getTranslationService());

        $listeLigne = [];
        $validator->validateForm($post, $listeLigne, (int)$idLigne);

        if (!$validator->isValid()) {
            return new Response(200, [], (string)json_encode(['statut' => 'E', 'error' => $validator->getError()]));
        }

        $multiMappEntity = new MultiMapp($this->pdo);
        $multiMappEntity->delete(['IDFORMAT' => $idFormat, 'LIGNE' => $idLigne]);

        $firstPosition = null;
        foreach ($listeLigne as $ligne) {
            if ($firstPosition === null) {
                $firstPosition = $ligne['POSITION'];
            }

            $multiMappEntity->insert([
                'IDFORMAT'                  => $idFormat,
                'LIGNE'                     => $idLigne,
                'POSITION'                  => $ligne['POSITION']??'',
                'LONGUEUR'                  => $ligne['LONGUEUR']??0,
                'ELEM_XML'                  => $ligne['ELEM_XML']??'',
                'ACTION'                    => $ligne['ACTION']??'',
                'OPCONCAT'                  => $ligne['OPCONCAT']??'',
                'RUBASSOCIEE'               => $ligne['RUBASSOCIEE']??'',
                'VALDEFAUT'                 => $ligne['VALDEFAUT']??'',
                'numerique_CONTROLE'        => sql::setBoolSql($ligne['CONTROLE']??false),
                'numerique_TRANSCODAGE'     => sql::setBoolSql($ligne['TRANSCODAGE']??false),
                'TRANCHEVAL'                => $ligne['TRANCHEVAL']??'',
            ]);
        }

        (new FmtMapp($this->pdo))->update([
            'TYPECONTSTR'   => $post['TYPECONTSTR'],
            'SEPARLST'      => $post['SEPARLST'],
            'SEPARCOUPLE'   => $post['SEPARCOUPLE'],
            'POSITION'      => $firstPosition,
        ], ['IDFORMAT' => $idFormat, 'LIGNE' => $idLigne]);

        return new Response(200, [], (string)json_encode([
            'statut' => 'O',
            'POSITION' => $firstPosition,
            'IDPOSITION' => 'input_POSITION'.$idLigne,
        ]));
    }

    public function popupMappingAction():string
    {
        $typeFormat = $this->request->getAttribute('typeFormat');
        $post = $this->request->getParsedBody();
        $filtre = $post;

        unset($filtre['divCode']);
        unset($filtre['divLibelle']);
        unset($filtre['value']);

        if (!$filtre) {
            $post['tri_TAG_XML'] = 'ASC';
        }
        
        $mappingService = new MappingDefaultService(
            (new Csv()),
            (new ParseBase1()),
            (new ArrayHelper()),
            (new FmtMapp($this->pdo)),
            (new MultiMapp($this->pdo)),
            (new Transcod($this->pdo)),
            (new FValDef($this->pdo)),
            (new RegValid($this->pdo)),
        );

        $mappingService->setTypeMapping($typeFormat);
        $tableau = $mappingService->getListeMapping();

        $listeMapping = (new FormatRepository($this->pdo))->listeMappingPopup($tableau, $post);

        return $this->renderer->render('@catalogue/ParametrageFormat/mappage/popupMapping', [
            'listeMapping' => $listeMapping,
            'typeFormat' => $typeFormat,
            'post' => $post
        ]);
    }

    //_____________________________ CONTROLE _____________________________

    public function paramControleAction():string
    {
        $idFormat = $this->request->getAttribute('IdFormat');
        $trad = $this->getTranslationService();

        ArianeSub::generate(0, 1, $trad->t('Contrôle'), $this->router->generateUri('Catalogue.parametrageFormat.paramControle', ['IdFormat' => $idFormat]), 1, [], '', '', '', '', true, true);

        $listeStructure = (new FormatRepository($this->pdo))->getStructureControle($idFormat);

        return $this->renderer->render('@catalogue/ParametrageFormat/controle/controller', [
            'menuActive'        => 'Catalogue',
            'idFormat'          => $idFormat,
            'listeStructure'    => $listeStructure,
            'blocEntete'        => ['controleMapping' => 1],
            'listeTypeFormat'   => $this->listeTypeFormat(),
            'listeDiviseur'     => [
                '0'      => '',
                '-1'    => $trad->t('Qté.Cdt'),
                '1'     => '1',
                '10'    => '10',
                '100'   => '100',
                '1000'  => '1000',
                '10000' => '10000'
            ],
        ]);
    }

    //_____________________________ TRANSCO _____________________________

    public function paramTranscoAction():string
    {
        $idFormat = $this->request->getAttribute('IdFormat');
        $trad = $this->getTranslationService();

        Ariane::generate(1, $trad->t('Paramétrage formats'));
        ArianeSub::generate(0, 2, $trad->t('Transcodification'), $this->router->generateUri('Catalogue.parametrageFormat.paramTransco', ['IdFormat' => $idFormat]), 1, [], '', '', '', '', true, true);
        $listeTransco = (new FormatRepository($this->pdo))->getTranscodage($idFormat);

        return $this->renderer->render('@catalogue/ParametrageFormat/transcodage/transcodification', [
            'menuActive'        => 'Catalogue',
            'idFormat'          => $idFormat,
            'listeTransco'      => $listeTransco,
            'listeTypeFormat'   => $this->listeTypeFormat(),
            'blocEntete'        => ['controleMapping' => 1],
        ]);
    }

    public function gestionTranscoAction():string
    {
        $idFormat = $this->request->getAttribute('IdFormat');
        $idLigne = $this->request->getAttribute('IdLigne');
        $trad = $this->getTranslationService();

        ArianeSub::generate(1, 1, $trad->t('Transcodage'), $this->router->generateUri('Catalogue.parametrageFormat.gestionTransco', ['IdFormat' => $idFormat, 'IdLigne' => $idLigne]), 1);
        $listeTransco = (new Transcod($this->pdo))->findAll(['IDFORMAT' => $idFormat, 'LGMAPPING' => $idLigne]);
        $infoStrcture = (new StruCata($this->pdo))->find($idLigne);

        return $this->renderer->render('@catalogue/ParametrageFormat/transcodage/gestionTransco', [
            'menuActive'        => 'Catalogue',
            'idFormat'          => $idFormat,
            'idLigne'           => $idLigne,

            'listeTypeFormat'   => $this->listeTypeFormat(),
            'blocEntete'        => ['controleMapping' => 1],
            'listeTransco'      => $listeTransco,
            'infoStrcture'      => $infoStrcture,
        ]);
    }

    public function ajaxAjoutLigneTranscoAction():string
    {
        return $this->renderer->render('@catalogue/ParametrageFormat/transcodage/_ligneTransco', [
            'random'            => rand(),
        ]);
    }

    public function validateTranscoAction():string|Response
    {
        $idFormat = $this->request->getAttribute('IdFormat');
        $idLigne = $this->request->getAttribute('IdLigne');
        $post = $this->request->getParsedBody();
        $validator = new TranscodageValidator($this->pdo, $this->getTranslationService());

        $listeValue = $validator->validateTranscodage($post);

        if ($validator->isValid()) {
            (new Transcod($this->pdo))->delete(['IDFORMAT' => $idFormat, 'LGMAPPING' => $idLigne]);

            $i = 1;
            foreach ($listeValue as $val) {
                (new Transcod($this->pdo))->insert([
                    'IDFORMAT'  => $idFormat,
                    'LGMAPPING' => $idLigne,
                    'LGTRANSCO' => $i,
                    'VALENTREE' => $val['VALENTREE'],
                    'VALREMPLA' => $val['VALREMPLA'],
                ]);
                $i++;
            }

            return new Response(443, [], (string) json_encode(['path' => $this->router->generateUri('Catalogue.parametrageFormat.gestionTransco', ['IdFormat' => $idFormat, 'IdLigne' => $idLigne])]));
        } else {
            return new Response(200, [], $this->renderer->render('@popup-erreur/ErreurCreation', [
                'ErreurValid' => $validator->getError(),
                'desactiveRow' => true,
            ]));
        }
    }

    public function popupImportTranscoAction():string
    {
        return $this->renderer->render('@catalogue/ParametrageFormat/transcodage/popupImportTransco', [
            'listeImport' => [],
        ]);
    }

    public function ajaxImportTranscoAction():string|Response
    {
        $file = $this->request->getUploadedFiles();

        if ($file) {
            $file_name = $file['importtransco']->getClientFilename();
            $fileSize = $file['importtransco']->getSize();
        } else {
            $file_name = '';
            $fileSize = 0;
        }

        $validator = $this->createValidator();
        $validator->fileCheck($this->getTranslationService()->t('import transcodage'), $file_name, ['csv'], '', $fileSize);
        if (!$validator->isValid()) {
            return new Response(443, [], (string) json_encode(['msgError' => $validator->getError()]));
        }

        $newPath = Fichier::UploadDocAtt($file_name);
        $fichier = $newPath['racine'].$newPath['new_name'];
        $file['importtransco']->moveTo($fichier);

        $reader = new \PhpOffice\PhpSpreadsheet\Reader\Csv();
        if (mb_detect_encoding($fichier) !== 'UTF-8') {
            $reader->setInputEncoding('Windows-1252');
        }
        $reader->setDelimiter(';');

        $spreadsheet = $reader->load($fichier);

        $sheet = $spreadsheet->getSheet(0);

        $highestRow = $spreadsheet->getActiveSheet()->getHighestRow();

        $arrayLigne = [];
        for ($row=1; $highestRow > $row; $row++) {
            $arrayLigne[] = [
                'LGTRANSCO' => '0',
                'VALENTREE' => $sheet->getCell([intval(1),intval($row)])->getValue(),
                'VALREMPLA' => $sheet->getCell([intval(2),intval($row)])->getValue(),
            ];
        }

        return $this->renderer->render('@catalogue/ParametrageFormat/transcodage/importTransco', [
            'listeImport' => $arrayLigne,
        ]);
    }

    //_____________________________ CONTROLE _____________________________

    public function paramValidationAction():string
    {
        $idFormat = $this->request->getAttribute('IdFormat');
        $trad = $this->getTranslationService();

        ArianeSub::generate(0, 3, $trad->t('Règle validation'), $this->router->generateUri('Catalogue.parametrageFormat.paramValidation', ['IdFormat' => $idFormat]), 1, [], '', '', '', '', true, true);

        $listeStructure = (new FormatRepository($this->pdo))->getRegleValidation($idFormat);

        return $this->renderer->render('@catalogue/ParametrageFormat/validation/validation', [
            'menuActive'        => 'Catalogue',
            'idFormat'          => $idFormat,
            'listeStructure'    => $listeStructure,
            'blocEntete'        => ['controleMapping' => 1],
            'listeTypeFormat'   => $this->listeTypeFormat(),
            'listeRegle'        => $this->listeRegleComparaison(),
            'listeOperateur'    => $this->listeOperateur(),
        ]);
    }

    public function popupValidationAction():string
    {
        $idFormat = $this->request->getAttribute('IdFormat');
        $idLigne = $this->request->getAttribute('IdLigne');

        $listeValidation = (new RegValid($this->pdo))->findAll([
            'IDFORMAT' => $idFormat,
            'LGMAPPING' => $idLigne,
        ]);

        return $this->renderer->render('@catalogue/ParametrageFormat/validation/popupValidation', [
            'IdFormat'          => $idFormat,
            'IdLigne'           => $idLigne,
            'listeRegle'        => $this->listeRegleComparaison(),
            'listeOperateur'    => $this->listeOperateur(),

            'listeValidation'    => $listeValidation,
        ]);
    }

    public function ajaxAjoutLigneValidationAction():string
    {
        return $this->renderer->render('@catalogue/ParametrageFormat/validation/_ligneValidation', [
            'random'            => rand(),
            'listeRegle'        => $this->listeRegleComparaison(),
            'listeOperateur'    => $this->listeOperateur(),
        ]);
    }

    public function validateValidationAction():string|Response
    {
        $idFormat = $this->request->getAttribute('IdFormat');
        $idLigne = $this->request->getAttribute('IdLigne');
        $post = $this->request->getParsedBody();

        $validator = (new ValidationValidator($this->pdo, $this->getTranslationService()));
        $listeValue = $validator->validateValidation($post);
        
        if (!$validator->isValid()) {
            return new Response(443, [], (string) json_encode(['msgError' => $validator->getError()]));
        }
        
        (new RegValid($this->pdo))->delete(['IDFORMAT' => $idFormat, 'LGMAPPING' => $idLigne]);

        $i = 1;
        foreach ($listeValue as $val) {
            (new RegValid($this->pdo))->insert([
                'IDFORMAT'  => $idFormat,
                'LGMAPPING' => $idLigne,
                'LIGNE'     => $val['LIGNE'],

                'OPERATEUR' => $val['OPERATEUR'],
                'REGCOMPAR' => $val['REGCOMPAR'],
                'ZONE1'     => $val['ZONE1'],
                'ZONE2'     => $val['ZONE2'],
            ]);
            $i++;
        }

        return new Response(200);
    }

    //_____________________________ GLOBAL _____________________________
    
    public function updateValueAction():Response
    {
        $idFormat = $this->request->getAttribute('IdFormat');
        $post = $this->request->getParsedBody();
        $trad = $this->getTranslationService();

        $validator = (new UpdateValueParametrageValidator($this->pdo, $trad));

        $validator->validatorField($post['field'], $post['value']);

        if (!$validator->isValid()) {
            return new Response(200, [

            ], (string) \json_encode([
                'statut' => 'B',
                'message' => substr($validator->getError(), 6),
                'title' => $trad->t('Erreur'),
                'content' => $this->renderer->render('@popup-erreur/ErreurCreation', [
                    'ErreurValid' => $validator->getError(),
                ])
            ]));
        }

        $updateValueService = new UpdateValueParamMappageService($this->pdo);
        $updateValueService->setFormat($idFormat);
        $updateValueService->updateValue($post['field'], $post['value']);
        
        $blocEntete = $this->generateSubAriane($trad, $idFormat);
        return new Response(200, [

        ], (string) \json_encode([
            'statut'            => 'O',
            'ariane'            => $this->renderer->render('@catalogue/ParametrageFormat/_arianeSub', [
                'blocEntete'        => $blocEntete
            ])
        ]));
    }


/*____________________________________________________________________________________*/
    /**
     * @param \Helpers\Trad\ITrad $trad
     * @param string $idFormat
     * @return array<mixed>
     */
    private function generateSubAriane(ITrad $trad, string $idFormat)
    {
        $formatRepo = (new FormatRepository($this->pdo));
        $infoAriane = $formatRepo->setupArianeStructure($idFormat);

        $infoFormat = (new CFormats($this->pdo))->find($idFormat, ['TYPDATAS']);

        ArianeSub::init();
        ArianeSub::generate(0, 0, $trad->t('Mappage'), $this->router->generateUri('Catalogue.parametrageFormat.paramMappage', ['IdFormat' => $idFormat]), 1, [], '', '', '', '', true, $infoAriane['countParam']? true:false);
        ArianeSub::generate(0, 1, $trad->t('Contrôle'), $this->router->generateUri('Catalogue.parametrageFormat.paramControle', ['IdFormat' => $idFormat]), 0, [], '', '', '', '', true, $infoAriane['countParam']? true:false);
        ArianeSub::generate(0, 2, $trad->t('Transcodification'), $this->router->generateUri('Catalogue.parametrageFormat.paramTransco', ['IdFormat' => $idFormat]), 0, [], '', '', '', '', true, $infoAriane['countTranso']? true:false);
        ArianeSub::generate(0, 3, $trad->t('Règles validation'), $this->router->generateUri('Catalogue.parametrageFormat.paramValidation', ['IdFormat' => $idFormat]), 0, [], '', '', '', '', true, $infoAriane['countRegle']? true:false);
    
        $array = [];
        if ($infoFormat['TYPDATAS'] == MappingDefaultService::OCI || $infoFormat['TYPDATAS'] == MappingDefaultService::CXML) {
            $array['controleMapping'] = $formatRepo->controleMapping($idFormat);
            $array['paramExist'] = $infoAriane['countParam'];
        } else {
            $array['controleMapping'] = 1;
        }

        if ($infoFormat['TYPDATAS'] == 'CSV' || $infoFormat['TYPDATAS'] == 'TXT') {
            $array['controlePosition'] = $formatRepo->controlePosition($idFormat);
        }

        return $array;
    }

    /**
     * @return array<mixed>
     */
    private function listeActionMultiMapping(int $idLigne)
    {
        $trad = $this->getTranslationService();

        if (in_array($idLigne, self::$listeLigneTab)) {
            return [
                'Col'       => $trad->t('Colonne'),
            ];
        } elseif (in_array($idLigne, self::$listeLigneRubrique)) {
            return [
                'Aff'       => $trad->t('Affectation'),
            ];
        } else {
            return [
                'Con'       => $trad->t('Concaténation'),
            ];
        }
    }

    /**
     * @return array<string>
     */
    private function listeTypeFormat()
    {
        return [
            'A'     => $this->getTranslationService()->t('Alpha'),
            'N'     => $this->getTranslationService()->t('Numérique'),
            'D'     => $this->getTranslationService()->t('Date'),
            'Tab'   => $this->getTranslationService()->t('Table'),
            'U'     => $this->getTranslationService()->t('Unicode'),
        ];
    }

    /**
     * @return array<string>
     */
    private function listeRegleComparaison()
    {
        return [
            'V'     => $this->getTranslationService()->t('Valeur ='),
            'S'     => $this->getTranslationService()->t('Supérieur ou égal'),
            'I'     => $this->getTranslationService()->t('Inférieur ou égal'),
            'E'     => $this->getTranslationService()->t('Entre'),
            'L'     => $this->getTranslationService()->t('Liste'),
        ];
    }

    /**
     * @return array<string>
     */
    private function listeOperateur()
    {
        return [
            'E'     => $this->getTranslationService()->t('Exclure'),
        ];
    }
}
