<?php
namespace Modules\Signature\Controller;

use Entity\Model\FactEnt;
use Entity\Model\Hastutil;
use Entity\Model\Incident;
use Entity\Model\Paravrac;
use Entity\Model\SigBap;
use GuzzleHttp\Psr7\Response;
use Helpers\Outil\Sql;
use Helpers\Session\InitSession;
use Helpers\Session\Session;
use Helpers\Trad\Trad;
use Helpers\Validator\Validator;
use Modules\Ajax\Repository\Signataires;
use Modules\GlobalApplication\Repository\Signature;
use Modules\Signature\MenuContextuel\SignatureBapMenuContextuel;
use Modules\Signature\Repository\BaPSignRepository;
use Modules\Suivi\Repository\SuiviFacRepo;
use Modules\Suivi\Service\SuiviService;
use Skeleton\Controller\Controller;

class SignatureBapController extends AbsSignatureController
{
    /**
     * Because of INCF_USER which is a zoom, we cannot use popupSignatureAction, this replace it
     * @return string|Response
     */
    public function formRefusSignatureAction()
    {
        $mode       = 'R';
        $signataire = $this->request->getAttribute('signataire');
        $post       = $this->request->getParsedBody();
        $trad       = $this->getTranslationService();

        $listEntityId = explode('|', $post['listeMultiSignature']);
        // Failsafe
        if (empty($listEntityId[0])) {
            return new Response(400, [], $trad->t('Vous devez sélectionner au moins une ligne.'));
        }

        foreach ($listEntityId as $id) {
            if (!is_numeric($id)) {
                throw new \Exception('invalid facture id "' . $id . '"');
            }
        }

        if (count($listEntityId) == 1) {
            $commentaireSignataire = ($this->getRepository($this->pdo))->getCommentaireSignataire((int) $listEntityId[0]);
        }

        $facture = (new FactEnt($this->pdo))->find(['NUM_FACT' => $listEntityId[0]]);

        return $this->renderer->render('@signature/Facture/refusSignBap', [
            'factureId'             => (int) $listEntityId[0], // TODO : handle multiple facture
            'facture'               => $facture,
            'commentaireSignataire' => $commentaireSignataire ?? [],
            'mode'                  => $mode,
            'post'                  => $post,
            'pathSignature'         => $this->getSignerPath($mode, $signataire),
            'config'                => [
                'OBLIG_COMMENT' => $this->isCommentRequired($mode),
                'MDP_ACTIF'     => $this->isPasswordActif(),
            ],
            'workflow'              => true,
            'asynchrone'            => true,

            'listChoixIncidentType' => array_column(
                (new Incident($this->pdo))->findAll(['CODE_CAT' => 'LITFACT']),
                'LIBELLE',
                'COD_INC',
            ),
        ]);
    }

    public function listeDocAction(): string
    {
        Session::setSessionTypeMenuTop();

        $post       = $this->request->getParsedBody();
        $trad       = $this->getTranslationService();
        $signataire = $this->request->getAttribute('signataire');

        $paginator = new \Helpers\Pagination\PaginatorGestion();
        $paginator->generate(0, 'NUM_FACT');

        $listFacture = (new BaPSignRepository($this->pdo))->listToBeSign($signataire, $post);

        $suiviFacRepo = new SuiviFacRepo($this->pdo, $this->router, $trad);

        $menuContextuel = new SignatureBapMenuContextuel($this->pdo, $this->router, $trad, $signataire);
        foreach ($listFacture as &$facture) {
            $ecartLigne = (new SuiviService($this->pdo, $trad))->getValeursEcartLigneFac($suiviFacRepo, $facture['NUM_FACT']);
            $facture    = array_merge($facture, $ecartLigne);

            $facture['menuContextuel'] = $menuContextuel->generate($facture);
            // Format bool
            $facture['AFF_TMP'] = Sql::toBool($facture['AFF_TMP']);
            $facture['LITIGE']  = Sql::toBool($facture['LITIGE']);
        }
        unset($facture);

        \Helpers\Ariane\Ariane::generate($signataire ? 1 : 0, $trad->t('Signature'), [], $paginator->getNbrArticle());
        $listeType = ['F' => $trad->t('Facture'), 'A' => $trad->t('Avoir'), 'C' => $trad->t('Acompte')];

        return $this->renderer->render('@signature/Facture/listeDoc', [
            'parametrage' => [
                'SIGN_BAP_INTERDITE_SI_LITIGE' => Sql::paravrac($this->pdo, 'PARAMINIFA', 'SIGN_BAP_INTERDITE_SI_LITIGE') == 'O',
            ],
            'menuActive'  => 'eproc',
            'post'        => $post,
            'listFacture' => $listFacture,
            'typePreaff'  => (new Paravrac($this->pdo))->getTypePreaffectation(),
            'pagination'  => \Helpers\Pagination\PaginatorGestion::getInfoPagination(),
            'signataire'  => $signataire,
            'delegAbs'    => (new Signature($this->pdo))->countDelegABS()['count'] ?? 0,
            'listeType'   => $listeType,
        ]);
    }

