<?php

namespace Modules\Facture\Repository;

use Entity\Model\Hastutil;
use Helpers\Filter\FilterTable;
use Helpers\Outil\ArrayHelper;
use Helpers\Outil\Sql;
use Helpers\QueryBuilder\AbsRepository;
use Helpers\Webservice\Wsdl;
use Modules\Index\Repository\Connexion;

class BonAPayerRepo extends AbsRepository
{
     /**
     * @param array<string> $listDeleg
     * @return array<mixed>
     */
    public function getCountSignatByDeleg(array $listDeleg) :array
    {
        if (empty($listDeleg)) {
            return [];
        }

        $paramListDeleg = [];
        foreach (array_values($listDeleg) as $k => $v) {
            $paramListDeleg[':param_' . $k] = $v;
        }
        $param = [];
        $req =
            'SELECT
            SIG_BAP.SIGNAT,
            count(FAC_ENT.NUM_FACT) as count
        FROM SIG_BAP with (nolock)
        LEFT JOIN FAC_ENT with (nolock) ON SIG_BAP.NO_FAC = FAC_ENT.NUM_FACT
        WHERE SIG_BAP.SIGNABLE= 0x54
            and
        '
            .$this->makeWhereIn(
                'SIG_BAP.SIGNAT',
                $listDeleg,
                $param
            );


        $userEntity = new Hastutil($this->pdo);
        $user = $userEntity->find($_SESSION["Session_Login"]);

        if (!Sql::boolSql($user['UTIMULTI'])) {
            $req .= "and exists (
                SELECT SOCIETE.CODE_STE
                FROM SOCIETE with (nolock)
                LEFT JOIN SOC_USR with (nolock)
                    ON SOC_USR.COD_STE = SOCIETE.CODE_STE
                    AND SOC_USR.COD_USR = :userSoc1
                LEFT JOIN HASTUTIL with (nolock)
                    ON HASTUTIL.CODE_STE = SOCIETE.CODE_STE
                    AND HASTUTIL.CODE = :userSoc2
                WHERE (SOC_USR.COD_USR IS NOT NULL OR HASTUTIL.CODE IS NOT NULL)
                    and (SOCIETE.DTEVALMIN = '00000000' or SOCIETE.DTEVALMIN <= '".date('Ymd')."')
                    and (SOCIETE.DTEVALMAX = '00000000' or SOCIETE.DTEVALMAX >= '".date('Ymd')."')
                    and SOCIETE.CODE_STE = FAC_ENT.CODE_STE
            )";

            $paramListDeleg[':userSoc1'] = $_SESSION["Session_Login"];
            $paramListDeleg[':userSoc2'] = $_SESSION["Session_Login"];
        }

            
        $req .= ' GROUP BY SIG_BAP.SIGNAT';
        
