<?php
require_once __DIR__ . '/../Auth.php';
require_once __DIR__ . '/../Log.php';
require_once __DIR__ . '/Validator.php';
require_once __DIR__ . '/Vistoria.php';
require_once __DIR__ . "../../../RabbitMQ/VSD/RpcClient.php";


class Agro_Vsd extends Agro_Auth {

    private $urlAmbiente = 'https://agronet.agrobrasilseguros.com.br';
    private $exceptionVistorias = [372513, 372515];

    public function __construct()
    {
        parent::__construct();

        if (getenv('APPLICATION_ENV') != 'production') {
            $this->urlAmbiente = 'http://agronet-vsd.agrobrasilseguros.com.br';
        }
    }

    public function auth ($usuario, $senha, $deviceId = "") {
        $retorno = parent::auth($usuario, $senha, $deviceId);
        if (!$retorno['status']) {

            $log = new Agro_Log(Agro_Log::VSD);
            $log->setRota('auth');
            $log->setUsuario(['ds_nome_usuario' => $usuario]);
            $log->logError("Erro: " . $retorno['message'] . "\n");
            return $retorno;
        }
        
        $vistoriador = $this->getVistoriador($usuario);
        $retorno['ds_nome_vistoriador'] = $vistoriador['ds_nome_vistoriador'];
        $retorno['id_vistoriador'] = $vistoriador['id_vistoriador'];

        $dadosZoneamento = $this->getZoneamento();
        $retorno = array_merge($retorno, $dadosZoneamento);

        return $retorno;
    }

    public function ola () {
        return ['status' => true,'data' => 'I\'m here!'];
    }

    protected function checkDevice($usuario, $deviceId) {

		// PARA TESTAR EM MAIS DE UM DISPOSITIVO
		if (in_array($usuario, self::$exceptionUser)) return true;

		if (!empty($usuario) && !empty($deviceId)) {

			$db_deviceid = self::$db->fetchOne("select deviceid_sinistro from sistema.usuarios 
				where ds_nome_usuario = '{$usuario}'");

			if (empty($db_deviceid)) {
				try {
					self::$db->update('sistema.usuarios', array('deviceid_sinistro' => $deviceId), "ds_nome_usuario = '{$usuario}'");
					return true;
				} catch (Exception $e) {
					return $e->getMessage();
				}
			} elseif ($deviceId == $db_deviceid) {
				return true;
			} else {
				return false;
			}
		}
	}

    protected function isUserAble($usuario) {

		//usuário de exceção
		if (in_array($usuario, self::$exceptionUser)) {
			return true;
		}

        $this->setDb();
        $Usuario = self::$db->select();
        $Usuario->from(array('u' => 'sistema.usuarios'), array('id','ds_nome_usuario','token'));
        $Usuario->where('u.ds_nome_usuario = ?', $usuario);
        $Usuario->where('u.fl_liberado_tablet_sinistro = ?', true);

        $Row = self::$db->fetchRow($Usuario);

		if (is_array($Row)) {
			return true;
		}

		return false;
	}

    /**
	* @param string usuario
	* @return array
	* Busca dados do vistoriador.
	*/
	private function getVistoriador($usuario) {
		try {
			$this->setDb();
			$Vistoriador = self::$db->select();
			$Vistoriador->from(array('usuarios' => 'sistema.usuarios'), false);
			$Vistoriador->join(array('funcionarios' => 'sistema.funcionarios'), 'usuarios.id = funcionarios.id_usuario', array('trim(ds_nome_funcionario) as ds_nome_vistoriador','id as id_vistoriador'));
			$Vistoriador->join(array('empresas' => 'sistema.empresas'), 'empresas.id = funcionarios.id_empresa', 'trim(ds_nome_fantasia) as ds_nome_empresa');
			$Vistoriador->where('usuarios.ds_nome_usuario = ?', trim($usuario));

			return self::$db->fetchRow($Vistoriador);
		} catch (Exception $e) {
			return false;
		}
	}

    /**
     * @return string
     */
    public function getvistorias()
    {
        try {
            $usuario = $this->checkToken();

            if (!is_array($usuario)) {
                throw new Exception($this->getError(0), 401);
            }

            $this->criarTabelasTemporarias();

            $rs = $this->getVistoriasFinais($usuario['id']);
            $vistorias = [];
            foreach ($rs as $index => $row) {

                $vistorias[$index]['id_vistoria'] = $row['id_vistoria'];
                $vistorias[$index]['id_processo'] = $row['id_processo'];
                $vistorias[$index]['dt_agendamento'] = $row['dt_agendamento'];
                $vistorias[$index]['ds_turno'] = $row['ds_turno'];
                $vistorias[$index]['laudos'] = $this->getLaudos($row['id_proposta_vigente']);
                $vistorias[$index]['peritos'] = $this->getPeritos($row['id_vistoria']);
                $vistorias[$index]['proposta']['id_proposta'] = $row['id_proposta'];
                $vistorias[$index]['proposta']['id_proposta_completo'] = $row['id_proposta_completo'];
                $vistorias[$index]['proposta']['id_endosso'] = $row['id_endosso'];
                $vistorias[$index]['proposta']['dt_vigencia_inicio'] = $row['dt_vigencia_inicio'];
                $vistorias[$index]['proposta']['dt_vigencia_fim'] = $row['dt_vigencia_fim'];
                $vistorias[$index]['proposta']['itens'] = $this->getItensProposta($row['id_proposta_vigente'], $row['id_vistoria']);
                $vistorias[$index]['proposta']['coberturas'] = $this->getCoberturasProposta($row['id_proposta_vigente'], $row['id_produto']);
                $vistorias[$index]['proposta']['croqui'] = $this->getCroquiProposta($row['id_proposta_vigente']);
                $vistorias[$index]['proposta']['proponente']['id_proponente'] = $row['id_proponente'];
                $vistorias[$index]['proposta']['proponente']['ds_nome_proponente'] = $row['ds_nome_proponente'];
                $vistorias[$index]['proposta']['proponente']['cpf_cnpj'] = $row['cpf_cnpj'];
                $vistorias[$index]['proposta']['proponente']['ds_tel_residencia'] = $row['ds_tel_residencia'];
                $vistorias[$index]['proposta']['proponente']['ds_tel_celular'] = $row['ds_tel_celular'];
                $vistorias[$index]['proposta']['proponente']['ds_tel_propriedade'] = $row['ds_tel_propriedade'];
                $vistorias[$index]['proposta']['proponente']['ds_email_proponente'] = $row['ds_email_proponente'];
                $vistorias[$index]['proposta']['propriedade']['ds_nome_propriedade'] = $row['ds_nome_propriedade'];
                $vistorias[$index]['proposta']['propriedade']['ds_endereco_cep'] = $row['ds_endereco_cep'];
                $vistorias[$index]['proposta']['propriedade']['ds_endereco'] = $row['ds_endereco'];
                $vistorias[$index]['proposta']['propriedade']['ds_endereco_bairro'] = $row['ds_endereco_bairro'];
                $vistorias[$index]['proposta']['propriedade']['ds_endereco_nro'] = $row['ds_endereco_nro'];
                $vistorias[$index]['proposta']['propriedade']['ds_endereco_complemento'] = $row['ds_endereco_complemento'];
                $vistorias[$index]['proposta']['propriedade']['ds_coordenadas'] = $row['ds_coordenadas'];
                $vistorias[$index]['proposta']['propriedade']['ds_referencia_localizacao'] = $row['ds_referencia_localizacao'];
                $vistorias[$index]['proposta']['propriedade']['municipio']['id_municipio'] = $row['id_municipio'];
                $vistorias[$index]['proposta']['propriedade']['municipio']['ds_nome_municipio'] = $row['ds_nome_municipio'];
                $vistorias[$index]['proposta']['propriedade']['estado']['id_estado'] = $row['id_estado'];
                $vistorias[$index]['proposta']['propriedade']['estado']['ds_nome_estado'] = $row['ds_nome_estado'];
                $vistorias[$index]['proposta']['propriedade']['estado']['ds_sigla'] = $row['ds_sigla'];
                $vistorias[$index]['proposta']['id_regiao'] = (int) "{$row['id_estado']}{$row['id_regiao']}";
                $vistorias[$index]['proposta']['id_produto'] = $row['id_produto'];
                $vistorias[$index]['proposta']['ds_nome_produto'] = $row['ds_nome_produto'];
                $vistorias[$index]['proposta']['id_cultura'] = $row['id_cultura'];
                $vistorias[$index]['proposta']['ds_nome_cultura'] = $row['ds_nome_cultura'];
                $vistorias[$index]['proposta']['id_safra'] = $row['id_safra'];
                $vistorias[$index]['proposta']['ds_nome_safra'] = $row['ds_nome_safra'];
                $vistorias[$index]['proposta']['ds_observacao'] = $row['ds_observacao'];
                $vistorias[$index]['proposta']['ds_observacoes_adicionais'] = $this->getObservacoesAdicionaisProposta($row['id_proposta_vigente']);
                $vistorias[$index]['proposta']['autorizados'] = $this->getAutorizadosProposta($row['id_proposta_vigente']);
                $vistorias[$index]['avisos'] =  $this->getAvisos($row['id_proposta_vigente']);
                $vistorias[$index]['id_status_vistoria'] = $row['id_status_vistoria'];
                $vistorias[$index]['ds_status_vistoria'] = $row['ds_status_vistoria'];
            }

        } catch (\Throwable $th) {

            $code = empty($th->getCode()) ? 500 : $th->getCode();
            http_response_code($code);
            return array('status' => false, 'message' => "Erro ao buscar as vistorias. \n{$th->getMessage()}");
        }

        http_response_code(200);
        return array('status' => true, "vistorias" => $vistorias);
    }

    /**
     * Cria tabelas temporárias que serão utilizadas no getvistorias
     */
    private function criarTabelasTemporarias(): void
    {
        self::$db->query("CREATE TEMP TABLE tmp_endosso AS (
            SELECT id_proposta, id_endosso FROM seguro.propostas_endosso
        );");

        self::$db->query("CREATE TEMP TABLE itens_segurados_croqui_temp AS (
            SELECT spct2.id as id_propostas_croquis_talhoes,
                    unnest(string_to_array(ds_item_segurado, ',')) AS id_item_segurado
            FROM seguro.propostas_croquis_talhoes spct2);"
        );
    }