    public function ajoutSignataireAction(): string
    {
        $numFact    = $this->request->getAttribute('idDoc');
        $post       = $this->request->getParsedBody();
        $trad       = $this->getTranslationService();
        $repo_Signa = new BaPSignRepository($this->pdo);

        $signaList = [];

        // on récupère la liste actuelle des signataires, pour actualiser les numéros d'ordre
        $signaList = \array_column($repo_Signa->listeSignat($numFact), null, 'SIGNAT');

        // seul le premier signataire attendu a le flag 'SIGNABLE' à vrai
        $signable                = false;
        $firstSignableRegistered = false;
        $previousSignatoryId     = 0;
        $order                   = 1;
        $newSignatory            = false;

        if ($post) {
            (new SigBap($this->pdo))->delete(['NO_FAC' => $numFact]);
            foreach ($post as $key => $value) {
                $tblKey = explode('_', $key);
                if (count($tblKey) == 2) {
                    if ($previousSignatoryId != $tblKey[0]) {
                        if ($post[$tblKey[0] . '_5'] == 'N' && !$signable) {
                            $signable = true;
                        }
                        if ($post[$tblKey[0] . '_6'] == 'N') {
                            $newSignatory = true;
                            $array        = [
                                'SIGNAT'   => $post[$tblKey[0] . '_3'],
                                'NO_FAC'   => $numFact,
                                'DTE_MISE' => $firstSignableRegistered ? '00000000' : date('Ymd'),
                                'ORDRE'    => $order,
                                'SIGNABLE' => $firstSignableRegistered ? false : $signable,
                                'INFORME'  => ($post[$tblKey[0] . '_5'] == 'O'),
                                'FAROLES'  => $post[$tblKey[0] . '_2'],
                                'BAP_BAS'  => true, // si on peut ajouter un signataire, c'est que le bon à payer est "bon à signer"
                            ];
                        } else {
                            $array = [
                                'SIGNAT'     => $signaList[$post[$tblKey[0] . '_3']]['SIGNAT'],
                                'NO_FAC'     => $numFact,
                                'DTE_MISE'   => $firstSignableRegistered ? '00000000' : date('Ymd'),
                                'ORDRE'      => $order,
                                'SIGNABLE'   => $firstSignableRegistered ? false : $signable,
                                'INFORME'    => Sql::toBool($signaList[$post[$tblKey[0] . '_3']]['INFORME']),
                                'FAROLES'    => $signaList[$post[$tblKey[0] . '_3']]['FAROLES'],
                                'TSTAMP_MOB' => $signaList[$post[$tblKey[0] . '_3']]['TSTAMP_MOB'],
                                'BAP_BAS'    => Sql::toBool($signaList[$post[$tblKey[0] . '_3']]['BAP_BAS']),
                            ];
                        }
                        $order++;

                        (new SigBap($this->pdo))->insert($array);
                    }
                    $previousSignatoryId     = $tblKey[0];
                    $firstSignableRegistered = $signable;
                }
            }

            $message = $trad->t('Aucun signataire ajouté.');
            if ($newSignatory) {
                $message = $trad->t('Vos signataires ont été ajoutés.');
            }
            return $this->renderer->render('@popup-erreur/confirmationGestion', [
                'message'    => $message,
                'reload'     => true,
                'iconePopup' => 'information',
            ]);
        }

        $signataires = new \Modules\Ajax\Repository\Signataires($this->pdo);
        $signataire  = $signataires->signatairesBAP($numFact);

        foreach ($signataire as $key => $value) {
            $listeSignataires[$value['CODE']] = $value['NOM'];
        }

        $Signa = $repo_Signa->listeSignat($numFact);

        $listeSigna = '';
        foreach ($Signa as $value) {
            if ($listeSigna) {
                $listeSigna .= '|' . $value['ORDRE'] . ';;' . $value['FAROLES'] . ';' . $value['SIGNAT'] . ';' . $value['NOM'] . ';' . (Sql::boolSql($value['INFORME']) ? 'O' : 'N') . ';O;';
            } else {
                $listeSigna .= $value['ORDRE'] . ';;' . $value['FAROLES'] . ';' . $value['SIGNAT'] . ';' . $value['NOM'] . ';' . (Sql::boolSql($value['INFORME']) ? 'O' : 'N') . ';O;';
            }
        }
        $erreurValid['AlgoSpecif'] = $listeSigna;

        $droits['ajoutSignataire']       = \Helpers\Outil\Roles::droitsUtilisateur($this->pdo, 'HA_SE_AJSI');
        $droits['suppressionSignataire'] = \Helpers\Outil\Roles::droitsUtilisateur($this->pdo, 'HA_SE_SUSI');

        return $this->renderer->render('@popup-erreur/signataireXml', [
            'listeTypeRole'    => ['N' => $trad->t('Signataire'), 'O' => $trad->t('Informé')],
            'listeSignataires' => $listeSignataires ?? [],
            'ErreurValid'      => $erreurValid,
            'pathValidation'   => $this->router->generateUri('Signature.SignatureBap.ajoutSignataire', ['idDoc' => $numFact]),
            'droits'           => $droits,
        ]);
    }

