<?php
require_once 'Zend/Loader/Autoloader.php';
$loader = Zend_Loader_Autoloader::getInstance();

class Agro_Log {

    private $pathRegistryLog;
    private $dirLogTransmissao;
    private $email = null;
    private $emailFrom = null;
    private $app;
    private $config;
    private $vistoria = [];
    private $usuario = [];
    private $idVistoria = null;
    private $idProposta = null;
    private $db = null;
    private $rota = '';
    private $registrarLogTxt;

    const PREVIA_DIGITAL = 1;
    const VSD = 2;

    /**
     * Define qual APP está logando as informações
     * 
     * @param int $app
     * @param bool $registrarLogTxt
     * @param ?string $applicationEnv
     */
    public function __construct(int $app = self::PREVIA_DIGITAL, bool $registrarLogTxt = true, ?string $applicationEnv = null)
    {
        $this->registrarLogTxt = $registrarLogTxt;
        $os = strtoupper(substr(PHP_OS, 0, 3));
        $dirRegistry = $os == 'WIN' ? "c:\Temp\\" :"/tmp/";
                
        if (empty($applicationEnv)) {
            $application_env = ($os == 'WIN') ? 'docker' : getenv('APPLICATION_ENV');
        } else {
            $application_env = $applicationEnv;
        }
		
		$this->config = new Zend_Config_Ini(__DIR__ . '/../../../application/config/application.ini', $application_env);

        switch ($app) {
            case self::PREVIA_DIGITAL:
                $this->pathRegistryLog = $dirRegistry . 'log_error_seventaps_'.date('Ymd').'.log';
                $this->dirLogTransmissao = __DIR__ . '/../../../application/upload_files/log_transmissao_vp/';
                $this->emailFrom = 'vp@agrobrasilseguros.com.br';
                break;
                
            case self::VSD:
                $this->pathRegistryLog = $dirRegistry . 'log_error_vsd_'.date('Ymd').'.log';
                $this->dirLogTransmissao = __DIR__ . '/../../../application/upload_files/log_transmissao_vsd/';
                $this->emailFrom = 'vp@agrobrasilseguros.com.br';
                break;
            
            default:
                throw new Exception("APP informado para o log não encontrado.");
                break;
        }

        if (!file_exists($this->dirLogTransmissao)) {
            mkdir($this->dirLogTransmissao, '0755', true);
        }

        $this->app = $app;
    }

    /**
     * Define os dados da requisição que foram recebidos
     * 
     * @param array $vistoria
     */
    public function setVistoria(array $vistoria): void
    {
        $this->vistoria = $vistoria;
    }

    /**
     * Define os dados usuário autenticado
     * 
     * @param array $usuario
     */
    public function setUsuario(array $usuario): void
    {
        $this->usuario = $usuario;
    }

    /**
     * Retorna os dados que foram recebidos da requisição
     * 
     * @return array
     */
    public function getVistoria(): array
    {
        return $this->vistoria;
    }

    /**
     * Retorna os dados do usuário autenticado
     * 
     * @return array
     */
    public function getUsuario(): array
    {
        return $this->usuario;
    }

    /**
     * Retorna uma instância de Zend_Db_Adapter_Pdo_Pgsql
     * 
     * @return Zend_Db_Adapter_Pdo_Pgsql
     */
    private function getDB(): Zend_Db_Adapter_Pdo_Pgsql
    {
        if (!is_null($this->db)) {
            return $this->db;
        }

        $Adapter = Zend_Db::factory('PDO_PGSQL', $this->config->resources->db->params);
        Zend_Db_Table_Abstract::setDefaultAdapter($Adapter);
        $this->db = Zend_Db_Table::getDefaultAdapter();
        
        return $this->db;
    }

    /**
     * Define qual rota está sendo logada
     * 
     * @param string $rota
     */
    public function setRota(string $rota): void 
    {
        $this->rota = $rota;
    }

    /**
     * Retorna a rota
     * 
     * @return string
     */
    public function getRota(): string
    {
        return $this->rota;
    }

    /**
     * Retorna o ID da vistoria de acordo com o APP
     * 
     * @return int|null
     */
    public function getIdVistoria(): ?int
    {
        if (!is_null($this->idVistoria)) {
            return $this->idVistoria;
        }

        switch ($this->app) {
            case self::PREVIA_DIGITAL:
                $this->idVistoria = !empty($this->vistoria['idVistoria']) ? $this->vistoria['idVistoria'] : null;
                break;
            case self::VSD:
                $this->idVistoria = !empty($this->vistoria['id_vistoria']) ? $this->vistoria['id_vistoria'] : null;
                break;
        }

        if (gettype($this->idVistoria) != "integer") {
            $this->idVistoria = null;
        }

        return $this->idVistoria;
    }