    private function getVistoriasFinais(int $idUsuario)
    {
        $caseTurno = " CASE WHEN sa.ds_turno = 'M' THEN 'Manhã'
                                    WHEN sa.ds_turno = 'T' THEN 'Tarde'
                                    WHEN sa.ds_turno = 'N' THEN 'Noite'
                                    ELSE ''
                               END AS ds_turno ";

        $query = self::$db->select();
        $query->from(['sv' => 'sistema.vistorias'], null);
        $query->join(['svc' => 'sistema.vistorias_coberturas'], 'svc.id_vistoria = sv.id', null);
        $query->join(['svp' => 'sinistro.vistorias_processos'], 'svp.id_vistoria = sv.id', ['id_processo', new Zend_Db_Expr('CASE WHEN lf.id_status = 207 THEN 223 ELSE 222 END as id_status_vistoria'), new Zend_Db_Expr("CASE WHEN lf.id_status = 207 THEN 'Cancelada' ELSE 'Aguardando Vistoria' END as ds_status_vistoria")]);
        $query->join(['sp' => 'sinistro.processos'], 'sp.id = svp.id_processo', ['id_proposta as id_proposta_vigente']);
        $query->join(['lf' => 'sinistro.laudos_finais'], 'lf.id_processo = sp.id', null);
        $query->join(['vlf' => 'sistema.vistorias_laudos_finais'], 'vlf.id_laudo_final = lf.id AND vlf.id_vistoria = sv.id', null);
        $query->join(['spr' => 'seguro.propostas'], 'spr.id = sp.id_proposta', ['id_proposta_mae as id_proposta', 'seguro.id_proposta_mae_completo(spr.id) as id_proposta_completo', 'dt_vigencia_inicio', 'dt_vigencia_fim', 'id_produto']);
        $query->join(['spe' => 'tmp_endosso'], 'spe.id_proposta = spr.id_proposta_mae', ['spe.id_endosso']);
        $query->join(['spp' => 'seguro.propostas_proponentes'], 'spp.id_proposta = spr.id', ['ds_nome_proponente', 'cpf_cnpj', 'ds_tel_residencia', 'ds_tel_celular', 'ds_tel_propriedade', 'ds_email_proponente']);
        $query->join(['sprop' => 'seguro.proponentes'], 'sprop.cpf_cnpj = spp.cpf_cnpj', ['id as id_proponente']);
        $query->join(['spprop' => 'seguro.propostas_propriedades'], 'spprop.id_proposta = spr.id', ['ds_nome_propriedade', 'ds_endereco_cep', 'ds_endereco', 'ds_endereco_bairro', 'ds_endereco_nro', 'ds_endereco_complemento', 'ds_coordenadas', 'ds_referencia_localizacao', 'id_municipio']);
        $query->join(['sm' => 'sistema.municipios'], 'sm.id = spprop.id_municipio', ['ds_nome_municipio', 'id_estado']);
        $query->join(['se' => 'sistema.estados'], 'se.id = sm.id_estado', ['ds_nome_estado', 'ds_sigla']);
        $query->join(['sva' => 'sistema.vistorias_agendamentos'], 'sva.id_vistoria = sv.id', ['id_vistoria']);
        $query->join(['sa' => 'sistema.agendamentos'], 'sa.id = sva.id_agendamento', ['dt_agendamento', $caseTurno]);
        $query->join(['saf' => 'sistema.agendamentos_funcionarios'], 'saf.id_agendamento = sa.id', null);
        $query->join(['sf' => 'sistema.funcionarios'], 'sf.id = saf.id_funcionario', null);
        $query->join(['pp' => 'produto.produtos'], 'pp.id = spr.id_produto', ['ds_nome_produto', 'id_safra']);
        $query->join(['ps' => 'produto.safras'], 'ps.id = pp.id_safra', ['ds_nome_safra']);
        $query->join(['ppg' => 'produto.produtos_geral'], 'ppg.id = pp.id_produto_geral', ['id_cultura']);
        $query->join(['pc' => 'produto.culturas'], 'pc.id = ppg.id_cultura', ['ds_nome_cultura']);
        $query->joinLeft(['smcr' => 'sistema.municipios_culturas_regioes'], 'smcr.id_cultura = pc.id AND smcr.id_municipio = sm.id', ['coalesce(smcr.id_regiao, 0) as id_regiao']);
        $query->joinLeft(['sps' => 'seguro.propostas_status'], 'sps.id_proposta = sp.id_proposta AND sps.fl_ativo is true', ['ds_observacao']);
        $query->where("sf.id_usuario = {$idUsuario}");
        //Valida que o usuário seja o vistoriador princial
        $query->where("saf.fl_principal is true");
        //Valida para buscar somente laudos LF003 e LF034
        $query->where("(EXISTS (
                            SELECT *
                              FROM produto.produtos_coberturas ppp
                              JOIN sinistro.tipo_laudo_final stlf ON stlf.id = ppp.id_tipo_laudo_final
                              JOIN produto.coberturas_eventos pce ON pce.id_cobertura = ppp.id_cobertura
                              JOIN sinistro.avisos_eventos sae ON sae.id_evento = pce.id_evento
                             WHERE ppp.id_produto = pp.id
                               AND ppp.id_cobertura = svc.id_cobertura
                               AND stlf.id IN (157, 170)
                            )
                        )"
                    );
        //Valida para buscar somente laudos com os status "Aguardando Vistoria" ou "Cancelada"
        $query->where("lf.id_status IN (211, 207)");
        //Valida para buscar somente as vistorias que não foram limpas do app (para o caso das vistorias que foram canceladas)
        $query->where("lf.fl_was_cleaned_in_tablet is false");
        //Valida para não buscar vistorias onde o endosso vigente não possua croqui
        $query->where("EXISTS(SELECT 1 FROM seguro.propostas_croquis spc WHERE fl_vigente is true AND spc.id_proposta = sp.id_proposta)");
        $query->group("svp.id_processo,
                       id_status_vistoria,
                       ds_status_vistoria,
                       sp.id_proposta,
                       spr.id_proposta_mae,
                       seguro.id_proposta_mae_completo(spr.id),
                       spr.dt_vigencia_inicio,
                       spr.dt_vigencia_fim,
                       spr.id_produto,
                       spe.id_endosso,
                       spp.ds_nome_proponente,
                       spp.cpf_cnpj,
                       spp.ds_tel_residencia,
                       spp.ds_tel_celular,
                       spp.ds_tel_propriedade,
                       spp.ds_email_proponente,
                       sprop.id,
                       spprop.ds_nome_propriedade,
                       spprop.ds_endereco_cep,
                       spprop.ds_endereco,
                       spprop.ds_endereco_bairro, 
                       spprop.ds_endereco_nro,
                       spprop.ds_endereco_complemento,
                       spprop.ds_coordenadas,
                       spprop.ds_referencia_localizacao,
                       spprop.id_municipio,
                       sm.ds_nome_municipio,
                       sm.id_estado,
                       se.ds_nome_estado,
                       se.ds_sigla,
                       sva.id_vistoria,
                       sa.dt_agendamento,
                       ds_turno,
                       pp.ds_nome_produto,
                       pp.id_safra,
                       ps.ds_nome_safra,
                       ppg.id_cultura,
                       pc.ds_nome_cultura,
                       smcr.id_regiao,
                       sps.ds_observacao,
                       spr.id");
        $query->order("spr.id, sva.id_vistoria");

        return self::$db->fetchAll($query);
    }

    private function getLaudos(int $idPropostaVigente)
    {
        $laudosPrevia = $this->getLaudosPrevia($idPropostaVigente);
        $laudosPreliminares = $this->getLaudosPreliminares($idPropostaVigente);
        $laudosFinais = $this->getLaudosFinais($idPropostaVigente);

        return array_merge($laudosPrevia, $laudosPreliminares, $laudosFinais);
    }

    private function getLaudosPrevia(int $idPropostaVigente)
    {
        $query = self::$db->select();
        $query->from(['sv' => 'sistema.vistorias'], ['id_tipo as id_tipo_vistoria']);
        $query->join(['spvp' => 'seguro.propostas_vistorias_previas'], 'spvp.id_vistoria = sv.id', ['id_vistoria']);
        $query->join(['spvpa' => 'seguro.propostas_vistorias_previas_arquivos'], 'spvpa.id_proposta_vistoria = spvp.id', ['ds_nome_arquivo', 'id_tipo_arquivo_laudo_previa as id_tipo_arquivo']);
        $query->join(['stalp' => 'sistema.tipo_arquivo_laudo_previa'], 'stalp.id = spvpa.id_tipo_arquivo_laudo_previa', ['ds_tipo_arquivo']);
        $query->where("spvpa.id_tipo_arquivo_laudo_previa in (2, 4, 6)");
        $query->where("spvp.id_proposta = {$idPropostaVigente}");
        $query->where("(spvp.id_status IN (71, 226) AND spvp.id_status_analise in (176, 175, 173, 178, 174, 233, 234))");
        $rs = self::$db->fetchAll($query);

        return $this->organizarRetornoLaudos($rs);
    }

    private function getLaudosPreliminares(int $idPropostaVigente)
    {
        $query = self::$db->select();
        $query->from(['sv' => 'sistema.vistorias'], ['id_tipo as id_tipo_vistoria']);
        $query->join(['svlp' => 'sistema.vistorias_laudos_preliminares'], 'svlp.id_vistoria = sv.id', ['id_vistoria']);
        $query->join(['slp' => 'sinistro.laudos_preliminares'], 'slp.id = svlp.id_laudo_preliminar', ['ds_nome_laudo_fisico as ds_nome_arquivo', new Zend_Db_Expr('2 as id_tipo_arquivo'), new Zend_Db_Expr("'Laudo' as ds_tipo_arquivo")]);
        $query->join(['sp' => 'sinistro.processos'], 'sp.id = slp.id_processo', null);
        $query->where("sp.id_proposta = {$idPropostaVigente}");
        $rs = self::$db->fetchAll($query);

        return $this->organizarRetornoLaudos($rs);
    }

    private function getLaudosFinais(int $idPropostaVigente)
    {
        $query = self::$db->select();
        $query->from(['sv' => 'sistema.vistorias'], ['id_tipo as id_tipo_vistoria']);
        $query->join(['svlf' => 'sistema.vistorias_laudos_finais'], 'svlf.id_vistoria = sv.id', ['id_vistoria']);
        $query->join(['slf' => 'sinistro.laudos_finais'], 'slf.id = svlf.id_laudo_final', ['coalesce(slf.ds_nome_laudo_fisico, slfis.ds_nome_laudo_fisico) as ds_nome_arquivo', new Zend_Db_Expr('2 as id_tipo_arquivo'), new Zend_Db_Expr("'Laudo' as ds_tipo_arquivo")]);
        $query->joinLeft(['slfis' => 'sinistro.laudos_finais_itens_segurados'], 'slfis.id_laudo_final = slf.id', null);
        $query->join(['sp' => 'sinistro.processos'], 'sp.id = slf.id_processo', null);
        $query->where("sp.id_proposta = {$idPropostaVigente}");
        $query->group(['id_tipo_vistoria', 'svlf.id_vistoria', 'ds_nome_arquivo', 'id_tipo_arquivo', 'ds_tipo_arquivo']);
        $rs = self::$db->fetchAll($query);

        return $this->organizarRetornoLaudos($rs);
    }

    private function organizarRetornoLaudos($rs)
    {
        $laudos = [];
        foreach ($rs as $row) {
            
            if (empty($row['ds_nome_arquivo'])) {
                continue;
            }

            if (array_key_exists($row['id_vistoria'], $laudos)) {
                $laudos[$row['id_vistoria']]['arquivos'][] = [
                    "id_tipo_arquivo" => $row['id_tipo_arquivo'],
                    "ds_tipo_arquivo" => $row['ds_tipo_arquivo'],
                    "url" => $this->getPathLaudos($row['ds_nome_arquivo'])
                ];

                continue;
            }

            $laudos[$row['id_vistoria']]['id_vistoria'] = $row['id_vistoria'];
            $laudos[$row['id_vistoria']]['id_tipo_vistoria'] = $row['id_tipo_vistoria'];
            $laudos[$row['id_vistoria']]['arquivos'][] = [
                "id_tipo_arquivo" => $row['id_tipo_arquivo'],
                "ds_tipo_arquivo" => $row['ds_tipo_arquivo'],
                "url" => $this->getPathLaudos($row['ds_nome_arquivo'])
            ];
        }

        //Para resetar as chaves do array
        return array_values($laudos);
    }

    private function getPeritos(int $idVistoria)
    {
        $query = self::$db->select();
        $query->from(['saf' => 'sistema.agendamentos_funcionarios'], ['fl_principal']);
        $query->join(['sva' => 'sistema.vistorias_agendamentos'], 'sva.id_agendamento = saf.id_agendamento', null);
        $query->join(['sf' => 'sistema.funcionarios'], 'sf.id = saf.id_funcionario', ['id as id_usuario', 'ds_nome_funcionario', 'ds_crea', 'cpf_cnpj']);
        $query->where("sva.id_vistoria = {$idVistoria}");
        return self::$db->fetchAll($query);
    }

    /**
     * Retorna os itens a serem vistoriados
     *
     * @param int $idPropostaVigente
     * @param int $idVistoria
     * @return array
     */
    private function getItensProposta(int $idPropostaVigente, int $idVistoria): array
    {
        $caseInicioPlantio = " CASE WHEN rlis.dt_inicio_semeadura IS NOT NULL THEN to_char(rlis.dt_inicio_semeadura, 'YYYY-mm-dd')::date
                                    WHEN sisc.dt_plantio IS NOT NULL THEN sisc.dt_plantio
                                    ELSE sisc.dt_semeadura
                               END AS dt_inicio_plantio ";
        
        $caseAreaSegurada = " CASE WHEN (sis.vl_area = 0 AND sis.vl_lmga = 0) THEN false ELSE true END as fl_area_segurada ";

        $casePossuiPrevia = " CASE WHEN EXISTS (SELECT *
                                                  FROM seguro.propostas_vistorias_previas spvp
                                                  JOIN seguro.propostas_vistorias_previas_arquivos spvpa ON spvpa.id_proposta_vistoria = spvp.id
                                                 WHERE spvp.id_status IN (71, 226)
                                                   AND spvp.id_proposta = sis.id_proposta
                                                   AND spvpa.fl_fila_transmissao is true)
                                   THEN true
                                   ELSE false
                              END as fl_possui_previa ";
        
        $sumVlAreaVistoriada = "(SELECT coalesce(sum(lfis.vl_area_vistoriada), 0) FROM sinistro.laudos_finais_itens_segurados lfis WHERE lfis.id_item_segurado = sis.id)";
        $sqlAreaAvaliada = " {$sumVlAreaVistoriada} as vl_area_avaliada";
        $sqlAreaDeclarada = "(sis.vl_area - {$sumVlAreaVistoriada}) as vl_area_declarada";

        $query = self::$db->select();
        $query->from(['sis' => 'seguro.itens_segurados'], ['nr_item_segurado', 'ds_item_segurado', $sqlAreaDeclarada, $sqlAreaAvaliada, 'vl_rendimento_tonelada', 'id_variedade', $caseAreaSegurada, $casePossuiPrevia]);
        $query->join(['sisc' => 'seguro.itens_segurados_complemento'], 'sisc.id_item_segurado = sis.id', ['id_item_segurado', 'ds_coordenadas_geograficas', 'vl_altitude', 'vl_producao_garantida', 'id_sistema_plantio as id_semeadura', 'id_tipo_solo']);
        $query->join(['pv' => 'produto.variedades'], 'pv.id = sis.id_variedade', ['ds_nome_variedade']);
        $query->join(['vis' => 'sistema.vistorias_itens_segurados'], 'vis.id_item_segurado = sis.id', null);
        $query->joinLeft(['psp' => 'produto.sistema_plantio'], 'psp.id = sisc.id_sistema_plantio', ['ds_descricao as descricao_semeadura']);
        $query->joinLeft(['rlis_temp' => new Zend_Db_Expr("(SELECT max(id) AS id, id_item_segurado
                                                              FROM regulacao.lvp001_itens_segurados
                                                             WHERE vl_area_excluida = 0.00
                                                             GROUP BY id_item_segurado)")],
                         'rlis_temp.id_item_segurado = sisc.id_item_segurado',
                        false);
        $query->joinLeft(['rlis' => 'regulacao.lvp001_itens_segurados'], 'rlis.id = rlis_temp.id', [$caseInicioPlantio, "to_char(rlis.dt_final_semeadura, 'YYYY-mm-dd')::date as dt_termino_plantio"]);
        $query->joinLeft(['pts' => 'produto.tipo_solo'], 'pts.id = sisc.id_tipo_solo', ['ds_tipo_solo']);
        $query->where("sis.id_proposta = {$idPropostaVigente}");
        $query->where("vis.id_vistoria = {$idVistoria}");
        $query->order("sis.nr_item_segurado");
        
        $rs = self::$db->fetchAll($query);

        foreach ($rs as $index => &$row) {
            $row['semeadura']['id_semeadura'] = $row['id_semeadura'];
            $row['semeadura']['descricao_semeadura'] = $row['descricao_semeadura'];
            
            $row['solo']['id_tipo_solo'] = $row['id_tipo_solo'];
            $row['solo']['ds_tipo_solo'] = $row['ds_tipo_solo'];

            $row['variedade']['id_variedade'] = $row['id_variedade'];
            $row['variedade']['ds_nome_variedade'] = $row['ds_nome_variedade'];

            $row['vl_area_declarada'] = (float)$row['vl_area_declarada'];
            
            unset($row['id_semeadura']);
            unset($row['descricao_semeadura']);
            unset($row['id_tipo_solo']);
            unset($row['ds_tipo_solo']);
            unset($row['id_variedade']);
            unset($row['ds_nome_variedade']);
        }

        return $rs;
    }

    private function getIdsConfiguracoesCondicoesEspeciais(int $idPropostaVigente): array
    {
        $queryProposta = self::$db->select();
        $queryProposta->from(['sp' => 'seguro.propostas'], false);
        $queryProposta->join(['spmae' => 'seguro.propostas'], 'spmae.id = sp.id_proposta_mae', ['spmae.dt_transmissao', 'spmae.id_produto']);
        $queryProposta->where('sp.id = ?', $idPropostaVigente);

        $proposta = self::$db->fetchRow($queryProposta);
        
        $dataTransmissao = !empty($proposta['dt_transmissao'])
            ? $proposta['dt_transmissao']
            : date('Y-m-d H:i:s');

        $dataTransmissao = substr($dataTransmissao, 0, 10);
        
        $sql = 'WITH configuracao AS (
                SELECT
                    condicao_especial_configuracao.id,
                    condicao_especial_configuracao.id_condicao_especial,
                    ROW_NUMBER() OVER (
                        PARTITION BY condicao_especial_configuracao.id_condicao_especial
                        ORDER BY dt_inicio_validade DESC
                    ) AS rn
                FROM produto.condicao_especial_configuracao
                INNER JOIN produto.produtos_coberturas_condicoes_especiais cond
                    ON cond.id_condicao_especial = condicao_especial_configuracao.id_condicao_especial
                WHERE cond.id_produto = '. $proposta['id_produto'] .'
                    AND condicao_especial_configuracao.dt_inicio_validade <= \''. $dataTransmissao .'\'
                    AND condicao_especial_configuracao.fl_ativo IS TRUE
            ) SELECT
                configuracao.id,
                configuracao.id_condicao_especial,
                ds_titulo,
                ds_complemento
            FROM configuracao
            INNER JOIN produto.condicoes_especiais
                ON condicoes_especiais.id = configuracao.id_condicao_especial
            WHERE rn = 1';

        $configuracoes = self::$db->fetchAll($sql);

        return !empty($configuracoes)
            ? array_column($configuracoes, 'id')
            : [];
    }

    private function getCoberturasProposta(int $idPropostaVigente, int $idProduto)
    {
        $idsConfiguracoes = $this->getIdsConfiguracoesCondicoesEspeciais($idPropostaVigente);
        $placeHolderDsCarencia = !empty($idsConfiguracoes) ? null : new Zend_Db_Expr('null as ds_carencia');

        $query = self::$db->select();
        //@todo AJUSTAR PARA BUSCAR O fl_area_total
        $query->from(['spc' => 'seguro.propostas_coberturas'], ['id_cobertura', 'fl_principal', new Zend_Db_Expr('true as fl_area_total')]);
        $query->join(['pc' => 'produto.coberturas'], 'pc.id = spc.id_cobertura', ['ds_nome_cobertura']);
        $query->join(['ppc' => 'produto.produtos_coberturas'], 'ppc.id_cobertura = spc.id_cobertura', null);
        $query->join(['pcce' => 'produto.produtos_coberturas_condicoes_especiais'], 'pcce.id_cobertura = ppc.id_cobertura and pcce.id_produto = ppc.id_produto', $placeHolderDsCarencia);
        $query->where("spc.id_proposta = {$idPropostaVigente}");
        $query->where("ppc.id_produto = {$idProduto}");
        $query->where("ppc.fl_contratacao_automatica = false");
        
        if (!empty($idsConfiguracoes)) {
            $query->joinLeft(
                ['config' => 'produto.condicao_especial_configuracao'],
                'config.id_condicao_especial = pcce.id_condicao_especial',
                ['ds_condicao_especial as ds_carencia']
            );
            $query->where('config.id IN(?)', $idsConfiguracoes);
        }
        
        $query->order("ppc.fl_cobertura_principal DESC");

        return self::$db->fetchAll($query);
    }

    private function getCroquiProposta(int $idPropostaVigente)
    {
        $query = self::$db->select();
        $query->from(['spc' => 'seguro.propostas_croquis'], null);
        $query->join(['spct' => 'seguro.propostas_croquis_talhoes'], 'spct.id_croqui = spc.id', ['id_croqui', 'ds_coordenadas', 'ds_nome as ds_nome_item']);
        $query->join(['temp' => 'itens_segurados_croqui_temp'], 'temp.id_propostas_croquis_talhoes = spct.id', null);
        $query->join(['sis' => 'seguro.itens_segurados'], 'sis.id = temp.id_item_segurado::integer', ['id as id_item_segurado', 'nr_item_segurado', 'vl_area']);
        $query->where("spc.id_proposta = {$idPropostaVigente}");
        $query->where("spc.fl_vigente is true");
        $query->where("sis.vl_area > 0");
        $query->where("sis.vl_lmga > 0");

        $rs = self::$db->fetchAll($query);
        $croqui = [];
        foreach ($rs as $index => $row) {
            $croqui['id_croqui'] = $row['id_croqui'];

            $croqui['itens'][] = [
                'ds_coordenadas' => json_decode($row['ds_coordenadas']),
                'ds_nome_item' => $row['ds_nome_item'],
                'vl_area' => $row['vl_area'],
                'id_item_segurado' => $row['id_item_segurado'],
                'nr_item_segurado' => $row['nr_item_segurado']
            ];
        }

        return $croqui;
    }

    private function getObservacoesAdicionaisProposta($idPropostaVigente)
    {
        $query = self::$db->select();
        $query->from(['spo' => 'seguro.propostas_observacoes'], ['ds_observacao']);
        $query->where("spo.id_proposta = {$idPropostaVigente}");
        $query->where("spo.fl_observacao_endosso is true");

        $rs = self::$db->fetchAll($query);

        $observacoes = '';
        foreach ($rs as $index => $row) {

            if ($index > 0) {
                $observacoes .= "\n";
            }

            $observacoes .= $row['ds_observacao'];
        }

        return $observacoes;
    }

    private function getAutorizadosProposta(int $idPropostaVigente)
    {
        $query = self::$db->select();
        $query->from(['sppav' => 'seguro.propostas_pessoa_autorizada_vistoria'], ['cpf_cnpj', 'ds_pessoa_autorizada', 'ds_telefone', 'ds_grau_parentesco']);
        $query->where("sppav.id_proposta = {$idPropostaVigente}");
       
        return self::$db->fetchAll($query);
    }

    private function getAvisos(int $idPropostaVigente)
    {
        $query = self::$db->select();
        $query->from(['sa' => 'sinistro.avisos'], ['id as id_aviso', 'fl_ocorrencia_replantio', 'id_proposta', 'ds_observacoes', 'dt_sinistro', 'dt_criacao as dt_envio', 'ds_pessoa_contato', 'ds_telefone_contato']);
        $query->join(['sae' => 'sinistro.avisos_eventos'], 'sae.id_aviso = sa.id', ['id_evento']);
        $query->join(['pe' => 'produto.eventos'], 'pe.id = sae.id_evento', ['ds_nome_evento']);
        $query->joinLeft(['sapc' => 'sinistro.avisos_pessoas_contato'], 'sapc.id_aviso = sa.id', ['ds_nome', 'ds_telefone']);
        $query->where("sa.id_proposta = {$idPropostaVigente}");

        $rs = self::$db->fetchAll($query);
        $avisos = [];
        foreach ($rs as $index => $row) {

            if (array_key_exists($row['id_aviso'], $avisos)) {
                if (!empty($row['ds_nome'])) {
                    $avisos[$row['id_aviso']]['contatos_adicionais'][] = [
                        'ds_nome' => $row['ds_nome'],
                        'ds_telefone' => $row['ds_telefone']
                    ];
                }

                continue;
            }

            $avisos[$row['id_aviso']]['id_aviso'] = $row['id_aviso'];
            $avisos[$row['id_aviso']]['ds_observacoes'] = $row['ds_observacoes'];
            $avisos[$row['id_aviso']]['dt_sinistro'] = $row['dt_sinistro'];
            $avisos[$row['id_aviso']]['dt_envio'] = $row['dt_envio'];
            $avisos[$row['id_aviso']]['contatos_adicionais'] = [];

            if (!empty($row['ds_nome'])) {
                $avisos[$row['id_aviso']]['contatos_adicionais'][] = [
                    'ds_nome' => $row['ds_nome'],
                    'ds_telefone' => $row['ds_telefone']
                ];
            }

            $avisos[$row['id_aviso']]['cobertura'] = $this->getCoberturasAviso($idPropostaVigente, $row['id_evento'], $row['fl_ocorrencia_replantio']);
        }

        //Para resetar as chaves do array
        return array_values($avisos);
    }

    private function getCoberturasAviso(int $idPropostaVigente, int $idEvento, ?bool $flOcorrenciaReplantio = false)
    {
        $idsConfiguracoes = $this->getIdsConfiguracoesCondicoesEspeciais($idPropostaVigente);
        $placeHolderDsCarencia = !empty($idsConfiguracoes) ? null : new Zend_Db_Expr('null as ds_carencia');

        $query = self::$db->select();
        //@todo verificar campo id_tipo_cobertura
        $query->from(['spc' => 'seguro.propostas_coberturas'], ['id_cobertura']);
        $query->join(['spr' => 'seguro.propostas'], 'spr.id = spc.id_proposta', null);
        $query->join(['pce' => 'produto.coberturas_eventos'], "pce.id_evento = {$idEvento} AND pce.id_cobertura = spc.id_cobertura", ['id_evento']);
        $query->join(['pe' => 'produto.eventos'], "pe.id = pce.id_evento", ['ds_nome_evento']);
        $query->join(['pc' => 'produto.coberturas'], 'pc.id = pce.id_cobertura', ['ds_nome_cobertura']);
        $query->join(['ppc' => 'produto.produtos_coberturas'], 'ppc.id_cobertura = spc.id_cobertura AND ppc.id_produto = spr.id_produto', null);
        $query->join(['stlf' => 'sinistro.tipo_laudo_final'],  'stlf.id = ppc.id_tipo_laudo_final', ['id as id_tipo_cobertura']);
        $query->join(['pcce' => 'produto.produtos_coberturas_condicoes_especiais'], 'pcce.id_cobertura = ppc.id_cobertura and pcce.id_produto = ppc.id_produto', $placeHolderDsCarencia);
        $query->where("spc.id_proposta = {$idPropostaVigente}");

        if (!empty($idsConfiguracoes)) {
            $query->joinLeft(
                ['config' => 'produto.condicao_especial_configuracao'],
                'config.id_condicao_especial = pcce.id_condicao_especial',
                ['ds_condicao_especial as ds_carencia']
            );
            $query->where('config.id IN (?)', $idsConfiguracoes);
        }

        if ($flOcorrenciaReplantio) {
            $query->where("pc.ds_chave_cobertura ilike '%REPLANTIO%'");
        } else {
            $query->where("pc.ds_chave_cobertura not ilike '%REPLANTIO%'");
        }

        $rs = self::$db->fetchAll($query);

        $cobertura = [];
        foreach ($rs as $row) {
            $cobertura['id_cobertura'] = $row['id_cobertura'];
			$cobertura['ds_nome_cobertura'] = $row['ds_nome_cobertura'];
			$cobertura['ds_carencia'] = $row['ds_carencia'];
			$cobertura['id_tipo_cobertura'] = $row['id_tipo_cobertura'];
            $cobertura['evento']['id_evento'] = $row['id_evento'];
            $cobertura['evento']['ds_nome_evento'] = $row['ds_nome_evento'];
        }

        return $cobertura;
    }


    public function getPathLaudos(string $nomeArquivo): string
    {
        return $this->urlAmbiente . "/laudos/{$nomeArquivo}";
    }

    /**
     * @return array
     */
    private function getZoneamento() : array
    {
        $query = self::$db->select();
        $query->from(['svz' => 'sistema.versao_zoneamento'], ["to_char(dt_criacao, 'DD/MM/YYYY HH24:MM:SS') as dt_alteracao", 'ds_nome_arquivo', 'md5']);
        $query->where('fl_ativo = true');

        $rs = self::$db->fetchRow($query);
        $dadosRetorno = [];

        if (!empty($rs)) {
            $dadosRetorno['zoneamento']['dt_alteracao'] = $rs['dt_alteracao'];
            $dadosRetorno['zoneamento']['md5_arquivo'] = $rs['md5'];
            $dadosRetorno['zoneamento']['link'] = $this->urlAmbiente . "/db_zoneamento/{$rs['ds_nome_arquivo']}";
        }

        return $dadosRetorno;
    }
    
    public function sendImage()
    {
        if (!empty($_FILES['image']['name'])) {
            $nomeSeparado = explode("_", $_FILES['image']['name']);
            $idVistoria = !empty($nomeSeparado[2]) ? $nomeSeparado[2] : null;
            if ($this->isVistoriasGoogleApple($idVistoria)) {
                http_response_code(200);
                return array('status' => true, 'message' => "Imagem {$_FILES['image']['name']} salva com sucesso.");
            }
        }

        try {
            $allowExtensions = ['png', 'jpg', 'jpeg', 'tiff', 'mp4']; // tipo de imagens aceito (NÃO COLOCAR PDF AQUI!)
            $allowMaxImageSize = 15728640.01; // 15Mb
            $usuario = $this->checkToken();

            $this->setDb();
            $db = self::$db;
            $db->beginTransaction();

            if (!is_array($usuario)) {
                throw new Exception($this->getError(0), 401);
            }

            if (count($_FILES) > 1) {
                throw new Exception($this->getError(12), 400);
            }

            if (!isset($_FILES['image']) || $_FILES['image']['error'] !== UPLOAD_ERR_OK) {
                throw new Exception($this->getError(11), 400);
            } else {
                $ext = strtolower(explode('/', $_FILES['image']['type'])[1]);

                if (!in_array($ext, $allowExtensions)) {
                    throw new Exception($this->getError(11), 415);
                }

                //if ($_FILES['image']['size'] > $allowMaxImageSize) {
                //    throw new Exception($this->getError(11), 400);
                //}

                $nomeArquivo = $_FILES['image']['name'];

                $path = __DIR__ . '/../../../../application/upload_files/laudofinal/' . $nomeArquivo;
                move_uploaded_file($_FILES['image']['tmp_name'], "$path");
                    
                (new Agro_APIs_VSD_Vistoria())->validarRecebimentoTodosArquivos($nomeArquivo, $usuario, $db);
                $db->commit();
            }

            http_response_code(200);
            return array('status' => true, "message" => "Imagem {$_FILES['image']['name']} salva com sucesso.");

        } catch (\Throwable $th) {

            $db->rollback();
            $code = empty($th->getCode()) ? 500 : $th->getCode();
            http_response_code($code);
            return array('status' => false, 'message' => "{$th->getMessage()}");
        }
    }
    
    public function setvistoria($vistoria)
    {
        if ($this->isVistoriasGoogleApple($vistoria['id_vistoria'])) {
            http_response_code(200);
            return array('status' => true, 'message' => 'Vistoria salva com sucesso!');
        }

        try {
            $this->setDb();
            $db = self::$db;
            $db->beginTransaction();

            $log = new Agro_Log(Agro_Log::VSD);
            $log->setParams($vistoria);
            $log->setRota('setvistoria');

            $usuario = $this->checkToken();

            if (!is_array($usuario)) {
                throw new Exception($this->getError(0), 401);
            }

            $log->setUsuario($usuario);

            $erros = (new Agro_Validator())->validarSetVistoria($vistoria);

            if (!empty($erros)) {

                $mensagem = "Os seguintes erros foram encontrados: \n - ";
                $mensagem .= implode("\n - ", $erros);
                throw new Exception($mensagem);
            }

            $modelVistoria = new Agro_APIs_VSD_Vistoria();
            $modelVistoria->salvar($vistoria, $usuario, $db);

            $log->logSuccess("Info: Vistoria salva com sucesso!\n");
            $db->commit();
        } catch (\Throwable $th) {

            $db->rollback();
            $mensagem = $th->getMessage();
            $log->logError("Erro: " . $mensagem . "\n");

            $code = empty($th->getCode()) ? 500 : $th->getCode();
            $status = false;

            // Caso retorne o erro de duplicate key, retornamos o status 200. Isso ocorre
            // casos onde há 2x o setvistoria ao mesmo tempo para a mesma vistoria.
            // O maior problema desse bug, é que depois de isso acontecer, normalmente
            // o processo é encerrado aí (não vem o setlogvistoria nem o sendimage)
            // e a vistoria fica como "Transmitida Sem Fotos".
            if (strpos($mensagem, 'duplicate key') !== false) {
                $code = 200;
                $status = true;
            }

            http_response_code($code);
            return array('status' => $status, 'message' => $mensagem);
        }

        //rabbitmq
        $os = strtoupper(substr(PHP_OS, 0, 3));
        $env = ($os == 'WIN') ? 'docker' : getenv('APPLICATION_ENV');
        
        $modelRpcClient = new Agro_RabbitMQ_VSD_RpcClient($env, 'vsd');
        $modelRpcClient->execute([
            'id_vistoria' => $vistoria['id_vistoria'],
            'id_usuario' => $usuario['id'],
            'acao' => 'gerarNovaVistoria'
        ]);

        //É necessário uma nova instância para que não seja finalizada a fila antes de adicionar o segundo processamento
        $modelRpcClient2 = new Agro_RabbitMQ_VSD_RpcClient($env, 'vsd');
        $modelRpcClient2->execute([
            'id_laudo_final' => $modelVistoria->getIdLaudoFinal(),
            'acao' => 'enviarTermoAutorizacao'
        ]);

        //Gera o PDF do laudo final
        $modelRpcClient3 = new Agro_RabbitMQ_VSD_RpcClient($env, 'vsd');
        $modelRpcClient3->execute([
            'id_laudo_final' => $modelVistoria->getIdLaudoFinal(),
            'id_tipo_laudo_final' => $modelVistoria->getIdTipoLaudoFinal(),
            'acao' => 'gerarLaudoFinal'
        ]);

        //Gera o laudo final do segurado (só com itens assinados) e envia PDF do laudo final de acordo com o tipo de envio
        $modelRpcClient4 = new Agro_RabbitMQ_VSD_RpcClient($env, 'vsd');
        $modelRpcClient4->execute([
            'id_laudo_final' => $modelVistoria->getIdLaudoFinal(),
            'id_tipo_laudo_final' => $modelVistoria->getIdTipoLaudoFinal(),
            'acao' => 'enviarLaudoFinal'
        ]);

        http_response_code(200);
        return array('status' => true, 'message' => 'Vistoria salva com sucesso!');
    }

    public function setlogvistoria($id_vistoria, $id_proposta, $itens)
    {
        if ($this->isVistoriasGoogleApple($id_vistoria)) {
            http_response_code(200);
            return array('status' => true, 'message' => 'Logs salvos com sucesso!');
        }

        try {
            $this->setDb();
            $db = self::$db;
            $db->beginTransaction();

            $log = new Agro_Log(Agro_Log::VSD);
            $log->setParams(["id_vistoria" => $id_vistoria, "id_proposta" => $id_proposta, 'itens' => $itens]);
            $log->setRota('setlogvistoria');

            $usuario = $this->checkToken();

            if (!is_array($usuario)) {
                throw new Exception($this->getError(0), 401);
            }

            $log->setUsuario($usuario);

            $erros = (new Agro_Validator())->validarSetLogVistoria($id_vistoria, $id_proposta, $itens);

            if (!empty($erros)) {

                $mensagem = "Os seguintes erros foram encontrados: \n - ";
                $mensagem .= implode("\n - ", $erros);
                throw new Exception($mensagem);
            }

            (new Agro_APIs_VSD_Vistoria())->salvarLog($id_vistoria, $id_proposta, $itens, $usuario, $db);

            $log->logSuccess("Info: Log da vistoria salva com sucesso!\n");
            $db->commit();
        } catch (\Throwable $th) {

            $db->rollback();
            $log->logError("Erro: " . $th->getMessage() . "\n");

            $code = empty($th->getCode()) ? 500 : $th->getCode();
            http_response_code($code);
            return array('status' => false, 'message' => $th->getMessage());
        }

        http_response_code(200);
        return array('status' => true, 'message' => 'Logs salvos com sucesso!');
    }

    public function limparvistorias($vistorias)
    {
        foreach ($vistorias as $vistoria) {
            if ($this->isVistoriasGoogleApple($vistoria['id_vistorias'])) {
                http_response_code(200);
                return array('status' => true, 'message' => 'Vistorias atualizadas com sucesso!');
            }
        }

        try {
            $this->setDb();
            $db = self::$db;
            $db->beginTransaction();

            $log = new Agro_Log(Agro_Log::VSD);
            $log->setParams($vistorias);
            $log->setRota('limparvistorias');

            $usuario = $this->checkToken();

            if (!is_array($usuario)) {
                throw new Exception($this->getError(0), 401);
            }

            $log->setUsuario($usuario);
            $erros = (new Agro_Validator())->validarLimparVistorias($vistorias);

            if (!empty($erros)) {

                $mensagem = "Os seguintes erros foram encontrados: \n - ";
                $mensagem .= implode("\n - ", $erros);
                throw new Exception($mensagem);
            }

            foreach ($vistorias as $vistoria) {
                (new Agro_APIs_VSD_Vistoria())->limparVistoria($vistoria['id_vistoria'], $usuario, $db);
            }

            $log->logSuccess("Info: Excluido vistoria do app com sucesso!\n");
            $db->commit();
        } catch (\Throwable $th) {

            $db->rollback();
            $log->logError("Erro: " . $th->getMessage() . "\n");

            $code = empty($th->getCode()) ? 500 : $th->getCode();
            http_response_code($code);
            return array('status' => false, 'message' => $th->getMessage());
        }

        http_response_code(200);
        return array('status' => true, 'message' => 'Vistorias atualizadas com sucesso!');
    }

    public function atualizarstatusvistoria($vistoria)
    {
        if ($this->isVistoriasGoogleApple($vistoria['id_vistoria'])) {
            http_response_code(200);
            return array('status' => true, 'message' => 'Status atualizado com sucesso!');
        }

        try {
            $this->setDb();
            $db = self::$db;
            $db->beginTransaction();

            $log = new Agro_Log(Agro_Log::VSD);
            $log->setParams($vistoria);
            $log->setRota('atualizarstatusvistoria');

            $usuario = $this->checkToken();

            if (!is_array($usuario)) {
                throw new Exception($this->getError(0), 401);
            }

            $log->setUsuario($usuario);

            $erros = (new Agro_Validator())->validarAtualizarVistoria($vistoria);

            if (!empty($erros)) {

                $mensagem = "Os seguintes erros foram encontrados: \n - ";
                $mensagem .= implode("\n - ", $erros);
                throw new Exception($mensagem);
            }

            (new Agro_APIs_VSD_Vistoria())->atualizarStatusVistoria($vistoria, $usuario, $db);

            $log->logSuccess("Info: Status da vistoria salvo com sucesso!\n");
            $db->commit();
        } catch (\Throwable $th) {

            $db->rollback();
            $log->logError("Erro: " . $th->getMessage() . "\n");

            $code = empty($th->getCode()) ? 500 : $th->getCode();
            http_response_code($code);
            return array('status' => false, 'message' => $th->getMessage());
        }

        http_response_code(200);
        return array('status' => true, 'message' => 'Status atualizado com sucesso!');
    }

    /**
     * Valida se as vistorias informadas são as utilizadas pelo Google e pela Apple
     * para a validação do APP (normalmente feita ao atualizar na loja)
     */
    private function isVistoriasGoogleApple($idVistoria): bool
    {
        if (!empty($idVistoria) && in_array($idVistoria, $this->exceptionVistorias)) {
            return true;
        }

        return false;
    }
}
