<?php

use DocuSign\eSign\Api\SigningGroupsApi;
use DocuSign\eSign\Model\CompositeTemplate;
use DocuSign\eSign\Model\Signer;
use DocuSign\eSign\Model\Recipients;
use DocuSign\eSign\Model\Document;
use DocuSign\eSign\Model\InlineTemplate;
use DocuSign\eSign\Model\RecipientAdditionalNotification;
use DocuSign\eSign\Model\RecipientPhoneNumber;
use DocuSign\eSign\Model\ServerTemplate;
use DocuSign\eSign\Model\SigningGroup;
use DocuSign\eSign\Model\SigningGroupInformation;
use DocuSign\eSign\Model\SigningGroupUser;

class Agro_DocuSign_EmailCompositeTemplates extends Agro_DocuSign_Email
{
    const TIPO_DOCUMENTO = 1;
    const TIPO_TEMPLATE = 2;
    const TIPO_ASSINATURA_EMAIL = 1;
    const TIPO_ASSINATURA_SMS = 5;

    private $templates = [];
    private $compositeTemplates = [];
    private $countRecipients = 0;
    private $errosTemplates = [];
    private $tipoAssinatura = null;

    /**
     * Método responsável por adicionar tanto templates quanto documentos a um envelope
     * 
     * @param stdClass $data
     *        Exemplo de $data para adicionar um template:
     *           std {
     *               tipo: Agro_DocuSign_EmailCompositeTemplates::TIPO_TEMPLATE
     *               signers[{
     *                   email: 'exemplo@agrobrasilseguros.com.br',
     *                   name: 'Exemplo Template',
     *                   roleName: 'exemplo-template',
     *                  emailNotification: null
     *               }],
     *               tipoTemplate: Agro_DocuSign_TemplateFactory::TERMO_SUB_SP
     *               }
     *           }
     * 
     *        Exemplo de $data para adicionar um documento:
     *           std {
     *               tipo: Agro_DocuSign_EmailCompositeTemplates::TIPO_DOCUMENTO
     *               signers[{
     *                   email: 'exemplo@agrobrasilseguros.com.br',
     *                   name: 'Exemplo Documento',
     *                   roleName: 'exemplo-documento',
     *                   emailNotification: null
     *               }],
     *               document{
     *               id: 'idDocumento123',
     *               name: 'Exemplo',
     *               dir: PATH_LAUDOS . '/TESTE_ASSINATURA.pdf'
     *               }
     *           }
     *
     */
    public function add(stdClass $data)
    {
        if (!isset($data->tipo)) {
            throw new Exception("Tipo do documento/template não informado.");
        }

        if ($data->tipo == self::TIPO_DOCUMENTO) {
            $this->addDocumento($data);
            return;
        }

        $this->addTemplate($data);
    }

    /**
     * Cria os signatários no padrão do Docusign.
     * Se houver template informado, realiza o depara dos campos dinâmicos.
     * 
     * @param stdClass $data
     * @param Agro_DocuSign_Template|null $template
     * @return Signer[]
     */
    private function addSignatarios(stdClass $data)
    {
        $signatarios = [];

        foreach ($data->signers as $signer) {
            $this->countRecipients++;

            if ($signer->roleName == Seguro_Model_PropostasDocusign::ROLE_NAME_SEGURADO &&
                $this->tipoAssinatura == self::TIPO_ASSINATURA_SMS) {
                
                $SMSDelivery = new RecipientAdditionalNotification();
                $SMSDelivery->setSecondaryDeliveryMethod("SMS");
            
                $signerPhone = new RecipientPhoneNumber([
                    'country_code' => '55',
                    'number' => preg_replace('([^0-9])', '', $signer->number)
                ]);

                $SMSDelivery->setPhoneNumber($signerPhone);
            
                $newSigner = new Signer([
                    'phone_number' => $signerPhone,
                    'name' => substr($signer->name, 0, 100),
                    'role_name' => $signer->roleName,
                    'recipient_id' => (string) $this->countRecipients,
                    'tabs' => !empty($signer->tabs) ? $signer->tabs : null,
                    'signing_group_id' => !empty($signer->signing_group_id) ? $signer->signing_group_id : null,
                ]);

            } else {

                $newSigner = new Signer([
                    'email' => $signer->email,
                    'name' => substr($signer->name, 0, 100),
                    'role_name' => $signer->roleName,
                    'recipient_id' => (string) $this->countRecipients,
                    'tabs' => !empty($signer->tabs) ? $signer->tabs : null,
                    'signing_group_id' => !empty($signer->signing_group_id) ? $signer->signing_group_id : null,
                    'email_notification' => !empty($signer->emailNotification) ? $signer->emailNotification : null 
                ]);
            }


            $signatarios[] = $newSigner;
        }

        return $signatarios;
    }

