<?php

use PhpAmqpLib\Message\AMQPMessage;

require_once __DIR__ . '/../../../../vendor/autoload.php';
require_once 'Zend/Loader/Autoloader.php';
$loader = Zend_Loader_Autoloader::getInstance();
require_once __DIR__ . '/../RpcServerBase.php';

class Agro_RabbitMQ_RelacionarHabilitacoes_RpcServer extends Agro_Rabbitmq_RpcServerBase
{
    public $db;
    public $client = null;
    public $header = null;
    public $response = null;
    public $result = null;

    private $idUsuarioCorretor = null;
    private $idProduto = null;
    private $idEstado = null;
    private $idMunicipio = null;
    private $idUsuarioSolicitante = null;
    private $errors = [];
    private $hashSolicitacao = "";
    private $limparHabilitacoes = true;

    public function __construct(string $func, string $env, string $nomeFila)
    {
        parent::__construct($func, $env);
        $this->nomeFila = $nomeFila;

        $porta = (
            array_key_exists(
                'resources.db.params.port',$this->settings[$this->env]
            )?
            $this->settings[$this->env]['resources.db.params.port']
            :'5432'
        );
        $conexao = [
            'host' => $this->settings[$this->env]['resources.db.params.host'],
            'port' => $porta,
            'dbname' => $this->settings[$this->env]['resources.db.params.dbname'],
            'username' => $this->settings[$this->env]['resources.db.params.username'],
            'password' => $this->settings[$this->env]['resources.db.params.password'],
        ];

        $adapter = Zend_Db::factory('PDO_PGSQL', $conexao);
        Zend_Db_Table_Abstract::setDefaultAdapter($adapter);
        $this->db = Zend_Db_Table::getDefaultAdapter();
    }

    public function process(AMQPMessage $msg) {
        
        echo "[SERVER] - process: begin\n";

        $payload = json_decode($msg->getBody(), true);
       
        $this->{$this->func}($payload);

        $msg->get('channel')->basic_ack(
            $msg->get('delivery_tag'), 1
        );
        echo "[SERVER] - process: end\n";
    }

    public function run($params)
    {
        echo "[SERVER] - run: begin\n";
        try {
            $this->db->beginTransaction();

            $this->hashSolicitacao = !empty($params['data']['hash_solicitacao']) ? $params['data']['hash_solicitacao'] : hash('sha256', uniqid(mt_rand(), true));
            $this->idUsuarioSolicitante = $params['id_usuario'];
            $this->idUsuarioCorretor = $params['data']['id_usuario_corretor'];
            $this->idProduto = $params['data']['id_produto'];
            $this->limparHabilitacoes = $params['data']['limpar_habilitacoes'];
            $idUsuarioPreposto = $params['data']['id_usuario_preposto'];
            $idUsuario = !empty($idUsuarioPreposto) ? $idUsuarioPreposto : $this->idUsuarioCorretor;

            if ($params['data']['habilitar']) {
                if ($params['data']['incluir_corretor']) {
                    $this->salvarHabilitacoes($idUsuario, $params['data']['estados']);
                }

                foreach ($params['data']['prepostos'] as $preposto) {
                    $this->idEstado = $this->idMunicipio = null;
                    $this->salvarHabilitacoes($preposto['id_usuario'], $params['data']['estados']);
                }
            } else {
                if ($params['data']['incluir_corretor']) {
                    $this->removerHabilitacoes($idUsuario, $params['data']['estados']);
                }

                foreach ($params['data']['prepostos'] as $preposto) {
                    $this->idEstado = $this->idMunicipio = null;
                    $this->removerHabilitacoes($preposto['id_usuario'], $params['data']['estados']);
                }
            }

            $this->db->commit();
        
            echo "[SERVER] - run: end\n";
        } catch (\Throwable $th) {
            $this->db->rollback();

            $mensagem = $th->getMessage();
            echo "[SERVER] - run: error\n";
            echo "[SERVER] - {$mensagem}\n";
            $hash = "{$this->idUsuarioCorretor}#{$this->idProduto}#{$this->idEstado}#{$this->idMunicipio}";
            $this->errors[$this->hashSolicitacao][$hash] = $mensagem;
        }

        if ($params['data']['enviar_email_conclusao']) {
            $this->enviarEmailConclusao($params['data']['nome_arquivo']);
        }
    }