    //_____________________________________________________________________________
    // Abstract AbsSignatureController

    /**
     * @param string $mode
     * @param \Helpers\Validator\Validator $validator
     * @param array<mixed> $post
     * @return array<mixed>
     */
    protected function signerValidation(
        string $mode,
        Validator $validator,
        array $post,
    ): array {
        if ($mode == 'R'/* Refus */) {
            $trad = $this->getTranslationService();
            // TODO : validate $post['Incident']['CODE']
            $validator->zoomListe(
                'Ajax.liste.utilisateur',
                $post['INCF_USER'],
                $trad->t('Responsable du litige'),
                $this->pdo,
            );

            $validator->isStringAvecEspace(
                $trad->t('Contact fournisseur'),
                $post['ListContactFournisseur'],
                0,
                500,
            );
            $listContactFournisseur = array_filter(explode(',', $post['ListContactFournisseur']));
            foreach ($listContactFournisseur as &$item) {
                $validator->adresseMail($trad->t('Contact fournisseur'), $item);
            }
            unset($item);
            $post['ListContactFournisseur'] = $listContactFournisseur;
        }

        return parent::signerValidation($mode, $validator, $post);
    }

    /**
     * Undocumented function
     *
     * @param boolean $confirm
     * @param string $mode
     * @param array<mixed> $listEntityId
     * @param string $password
     * @param string|null $message
     * @param string|null $deleg
     * @param array<mixed> $post
     * @return \SimpleXMLElement
     */
    protected function processSignature(
        bool $confirm,
        string $mode,
        array $listEntityId,
        array $post,
        ?string $password = null,
        ?string $message = null,
        ?string $deleg = null,
    ): \SimpleXMLElement {
        $signature = new \Modules\Facture\WebService\GestionFacture();
        $signature = $signature->signatureMultiFac(
            $password,
            $mode,
            $deleg ?? $_SESSION['Session_Login'],
            $listEntityId,
            $confirm,
            $message ?? '',
            $post,
        );
        return new \SimpleXMLElement($signature->responseData);
    }