    /**
     * Adiciona um documento ao envelope.
     * 
     * @param stdClass $data
     */
    private function addDocumento(stdClass $data)
    {
        $signatarios = $this->addSignatarios($data);

        $recipients = new Recipients([
            'signers' => $signatarios
        ]);

        $extensao = pathinfo($data->document->dir, PATHINFO_EXTENSION);
        $documentoBytes = file_get_contents($data->document->dir);
        $documentoBase64 = base64_encode($documentoBytes);

        $document = new Document([
            'document_base64' => $documentoBase64,
            'name' => $data->document->name,
            'file_extension' => $extensao,
            'document_id' => $data->document->id
        ]);

        $this->compositeTemplates[] = new CompositeTemplate([
            'composite_template_id' => count($this->compositeTemplates) + 1,
            'inline_templates' => [
                new InlineTemplate([
                    'sequence' => "1", 
                    'recipients' => $recipients
                ])
            ],
            'document' => $document
        ]);
    }
    
    /**
     * Adiciona um template ao envelope.
     * 
     * @param stdClass $data
     */
    private function addTemplate(stdClass $data)
    {
        $template = Agro_DocuSign_TemplateFactory::get(
            $this->docuSignAuth->getApiClient(),
            $data->tipoTemplate,
            $data->parametros
        );

        $signatarios = $this->addSignatarios($data);

        $recipients = new Recipients([
            'signers' => $signatarios
        ]);


        $this->compositeTemplates[] = new CompositeTemplate([
            'composite_template_id' => count($this->compositeTemplates) + 1,
            'server_templates' => [
                new ServerTemplate([
                    'sequence' => "1", 'template_id' => $template->getId()
                ])
            ],

            'inline_templates' => [
                new InlineTemplate([
                    'sequence' => "2",
                    'recipients' => $recipients
                ])
            ]
        ]);

        if (!empty($template->getMensagemErros())) {
            $this->errosTemplates[] = $template->getMensagemErros();
        }

        $this->templates[count($this->compositeTemplates)] = $template;
    }

    protected function configurarSignatarios()
    {
        $this->envelopeDefinition->setCompositeTemplates($this->compositeTemplates);
    }

    /**
     * Retorna todos os documentos e os salva no diretório /upload_files/docusign/
     *
     * @param  string $idEnvelope
     * @return stdClass[]|array
     */
    public function getAllDocumentos(string $idEnvelope) 
    {
        $envelopeDocumentsResult = $this->envelopesApi->listDocuments(Agro_DocuSign_Auth::$docusignApiAccountId, $idEnvelope);
        $envelopeDocuments = $envelopeDocumentsResult->getEnvelopeDocuments();
        
        $documentos = [];
        foreach ($envelopeDocuments as $envelopeDocument) {

            $chave = "{$envelopeDocument->getDocumentId()}-{$idEnvelope}";
            $nome = $envelopeDocument['name'];

            if ($envelopeDocument['document_id'] == 'certificate') {
                if (!Sistema_Model_Usuarios::usuarioLogadoFuncionarioAgro()) {
                    continue;
                }

                $nome = $envelopeDocument['document_id'];
            }
            
            $dadosDocumentos = new stdClass();
            $dadosDocumentos->splFileObject = $this->getDocumento($idEnvelope, $envelopeDocument->getDocumentId());
            $dadosDocumentos->nome = "{$nome}.pdf";
            $documentos[$chave] = $dadosDocumentos;
        }

        return $documentos;
    }

    public function test()
    {
        foreach ($this->templates as $idDocument => $template) {
            $template->deParaCampos($idDocument);
        }
    }