    private function removerHabilitacoes(int $idUsuario, array $estados): void
    {
        foreach ($estados as $idEstado => $estado) {
            $this->idEstado = $idEstado;
            $this->removerHabilitacoesMunicipios($idUsuario, $idEstado, $estado['municipios']);
            
            $totalMunicipiosEstado = $this->getTotalMunicipiosHabilitados($idUsuario, $idEstado);
            if (empty($totalMunicipiosEstado) || empty($estado['municipios'])) {
                $this->limparHabilitacoesUsuarioProduto($idUsuario, $idEstado);
            }
        }
    }

    private function getTotalMunicipiosHabilitados(int $idUsuario, int $idEstado): int
    {
        $where = [
            "ph.id_produto = {$this->idProduto}",
            "ph.id_usuario = {$idUsuario}",
            "ph.id_estado = {$idEstado}",
        ];

        $where = implode(" AND ", $where);

        $sql  = " SELECT count(phm.id_municipio) as total ";
        $sql .= "   FROM produto.produtos_habilitacoes ph ";
        $sql .= "   JOIN produto.produtos_habilitacoes_municipios phm ON phm.id_produtos_habilitacoes = ph.id ";
        $sql .= "  WHERE {$where}" ;
        $sql .= "  GROUP BY ph.id ";

        return $this->db->fetchOne($sql);
    }

    private function getIdHabilitacoes(int $idUsuario, ?int $idEstado = null): array
    {
        $where = [
            "ph.id_produto = {$this->idProduto}",
            "ph.id_usuario = {$idUsuario}",
        ];

        if (!empty($idEstado)) {
            $where[] = "ph.id_estado = {$idEstado}";
        }

        $where = implode(" AND ", $where);
        
        $sql  = " SELECT ph.id ";
        $sql .= "   FROM produto.produtos_habilitacoes ph ";
        $sql .= "  WHERE {$where}" ;
        $sql .= "  GROUP BY ph.id ";
        return $this->db->fetchAll($sql);
    }

    private function limparHabilitacoesUsuarioProduto(int $idUsuario, ?int $idEstado = null): void
    {
        $idProdutoHabilitacoes = $this->getIdHabilitacoes($idUsuario, $idEstado);

        if (!empty($idProdutoHabilitacoes)) {
            $this->db->delete('produto.produtos_habilitacoes_municipios', ["id_produtos_habilitacoes IN (?)" => $idProdutoHabilitacoes]);
            $this->db->delete('produto.produtos_habilitacoes', ["id IN (?)" => $idProdutoHabilitacoes]);
        }
    }

    private function removerHabilitacoesMunicipios(int $idUsuario, int $idEstado, ?array $municipios)
    {
        $idProdutoHabilitacoes = $this->getIdHabilitacoes($idUsuario, $idEstado);

        if (empty($idProdutoHabilitacoes)) {
            return;
        }

        $municipios = implode(", ", $municipios);
        $where = ["id_produtos_habilitacoes IN (?)" => $idProdutoHabilitacoes];

        if (!empty($municipios)) {
            $where["id_municipio IN (?)"] = $municipios;
        }
        $this->db->delete(
            'produto.produtos_habilitacoes_municipios',
            $where
        );
    }

    private function salvarHabilitacoes(int $idUsuario, array $estados): void
    {
        if ($this->limparHabilitacoes) {
            $this->limparHabilitacoesUsuarioProduto($idUsuario);
        }

        foreach ($estados as $idEstado => $estado) {

            $this->idEstado = $idEstado;
            $idProdutoHabilitacao = $this->salvarHabilitacoesEstado($idUsuario, $idEstado);

            if (count($estado['municipios']) == $estado['total_municipios_estado']) {
                continue;
            }

            if (!$this->limparHabilitacoes) {
                $this->removerHabilitacoesMunicipios($idUsuario, $idEstado, $estado['municipios']);
            }

            $this->salvarHabilitacoesMunicipios($idUsuario, $idProdutoHabilitacao, $estado['municipios']);
        }
    }

    private function salvarHabilitacoesEstado(int $idUsuario, int $idEstado): int
    {
        $habilitacoes = $this->getIdHabilitacoes($idUsuario, $idEstado);

        if (empty($habilitacoes)) {
            $this->db->insert("produto.produtos_habilitacoes", [
                'id_usuario' => $idUsuario,
                'id_produto' => $this->idProduto,
                'id_estado' => $idEstado,
            ]);

            $idProdutoHabilitacao = $this->db->lastInsertId();
        } else {
            $idProdutoHabilitacao = $habilitacoes[0]['id'];
        }

        if (empty($idProdutoHabilitacao)) {
            throw new Exception("Erro ao incluir a habilitação do produto para o estado {$idEstado} e usuário do sublogin{$idUsuario}.");
        }

        return $idProdutoHabilitacao;
    }