    /**
     * Retorna o ID da Proposta de acordo com o APP
     * 
     * @return int|null
     */
    public function getIdProposta(): ?int
    {
        if (!is_null($this->idProposta)) {
            return $this->idProposta;
        }

        switch ($this->app) {
            case self::PREVIA_DIGITAL:
                $this->idProposta = !empty($this->vistoria['idProposta']) ? $this->vistoria['idProposta'] : null;
                break;
            case self::VSD:

                $this->idProposta = !empty($this->vistoria['id_proposta']) ? $this->vistoria['id_proposta'] : null;

                $idVistoria = $this->getIdVistoria();
                if (!empty($idVistoria) && empty($this->idProposta)) {
                    $db = $this->getDB();
                    $query = $db->select();
                    $query->from(['svp' => 'sinistro.vistorias_processos'], null);
                    $query->join(['sp' => 'sinistro.processos'], 'sp.id = svp.id_processo', ['id_proposta']);
                    $query->where("svp.id_vistoria = {$idVistoria}");

                    $rs = $db->fetchRow($query);

                    if (!empty($rs)) {
                        $this->idProposta = $rs['id_proposta'];
                    }
                }
                break;
        }

        if (gettype($this->idProposta) != "integer") {
            $this->idProposta = null;
        }

        return $this->idProposta;
    }

    /**
     * Loga o sucesso no arquivo configurado
     *
     * @param string $mensagem
     */
    public function logSuccess(string $mensagem): void
    {
        $mensagem = $this->montarMensagem($mensagem);
        $pathJson = null;

        if ($this->registrarLogTxt) {
            $this->registryLog();
            $mensagemLog = $mensagem;
            $mensagemLog .= "Json: " . json_encode($this->vistoria) . PHP_EOL;
            $mensagemLog .= str_repeat('-', 160) . PHP_EOL . PHP_EOL;
    
            $logger = @Zend_Registry::get('logger');
            $logger->log($mensagemLog, Zend_Log::INFO);
    
            $pathJson = $this->logTransmission('success');
        }


        $idVistoria = $this->getIdVistoria();
        $idProposta = $this->getIdProposta();

        $subject = "AgroNet 2.0 - SINCRONIA DO TABLET REALIZADA COM SUCESSO - Proposta ". $idProposta ."/Vistoria " . $idVistoria;
        
        if ($this->app == self::VSD) {
            $subject = "[VSD] SINCRONIA DO TABLET REALIZADA COM SUCESSO - Proposta ". $idProposta ."/Vistoria: ". $idVistoria;
        }

        $this->sendEmail($mensagem, $subject, $pathJson, null, array('log_json' => true));
    }

    /**
     * Loga o erro no arquivo configurado
     *
     * @param string $mensagem
     */
	public function logError(string $mensagem): void
    {
        $mensagem = $this->montarMensagem($mensagem);
	    $pathJson = null;

        if ($this->registrarLogTxt) {
            $this->registryLog();

            $mensagemLog = $mensagem;
            $mensagemLog .= "Json: " . json_encode($this->vistoria) . PHP_EOL;
            $mensagemLog .= str_repeat('-', 160) . PHP_EOL . PHP_EOL;
    
            $logger = @Zend_Registry::get('logger');
            $logger->log($mensagemLog, Zend_Log::ERR);
    
            $pathJson = $this->logTransmission('error');
        }

        
        $idVistoria = $this->getIdVistoria();
        $idProposta = $this->getIdProposta();
        
        $subject = "AgroNet 2.0 - ERRO DE SINCRONIA DO TABLET - Proposta ". $idProposta ."/Vistoria ". $idVistoria;
	$this->sendEmail($mensagem, $subject, $pathJson, null, array('log_json' => true));
	return; //desligado daqui pra baixo pq estava gerando muito e-mails do VSD.

        if ($this->app == self::VSD) {
            $subject = "[VSD] ERRO DE SINCRONIA - Vistoria: ". $idVistoria;
        }
        
        $this->sendEmail($mensagem, $subject, $pathJson, null, array('log_json' => true));
    }

    /**
     * Loga as informações da transmissão
     * 
     * @param string $stateof
     * @return string
     */
    private function logTransmission(string $stateof): string 
    {
        $t = microtime(true);
        $micro = sprintf("%06d",($t - floor($t)) * 1000000);
        $d = new DateTime( date("Y-m-d H:i:s.".$micro, $t) );
    
        $filename = $d->format("YmdHisu") . "_request_data_".$stateof.".json";
        $path = $this->dirLogTransmissao . $filename;
        file_put_contents($path, json_encode($this->vistoria));

        //guarda as informações do modelo do device utilizado
        $this->saveDeviceInfo();

        return $path;
    }

    /**
     * Configura o logger para o arquivo correto
     */
    private function registryLog(): void
    {
    	if (!@Zend_Registry::isRegistered('logger')) {
	        $logger = new Zend_Log();

	        $writer = new Zend_Log_Writer_Stream($this->pathRegistryLog);

	        $logger->addWriter($writer);
	        @Zend_Registry::set('logger', $logger);
	   	}
    }