        return $this->fetchAssocAll(
            $req,
            $paramListDeleg
        );
    }

    // /**
    //  * @param array<string|int> $listFactureId
    //  * @return array<string,array<mixed>> SignBap&Hastutil indexed by num facture
    //  */
    // public function listSignataireAttendu($listFactureId) :array
    // {
    //     $param = [];
    //     $listRow = $this->fetchAssocAll(
    //         "SELECT
    //             SIG_BAP.NO_FAC, SIG_BAP.DTE_MISE, SIG_BAP.FAROLES, SIG_BAP.INFORME,
    //             HASTUTIL.CODE, HASTUTIL.NOM
    //         FROM SIG_BAP with (nolock)
    //         JOIN HASTUTIL with (nolock) ON SIG_BAP.SIGNAT = HASTUTIL.CODE
    //         WHERE ".$this->makeWhereIn('SIG_BAP.NO_FAC', $listFactureId, $param)
    //         ."ORDER BY SIG_BAP.ORDRE",
    //         $param
    //     );

    //     return ArrayHelper::indexBy($listRow,'NO_FAC');
    // }

    /**
     * @param string[] $listDeleg
     */
    public function countFactureSignable(string $user = null, array $listDeleg = []) :int
    {
        $param = [];

        if (!$user && !$listDeleg) {
            return 0;
        }

        $listUser = (!empty($listDeleg) ? $listDeleg : [$user]);

        $req =
            "SELECT count(facture.NUM_FACT) as count
            FROM FAC_ENT as facture with (nolock)
            JOIN SIG_BAP as sigBap with (nolock) ON sigBap.NO_FAC = facture.NUM_FACT
            WHERE facture.ATT_SIG = ".Sql::TRUE." 
                AND sigBap.SIGNABLE = ".Sql::TRUE." 
                AND sigBap.BAP_BAS = ".Sql::TRUE."
                AND sigBap.INFORME	 = ".Sql::FALSE."
                AND ".$this->makeWhereIn('sigBap.SIGNAT', $listUser, $param)
                . $this->andWhereUserMultisoc('facture.CODE_STE', $param)
                . $this->andWhereTypeDocConf('facture.NUM_FACT')
        ;
        return $this->fetchAssocOne($req, $param)['count'] ?? 0;
    }

    // TODO : move into a class "UserSession" or something alike
    private static ?int $cacheCountFactureSignableCurrent = null;

    public function countFactureSignableCurrent() :int
    {
        // TODO : use cache interface
        // Get from light cache
        if (self::$cacheCountFactureSignableCurrent !== null) {
            return self::$cacheCountFactureSignableCurrent;
        }

        self::$cacheCountFactureSignableCurrent =
            $this->countFactureSignable($_SESSION['Session_Login']);

        return self::$cacheCountFactureSignableCurrent;
    }


    /**
     * This is a clean up for V1 Sign::callWisdlForSigning() WIP
     * @param array<string> $listFactureId
     */
    public function sign(
        string $signer,
        array $listFactureId,
        string $password,
        string $comment
    ) :void {

        $array = [];

        $user_transfert = '';
    
        $listFactureId = [];
        $multiDocument = true;
        
        $algo = '';
        /**
         *
         * @author Eric Carles
         * @version 1.0 du 03/01/2008
         *          Ajout du spécifique 2173 Workflow Edifice :
         *          En cas de seuil insuffisant un signataire est susceptible de sélectionner un nouveau signataire
         */
        // TODO
        // Si pour la commande un nouveau signataire a été choisi
        // if (!$multiDocument
        //     && array_key_exists('is_new_signat', $array)
        //     && $array['is_new_signat'] == 1
        // ) {
            
        //     // On ajoute le signataire choisi
        //     if (array_key_exists('NouveauSignataire', $array))
        //         $user_transfert = $array['NouveauSignataire'];
            
        //     // Et on ajoute l'organigramme précédemment envoyé par le wsdl de signature
        //     if (array_key_exists('AlgoSpecif', $array)) {
        //         XmlEntities($array['AlgoSpecif']);
        //         $algo = $array['AlgoSpecif'];
        //     }
        // }


        $listAdditionnalSigner = [];
        // TODO
        /** @phpstan-ignore-next-line */
        if (array_key_exists('LstSignSup', $array) && '' != $array['LstSignSup']) {
            $listAdditionnalSigner = explode('|', $array['LstSignSup']);
        }

        $listNextSigner = [];
        // TODO
        // if (array_key_exists('CSV_' . $type_item . '_' . $num, $_SESSION)) {
        //     $listeSignataire = explode('|', $_SESSION['CSV_' . $type_item . '_' . $num]);
            
        //     if (is_array($listeSignataire) && !empty($listeSignataire)) {
        //         $array_base = null;
        //         foreach ($listeSignataire as $signataireAttendu) {
        //             $info_signat_attendu = explode(';', $signataireAttendu);
        //             $b = str_replace('.', '', sprintf('%06d', ((float) $info_signat_attendu[0]) * 100.0));
        //             $array_base[$b][] = $signataireAttendu;
        //         }
                
        //         ksort($array_base);
                
        //         foreach ($array_base as $result)
        //             foreach ($result as $signataireAttendu) {
        //                 $info_signat_attendu = explode(';', $signataireAttendu);
        //                 if (is_array($info_signat_attendu)
        //                     && count($info_signat_attendu) >= 5
        //                     && $info_signat_attendu[1] != ''
        //                 ) {
        //                     $listNextSigner[] = (object) [
        //                         'user' => $info_signat_attendu[1],
        //                         'informe' => ('N' == $info_signat_attendu[5]) ? 'false' : 'true',
        //                     ];
        //                 }
        //             }
        //     }
        // }

        
        $Wsdl = (new Wsdl(
            'Oxaproc_Signature.wsdl',
            'OXAPRC_SIGNBAP',
            $this->createPayload(
                $_SESSION['Session_Langue'],
                $_SESSION['Session_Login'],
                (array_key_exists('MODE_BACKUP', $_SESSION) && $_SESSION['MODE_BACKUP'] ?
                    $_SESSION['user_origine'] : $_SESSION['Session_Login']),
                $password,
                $signer,
                $comment,
                $listFactureId,
                null,
                $listAdditionnalSigner,
                $listNextSigner,
                $user_transfert,
                $algo
            ),
            false
        ));

        $response = new \SimpleXMLElement($Wsdl->responseData);
        if ($response->Statut != 'O') {
            throw new \Exception($response->MsgErreur);
        }
    }