    private function salvarHabilitacoesMunicipios(int $idUsuario, int $idProdutoHabilitacao, array $municipios): void
    {
        foreach ($municipios as $idMunicipio) {
            $this->idMunicipio = $idMunicipio;

            $this->db->insert("produto.produtos_habilitacoes_municipios", [
                'id_produtos_habilitacoes' => $idProdutoHabilitacao,
                'id_municipio' => $idMunicipio,
            ]);

            $idProdutoHabilitacaoMunicipio = $this->db->lastInsertId();

            if (!$idProdutoHabilitacaoMunicipio) {
                throw new Exception("Erro ao incluir a habilitação do produto {$this->idProduto} para o município {$idMunicipio} e usuário do sublogin {$idUsuario}.");
            }
        }
    }

    /**
     * Retorna o e-mail do funcionário que adicionou o processamento a fila
     *
     * @return string
     */
    private function getEmailFuncionario(): string
    {
        $email = $this->db->fetchOne("
            SELECT ds_email as email
            FROM sistema.funcionarios
            WHERE id_usuario = {$this->idUsuarioSolicitante}
        ");

        if (empty($email)) {
            throw new Exception("Não foi possível buscar o e-mail do usuário {$this->idUsuarioSolicitante} solicitante.");
        }

        if (!FILTER_VAR($email, FILTER_VALIDATE_EMAIL)) {
            throw new Exception('Endereço de email do corretor inválido.');
        }

        return $email;
    }

    /**
     * Busca o nome abreviado do produto
     *
     * @return string
     */
    private function getNomeProduto(): string
    {
        $nome = $this->db->fetchOne("
            SELECT ds_nome_abreviado as nome
            FROM produto.produtos 
            WHERE id = {$this->idProduto}
        ");

        if (empty($nome)) {
            throw new Exception("Não foi possível buscar o nome do produto {$this->idProduto}");
        }

        return $nome;
    }

    /**
     * Busca o nome fantasia do corretor
     *
     * @return string
     */
    private function getNomeCorretor(): string
    {
        $nome = $this->db->fetchOne("
            SELECT ds_nome_fantasia as nome
            FROM sistema.corretores 
            WHERE id_usuario = {$this->idUsuarioCorretor}
        ");

        if (empty($nome)) {
            throw new Exception("Não foi possível buscar o nome do corretor {$this->idUsuarioCorretor}");
        }

        return $nome;
    }
    
    /**
    * Envia o e-mail da conclusão do procedimento para um corretor responsável.
    */
    private function enviarEmailConclusao(?string $nomeArquivo = null): void
    {
        $emailUsuarioSolicitante = $this->getEmailFuncionario();
        $nomeProduto = $this->getNomeProduto();
        $nomeCorretor = $this->getNomeCorretor();
        $emails = [$this->env == 'production' ? $emailUsuarioSolicitante : 'andre.mello@agrobrasilseguros.com.br'];

        $corpo = " Prezado, <br><br>";

        if (!empty($this->errors[$this->hashSolicitacao])) {

            $emails[] = 'andre.mello@agrobrasilseguros.com.br';
            if ($this->env == 'production') {
                $emails[] = "ti@agrobrasilseguros.com.br";
            }
            
            $assunto = "[RabbitMQ][RelacionarHabilitacoes] - Erro ao Processo de Habilitação de Sublogins";
            $corpo .= "Houveram alguns erros durante o processamento";
            $corpo .= !empty($nomeArquivo) ? " do arquivo <b>'{$nomeArquivo}'</b>:" : " do corretor {$nomeCorretor} e seus sublogins para o produto {$nomeProduto}:";

            $arraykeys = array_keys($this->errors[$this->hashSolicitacao]);
            foreach ($arraykeys as $hash) {
                $dados = explode("#", $hash);
                $corpo .= "<br> - Não foi possível processar o corretor {$dados[0]} e seus sublogins para o produto {$dados[1]}";
                
                if (!empty($dados[2])) {
                    $corpo .= ", para o estado {$dados[2]}";
                }
                
                if (!empty($dados[3])) {
                    $corpo .= ", para o município {$dados[3]}";
                }

                $corpo .= ";";
            }

            $corpo .= "<br><br>Tente novamente e caso o problema persista, entre em contato.<br><br>";
            unset($this->errors[$this->hashSolicitacao]);
        } else {
            $assunto = "[RabbitMQ][RelacionarHabilitacoes] - Conclusão do Processo de Habilitação de Sublogins";

            if (!empty($nomeArquivo)) {
                $corpo .= "O processo de habilitação do arquivo importado <b>'{$nomeArquivo}'</b> foi concluído com sucesso!<br><br>";
            } else {
                $corpo .= "O processo de habilitação do corretor <b>{$nomeCorretor}</b> e seus sublogins para o produto <b>{$nomeProduto}</b> foi concluído com sucesso!<br><br>";
            }
        }

        $corpo .= "Acesse o sistema Agronet 2.0 através do endereço: <a href='http://agronet.agrobrasilseguros.com.br/'>http://agronet.agrobrasilseguros.com.br/</a><br>";
        $corpo .= "ATENÇÃO: esta é uma mensagem automática. Por favor, não responda. Se deseja entrar em contato conosco, escreva para atendimento@agrobrasilseguros.com.br <br><br>";

        $this->enviarEmail($emails, $assunto, $corpo, true);
    }

    /**
     * Envia o e-mail
     *
     * @param array $emails
     * @param string $assunto
     * @param string $corpo
     * @param bool $imprimirRodape
     */
    private function enviarEmail(array $emails, string $assunto, string $corpo, bool $imprimirRodape = false): void
    {
        try {
            $transport = new Zend_Mail_Transport_Smtp($this->settings[$this->env]['constants.MAIL_SMTP'], $this->mailSettings);
            $mail = new Zend_Mail('UTF-8');

            if ($imprimirRodape) {

                $filename = __DIR__ . '/../../../../agronet/resources/imagens/assinatura_email_tecnica.png';
                $anexo = $mail->createAttachment(file_get_contents($filename));
                $anexo->type = 'image/png';
                $anexo->disposition = Zend_Mime::DISPOSITION_INLINE;
                $anexo->encoding = Zend_Mime::ENCODING_BASE64;
                $anexo->id = 'cid' . md5_file($filename);

                $corpo .= "<img src=\"cid:{$anexo->id}\" height=\"102\" width=\"480\" />";

                $corpo .= "<br>";
                $corpo .= "<span style=\"color: grey; margin: 0!important;  font-family: Verdana; font-size: .5em; text-align: left; display: block;\"> ";
                $corpo .= "<font face='webdings' style=\"color: darkgreen\">i</font> ";
                $corpo .= "<span style=\"color: darkblue\"> Este e-mail, inclusive anexos, podem conter informações confidenciais de propriedade exclusiva da AgroBrasil Seguros, ";
                $corpo .= "<br />não devendo ser utilizado, copiado ou revelado sem prévia autorização.</span> This e-mail, including attachments, is intended<br /> for ";
                $corpo .= "the person(s) or company named and may contain confidential and/or legally privileged information. Unauthorized<br /> disclosure, ";
                $corpo .= "copying or use of this information may be unlawful and is prohibited. If you are not the intended recipient,<br /> please delete this ";
                $corpo .= "message and notify the sender. ";
                $corpo .= "</span> ";
                $corpo .= "<br /> ";
                $corpo .= "<span style=\"color: grey; margin: 0!important; font-family: Verdana; font-size: .5em; text-align: left; display: block\"> ";
                $corpo .= "<font face='webdings'  style=\"color: darkgreen\">P</font> <span style=\"font-weight: bold\">Antes de imprimir, pense em seu compromisso com o Meio Ambiente.</span> Before printing, think about your<br /> commitment ";
                $corpo .= "to the environment. ";
            }
            
		    $mail->setFrom($this->settings[$this->env]['constants.MAIL_USERNAME'], 'AgroBrasil - Agronet 2.0');

            foreach ($emails as $email) {
                $mail->addTo($email);
            }
            
            $mail->setSubject($assunto);
            $mail->setBodyHtml($corpo);
            $mail->send($transport);
        } catch (Zend_Mail_Protocol_Exception $e) {

            $mensagem = $e->getMessage();
            echo "[SERVER] - enviarEmail: error\n";
            echo "[SERVER] - {$mensagem}\n";
        }
    }
}