    /**
     * Realiza o envio de email para notificar os erros da sincronia
     *
     * @param $message Mensagem de erro para enviar por email
     */
    private function sendEmail($message, $subject = "AgroNet 2.0 - ERRO DE SINCRONIA DO TABLET", $filePath = null, $cc = null, array $opt = null): void
    {
        $this->registryEmail();

        $os = strtoupper(substr(PHP_OS, 0, 3));
        $application_env = ($os == 'WIN') ? 'docker' : getenv('APPLICATION_ENV');

        if ($application_env != 'production') {
            $this->email->clearFrom();
            $this->email->setFrom('testes@agrobrasilseguros.com.br');
            $this->email->addTo('andre.mello@agrobrasilseguros.com.br', 'Andre Mello');
            /*
            $this->email->addTo('tonismar.bernardo@agrobrasilseguros.com.br', 'Tonismar Bernardo');
            $this->email->addTo('fabio.bertoldi@agrobrasilseguros.com.br', 'Fábio Bertoldi');
            //para evitar o envio dos logs para fora da ti
            if (!isset($opt['log_json']) || (isset($opt['log_json']) && !$opt['log_json'])) {
                $this->email->addBcc('luana.beck@agrobrasilseguros.com.br', 'Luana Beck');
                $this->email->addBcc('karina.silva@agrobrasilseguros.com.br', 'Karina Silva');
            }
            */
            $subject .= " - HOMOLOG";
        } else {
            $this->email->addTo('ti@agrobrasilseguros.com.br', 'TI - Agrobrasil');
            /*
            //para evitar o envio dos logs para fora da ti
            if (!isset($opt['log_json']) || (isset($opt['log_json']) && !$opt['log_json'])) {
                $this->email->addBcc('luana.beck@agrobrasilseguros.com.br', 'Luana Beck');
                $this->email->addBcc('karina.silva@agrobrasilseguros.com.br', 'Karina Silva');
            }
            */
        }

        $this->email->setSubject($subject);

        if (isset($opt['html'])) {
            $this->email->setBodyHtml($message);
		} else {
            $this->email->setBodyText($message);
        }

        if (!is_null($filePath)) {
        	$content = file_get_contents($filePath);
			$attachment = new Zend_Mime_Part($content);
			$attachment->type = mime_content_type($filePath);
			$attachment->disposition = Zend_Mime::DISPOSITION_ATTACHMENT;
			$attachment->encoding = Zend_Mime::ENCODING_BASE64;
			$attachment->filename = basename($filePath);

			$this->email->addAttachment($attachment);
        }

        // Precisou suprimir o erro (deprecated: array_key_exists on objects) pois acontece no Zend 
        @$this->email->send();

        unset($this->email);
    }

    /**
     * Configura o cliente de email
     */
    private function registryEmail(): void
    {
    	if (empty($this->email)) {
            
            $this->email = new Zend_Mail('UTF-8');

            $config = array(
                'ssl' => $this->config->constants->MAIL_SSL,
                'port' => $this->config->constants->MAIL_PORT,
                'auth' => $this->config->constants->MAIL_AUTH,
                'username' => $this->config->constants->MAIL_USERNAME,
                'password' => $this->config->constants->MAIL_PASSWORD
            );

            $transport = new Zend_Mail_Transport_Smtp($this->config->constants->MAIL_SMTP, $config);

            $this->email->setDefaultTransport($transport);
            $this->email->setFrom($this->emailFrom, 'AgroBrasil - Agronet 2.0');
        }
    }

    /**
     * Salva o vínculo do dispositivo com a vistoria
     */
    private function saveDeviceInfo(): void
    {
        $idVistoria = $this->getIdVistoria();

	    if (!empty($this->vistoria['deviceId']) && !empty($idVistoria)) { 

            $Adapter = Zend_Db::factory('PDO_PGSQL', $this->config->resources->db->params);
            Zend_Db_Table_Abstract::setDefaultAdapter($Adapter);
            $db = Zend_Db_Table::getDefaultAdapter();
            
            $db->query("INSERT INTO sistema.vistoria_dispositivo (id_vistoria, dispositivo_info) VALUES ('{$idVistoria}', '{$this->vistoria['deviceId']}')");
        }
    }

    /**
     * Monta a mensagem de log com os dados identificadores
     * 
     * @param string $mensagem
     * @return string
     */
    private function montarMensagem(string $mensagem): string
    {
        $idVistoria = $this->getIdVistoria();
        $idProposta = $this->getIdProposta();
        $usuario = $this->getUsuario();

        $mensagem .= "Vistoria: " . $idVistoria . PHP_EOL;
        $mensagem .= "Proposta: " . $idProposta . PHP_EOL;
        $mensagem .= "Data e Hora da recepção: " . date('d/m/Y H:i') . PHP_EOL;
        
        if (!empty($usuario['ds_nome_usuario'])) {
            $mensagem .= "Usuário: " . $usuario['ds_nome_usuario'] . PHP_EOL;
        }

        if (!empty($this->rota)) {
            $mensagem .= "Rota: " . $this->rota . PHP_EOL;
        }
        
        return $mensagem;
    }
}