//_____________________________________________________________________________
// Sub-routine

    // TODO : simplify & factorize
    /**
     * Filtre sur les factures en fonction du niveau de confidentialité des documents
     */
    protected function andWhereTypeDocConf(string $field = 'FAC_ENT.NUM_FACT') :string
    {
        /** @var \SimpleXMLElement $xml */
        $xml = simplexml_load_string($_SESSION['OXAPRC_LOGUSR_XML']);
        if (!$xml->CONFIDENTIALITE_ACTIVE) {
            return '';
        }
        return " AND NOT EXISTS (
            SELECT CA_ENTET.NO_CDE
            FROM FAC_LIG with (nolock)
            JOIN CA_ENTET with (nolock) ON CA_ENTET.NO_CDE = FAC_LIG.NUM_CDE
            JOIN TYPDOC with (nolock) 
                ON CA_ENTET.TYP_DOC = TYPDOC.TYPE 
                AND TYPDOC.NIV_CONF > ".$xml->NiveauConfidentialite."
            WHERE FAC_LIG.NUM_FACT = ".$this->quoteColumn($field)."
        )";
    }

//_____________________________________________________________________________
// Sub-routine - Wsdl
    /**
     * @param array<string> $listFactureId
     * @param array<mixed> $modifDoc
     * @param array<string> $listAdditionnalSigner
     * @param array<string> $listNextSigner
     */
    private function createPayload(
        string $lang,
        string $user,
        string $realUser,
        string $password,
        string $userSigning,
        string $comment,
        array $listFactureId,
        ?array $modifDoc = null,
        array $listAdditionnalSigner = [],
        array $listNextSigner = [],
        string $user_transfert = '',
        string $algo = ''
    ) :string {
        ob_start();
        ?>
<SigBAPIn LngUtilisation="<?=$lang?>">
    <Utilisateur><?=Wsdl::XmlEntities($user)?></Utilisateur>
    <UserConnecte><?=Wsdl::XmlEntities($realUser)?></UserConnecte>
    <MotdePasse><?=Wsdl::XmlEntities($password)?></MotdePasse>
    <Mode>S</Mode>
    <MultiFact>true</MultiFact>
    <ListeFact>
        <?php foreach ($listFactureId as $factureId) : ?>
        <Fact>
            <NumFact><?=Wsdl::XmlEntities($factureId)?></NumFact>
        </Fact>
        <?php endforeach ?>
    </ListeFact>
    <Signataire><?=Wsdl::XmlEntities($userSigning)?></Signataire>
    <Comment><?=Wsdl::XmlEntities($comment)?></Comment>

        <?php if ($modifDoc != null) {
            $this->createPayloadModifDoc($modifDoc);
        } ?>

        <?php
    // S'il s'agit d'un transfert de signature
        if (!empty($user_transfert)) : ?>
        <NvSignataire><?=Wsdl::XmlEntities($user_transfert)?></NvSignataire>
        <?php endif ?>
        <?php
    // S'il s'agit d'un transfert de signature
        if (!empty($algo)) : ?>
        <AlgoSpecif><?=$algo?></AlgoSpecif>
        <?php endif ?>
       
        <?php
    /** @phpstan-ignore-next-line */
        if (true) {
            throw new \Exception('TODO');
        }
    // Dans le cas de la confirmation
    /** @phpstan-ignore-next-line */
        if ($this->confirm == true) {
            echo '<Confirm>true</Confirm>';
        
            // // Dans le cas spécifique Boeringher si des codes comptables avaient été saisies en première instance de signature alors on les récupère
            // if (array_key_exists('SIGN_SPECIF_BOEH_INVEST', $_SESSION)) {
            //     echo $_SESSION['SIGN_SPECIF_BOEH_INVEST'];
            //     unset($_SESSION['SIGN_SPECIF_BOEH_INVEST']);
            // }
        } else {
             // Si première instance de signature
            echo '<Confirm>false</Confirm>';
        
            // // Réinitialisation de la variable de session destinée à conserver la partie signature spécifique BOEH
            // if (array_key_exists('SIGN_SPECIF_BOEH_INVEST', $_SESSION))
            //     unset($_SESSION['SIGN_SPECIF_BOEH_INVEST']);
        }

        ?>
        <?php
    // Ajout des signataires supplémentaires
        if (!empty($listAdditionnalSigner)) :?>
    <ListeAjoutSignataires>
            <?php foreach ($listAdditionnalSigner as $signer) :?>
        <NvSignataire><?=$signer?></NvSignataire>
            <?php endforeach ?>
    </ListeAjoutSignataires>
        <?php endif ?>

        <?php
     // Sinon, si des signataires ont été ajoutés sur le document à signer
        if (!empty($listNextSigner)) :?>
    <ListeSignatairesAttendus>
            <?php foreach ($listNextSigner as $signer) :?>
            <SignataireAttendu>
                <Utilisateur><?php $signer->user ?></Utilisateur>
                <Informe><?php $signer->informe ?></Informe>
            </SignataireAttendu>
            <?php endforeach ?>
    </ListeSignatairesAttendus>
        <?php endif ?>
</SigBAPIn>
        <?php
        return ob_get_clean();
    }

    /**
     * Subroutine for createPayload
     * @param array<mixed> $modifDoc
     */
    private function createPayloadModifDoc(array $modifDoc) :string
    {
        throw new \Exception('Not implemented yet');
        /*
        ?>
    TODO

$panierEntete = new PanierEntete();
$panierEntete->getEntetePanier($_SESSION['id_panier'], $_SESSION['id_user']);
<ModifDocument>true</ModifDocument>
<Document>
    <SectImp>{$panierEntete->getSI_CODE()}</SectImp>
    <CodeComp>{$panierEntete->getCDC_CODE()}</CodeComp>
    <SCptAna>{$panierEntete->getSCA_CODE()}</SCptAna>
    <CodeGest>{$panierEntete->getCG_CODE()}</CodeGest>

    $listeChampSup = '';
    $ListeCSEntete = SqlCs::rqRechCsFixe($_SESSION['id_panier'], 0)->TrouveTous());

    <?php foreach ($ListeCSEntete as & $enteteCS) :?>
        XmlEntities($enteteCS);
        $AttributCS = & SqlCs::rqGetInfoCS($code_table_entete, $enteteCS['NUM_FIX'])->Trouve1();

        if ('L' == $AttributCS['FORMAT'])
            $enteteCS['VALEUR'] = Wsdl::convertBooleenCheckboxForWsdl($enteteCS['VALEUR']);
        if ('D' == $AttributCS['FORMAT'])
            $enteteCS['VALEUR'] = convertDateSqlToFr($enteteCS['VALEUR']);

    <ChpSup>
        <CSNumFixe>{$enteteCS['NUM_FIX']}</CSNumFixe>
        <CSValeur>' . trim($enteteCS['VALEUR']) . '</CSValeur>
    </ChpSup>
    <?php endforeach ?>

    <ListChpSup>$listeChampSup</ListChpSup>
    $liste_ligne = SqlPanier::rqGetAllLignePanier($_SESSION['id_panier'])->TrouveTous();

    <ListLignes>
    <?php foreach ($liste_ligne as & $ligne_panier) : ?>
        <Ligne>
            <NumLigne>{$ligne_panier['NO_LIGNE_CA']}</NumLigne>
            <SectImp>{$ligne_panier['SI_CODE']}</SectImp>
            <CodeComp>{$ligne_panier['CDC_CODE']}</CodeComp>
            <SCptAna>{$ligne_panier['SCA_CODE']}</SCptAna>
            <CodeGest>{$ligne_panier['CG_CODE']}</CodeGest>
            <ListChpSup>
            <?php foreach ($ListeCSLigne as & $ligneCS) : ?>

                XmlEntities($ligneCS);
                $AttributCS = & SqlCs::rqGetInfoCS($code_table_ligne, $ligneCS['NUM_FIX'])->Trouve1();

                if ('L' == $AttributCS['FORMAT'])
                    $ligneCS['VALEUR'] = Wsdl::convertBooleenCheckboxForWsdl($ligneCS['VALEUR']); // Dossier 23912
                if ('D' == $AttributCS['FORMAT'])
                    $ligneCS['VALEUR'] = convertDateSqlToFr($ligneCS['VALEUR']);

                <ChpSup>
                    <CSNumFixe>{$ligneCS['NUM_FIX']}</CSNumFixe>
                    <CSValeur>' . trim($ligneCS['VALEUR']) . '</CSValeur>
                </ChpSup>
            <?php endforeach ?>
            </ListChpSup>

            // SPEC 4241 Caractéristiques complémentaires : Intégration des CC de la ligne
            $ListeCCLigne = SqlCaracteristiquesCompl::getCCDoc('PAN', $_SESSION['id_panier'], $ligne_panier['id_lig'], $_SESSION['id_user'])->TrouveTous();
            $listeCarComp = '';
            <?php if (is_array($ListeCCLigne)) :?>
            <ListCarComp>
            <?php foreach ($ListeCCLigne as $ligneCC) :?>
                    if ($ligneCC['FORMAT'] == 'L'){
                        $ligneCC['VALEUR'] = Wsdl::convertBooleenCheckboxForWsdl($ligneCC['VALEUR']);
                    }

                <CarComp>
                    <CC_ID>".$ligneCC['CC_ID']."</CC_ID>
                    <CC_FREE>".Wsdl::convertBooleenCheckboxForWsdlTrueFalse($ligneCC['CC_FREE'])."</CC_FREE>
                    <CC_DISPLAY_NUM>".$ligneCC['CC_DISPLAY_NUM']."</CC_DISPLAY_NUM>
                    <CC_IS_TITLE>".Wsdl::convertBooleenCheckboxForWsdlTrueFalse($ligneCC['CC_IS_TITLE'])."</CC_IS_TITLE>
                    <CC_NAME>".htmlspecialchars($ligneCC['NOM'])."</CC_NAME>
                    <CC_TYPE>".$ligneCC['CC_TYPE']."</CC_TYPE>
                    <CC_UPD_ONLY_RECEIPT>".Wsdl::convertBooleenCheckboxForWsdlTrueFalse($ligneCC['CC_UPD_ONLY_RECEIPT'])."</CC_UPD_ONLY_RECEIPT>
                    <CC_INVIS_RECEIPT>".Wsdl::convertBooleenCheckboxForWsdlTrueFalse($ligneCC['CC_INVIS_RECEIPT'])."</CC_INVIS_RECEIPT>
                    <CC_REQUIRED>".Wsdl::convertBooleenCheckboxForWsdlTrueFalse($ligneCC['CC_REQUIRED'])."</CC_REQUIRED>
                    <CC_PRINTED_OF>".Wsdl::convertBooleenCheckboxForWsdlTrueFalse($ligneCC['CC_PRINTED_OF'])."</CC_PRINTED_OF>
                    <CC_CALC>".Wsdl::convertBooleenCheckboxForWsdlTrueFalse($ligneCC['CC_CALC'])."</CC_CALC>
                    <CC_CALC_EXP>".htmlspecialchars($ligneCC['CC_CALC_EXP'])."</CC_CALC_EXP>
                    <CC_VALUE>".htmlspecialchars($ligneCC['VALEUR'])."</CC_VALUE>
                </CarComp>
            <?php endforeach ?>
            </ListCarComp>
            <?php endif; ?>

        </Ligne>
    <?php endforeach ?>
    </ListLignes>

    $liste_pj = SqlPanier::rqGetQueryClausePj($_SESSION['id_user'], $_SESSION['id_panier'])->TrouveTous();

    $ListPJ = '';

    <ListPJ>
    <?php foreach ($liste_pj as &$pj) :?>
        <?php if ($pj['TYP_ACH'] == '____') continue; ?>
        XmlEntities($pj);
        <PJ>
            <TypePJ>{$pj['PJ_TYPES']}</TypePJ>
            <Titre>{$pj['TITRE']}</Titre>
            <NomFichier>{$pj['nom_piece_sys']}</NomFichier>
            <NomFichierOrigine>{$pj['nom_piece_user']}</NomFichierOrigine>
            <Verrou>' . BoolWsdl($pj['VERROU']) . '</Verrou>
            <LectureSeule>' . BoolWsdl($pj['PHYSIQUE']) . '</LectureSeule>
            <ImprimerSurDoc>' . BoolWsdl($pj['OUVRABLE']) . '</ImprimerSurDoc>
            <ImprimerTitreSurDoc>' . BoolWsdl($pj['IMPRIMABL']) . '</ImprimerTitreSurDoc>
        </PJ>
    <?php endforeach ?>
    </ListPJ>
</Document>
        <?php*/
    }
}