    public function createGroupSiginers($emailsAssinatura)
    {
        $signingGroupsApi = new SigningGroupsApi($this->docuSignAuth->getApiClient()); 
        $listSigningGroups = $signingGroupsApi->callList(Agro_DocuSign_Auth::$docusignApiAccountId);

        $signingGroupId = null;

        if (count($listSigningGroups->getGroups()) >= 30) {
            $signingGroupId = $listSigningGroups->getGroups()[0]->getSigningGroupId();
        }

        $groupName = "orcamento_" . time();

        $signingGroup = new SigningGroup();
        $signingGroup->setSigningGroupId($signingGroupId);
        $signingGroup->setGroupName($groupName);
        $signingGroup->setGroupType('sharedSigningGroup');
        $signingGroup->setUsers([
            new SigningGroupUser([
                'email' => $emailsAssinatura['ds_email_corretor'],
                'user_name' => $emailsAssinatura['ds_nome_corretor']
            ]),
            new SigningGroupUser([
                'email' => $emailsAssinatura['ds_email_segurado'],
                'user_name' =>  $emailsAssinatura['ds_nome_proponente']
            ])
        ]);

        $signingGroupInformation = new SigningGroupInformation();
        $signingGroupInformation->setGroups([$signingGroup]);

        if (!empty($signingGroupId)) {

            $retorno = $signingGroupsApi->deleteList(Agro_DocuSign_Auth::$docusignApiAccountId, $signingGroupInformation);

            if ($retorno->getGroups()[0]->getErrorDetails()) {
                $errorCode = $retorno->getGroups()[0]->getErrorDetails()->getErrorCode();
                $message = $retorno->getGroups()[0]->getErrorDetails()->getMessage();
                throw new Exception("Error ao excluir grupo de assinatura. \n\n{$errorCode} - {$message}");
            }
        }

        $retorno = $signingGroupsApi->createList(Agro_DocuSign_Auth::$docusignApiAccountId, $signingGroupInformation);
        
        if ($retorno->getGroups()[0]->getErrorDetails()) {
            $errorCode = $retorno->getGroups()[0]->getErrorDetails()->getErrorCode();
            $message = $retorno->getGroups()[0]->getErrorDetails()->getMessage();
            throw new Exception("Error ao criar grupo de assinatura. \n\n{$errorCode} - {$message}");
        }

        return $retorno->getGroups()[0]->getSigningGroupId();
    }

    public function enviar($isRascunho = false): ?string
    {
        if (!empty($this->errosTemplates)) {
            throw new Exception("Os seguintes erros foram encontrados: <br>" . implode("<br><br>", $this->errosTemplates));
        }

        $idEnvelope = parent::enviar($isRascunho);
        
        foreach ($this->templates as $idDocument => $template) {
            if (!empty($template->getTabsByDocument()->getPrefillTabs())) {
                
                $documentTabs = $this->envelopesApi->getDocumentTabs(Agro_DocuSign_Auth::$docusignApiAccountId, (string)$idDocument, $idEnvelope);
                $template->setTabs($documentTabs);
                $this->envelopesApi->updateDocumentTabs(Agro_DocuSign_Auth::$docusignApiAccountId, (string) $idDocument, $idEnvelope, $template->deParaCampos($idDocument));
            }
        }

        try {
            // Altera de created para sent (de rascunho para enviado)
            $envelope = $this->envelopesApi->getEnvelope(Agro_DocuSign_Auth::$docusignApiAccountId, $idEnvelope);

            $envelope->setStatus(Seguro_Model_PropostasDocusign::STATUS_SENT);
            $envelope->setPurgeState(null);
            $this->envelopesApi->update(Agro_DocuSign_Auth::$docusignApiAccountId, $idEnvelope, $envelope);
        } catch (ApiException $e) {
            throw new Exception("Erro ao alterar envelope de rascunho para enviado. \n{$e->getMessage()}");
        }

        return $idEnvelope;
    }

    /**
     * Define o tipo de assinatura (E-mail ou SMS)
     * 
     * @param int $tipoAssinatura
     */
    public function setTipoAssinatura(int $tipoAssinatura): void
    {
        $this->tipoAssinatura = $tipoAssinatura;
    }

    /**
     * Retorna o tipo de assinatura
     * 
     * @return int
     */
    public function getTipoAssinatura(): ?int
    {
        return $this->tipoAssinatura;
    }
}