    /**
     * @param array<string|int> $listEntityId
     */
    protected function handleSignatureSuccess(string $mode, array $listEntityId): Response
    {
        // Case : not a refus -> handle as usual
        if ($mode == 'S') {
            return parent::handleSignatureSuccess($mode, $listEntityId);
        }

        //_________________
        // Since form refus cannot be inside a popup we use popupRefusSignBapSuccess to show success (and force the user to do an arianePop)

        $trad = $this->getTranslationService();

        $this->refreshSessionCount($this->pdo);

        return $this->createJsonResponse([
            'type'     => 'popup',
            'title'    => $trad->t('Refus réussi'),
            'bodyHtml' => $this->renderer->render('@signature/Facture/popupRefusSignBapSuccess', [
                'message' => join('<br>', array_map(function ($commandId) use ($trad) {
                    return Trad::strBuild(
                        $trad->t('@1@ n°@2@ a été @3@ avec succès.'),
                        ucfirst($this->getLabelTheEntity()),
                        $commandId,
                        $trad->t('refusée'),
                    );
                }, $listEntityId)),
            ]),
            'class'    => 'modal_small',
        ]);
    }


    protected function modifEtSigner(string $idDoc, string $signataire, $arraySign): \SimpleXMLElement
    {
        $value = '';
        return new \SimpleXMLElement($value);
    }

    protected function changementSignataire(string $idDoc, string $password, string $newSig): \SimpleXMLElement
    {
        $signature = new \Modules\Facture\WebService\GestionFacture();
        $signature = $signature->signatureFacture([
            'MotdePasse'   => $password,
            'Mode'         => 'M',
            'NumFact'      => $idDoc,
            'NvSignataire' => $newSig,
            'Signataire'   => $_SESSION['Session_Login'],
            'Confirm'      => 'false',
        ]);

        return new \SimpleXMLElement($signature->responseData);
    }

    /**
     * @param string $mode
     * @param string|null $signataire
     * @return string
     */
    protected function getPopupSignaturePath(string $mode, $signataire = ''): string
    {
        return $this->router->generateUri(
            'Signature.SignatureBap.popupSignature',
            array_merge(['mode' => $mode], $signataire ? ['signataire' => $signataire] : []),
        );
    }

    /**
     * @param string $mode
     * @param string|null $signataire
     * @return string
     */
    protected function getConfirmSignaturePath(string $mode, $signataire = ''): string
    {
        return $this->router->generateUri(
            'Signature.SignatureBap.confirmationSignature',
            array_merge(['mode' => $mode], $signataire ? ['signataire' => $signataire] : []),
        );
    }

    /**
     * @param string|null $signataire
     */
    protected function getSignerPath(string $mode, $signataire = ''): string
    {
        return $this->router->generateUri(
            'Signature.SignatureBap.signer',
            array_merge(['mode' => $mode], $signataire ? ['signataire' => $signataire] : []),
        );
    }

    /**
     * @param string $mode
     * @param string $signataire
     * @return string
     */
    protected function getAsynchronePath(string $mode, ?string $signataire = null): string
    {
        return $this->router->generateUri(
            'Signature.SignatureBap.asynchSignature',
            array_merge(['mode' => $mode], $signataire ? ['signataire' => $signataire] : []),
        );
    }

    /**
     * @param string $signataire
     * @return string
     */
    protected function getListePath(?string $signataire = null): string
    {
        return $this->router->generateUri(
            'Signature.SignatureBap.listeDoc',
            $signataire ? ['signataire' => $signataire] : []
        );
    }

    protected function getChangementSignatairePath(string $idDoc): string
    {
        return $this->router->generateUri(
            'Signature.SignatureBap.changementSignataire',
            ['idDoc' => $idDoc],
        );
    }

    protected function getXmlTagKey(): string
    {
        return 'Fact';
    }

    protected function getLabelTheEntity(): string
    {
        $trad = $this->getTranslationService();
        return $trad->t('la facture');
    }

    protected function getLabelEntity(): string
    {
        $trad = $this->getTranslationService();
        return $trad->t('facture');
    }

    protected function getTagHastutil(): string
    {
        return 'SIG_BAP';
    }

    /**
     * @return BaPSignRepository
     */
    protected function getRepository(\PDO $pdo)
    {
        return new BaPSignRepository($pdo);
    }

    protected function refreshSessionCount(\PDO $pdo): void
    {
        InitSession::initSigFacture($pdo, true);
        InitSession::countDeleg($pdo, true);
    }
}
