<?php
class Agro_Validator
{
    private $errors = [];

    /**
     * Valida os dados da vistoria que foram enviados na requisição setvistoria e retorna um array com os erros
     * 
     * @param array $vistoria
     */
    public function validarSetVistoria(array $vistoria): array
    {
        $template = file_get_contents(__DIR__ . '/templates/retorno.json');
        $template = json_decode($template, true);

        foreach ($template[0]['vistoria'] as $chaveTemplate => $valorTemplate) {
            
            if (!array_key_exists($chaveTemplate, $vistoria)) {
                $this->errors[] = "O campo '{$chaveTemplate}' não foi informado.";
                continue;
            }

            if (empty($vistoria[$chaveTemplate])) {
                continue;
            }

            switch ($chaveTemplate) {
                case 'acompanhante':
                    $this->validarAcompanhante($valorTemplate, $vistoria[$chaveTemplate]);
                    continue 2;
                    break;
                case 'segurado':
                    $this->validarSegurado($valorTemplate, $vistoria[$chaveTemplate]);
                    continue 2;
                    break;
                case 'itens':
                    $this->validarItens($valorTemplate, $vistoria[$chaveTemplate]);
                    continue 2;
                    break;
                case 'croqui':
                    $this->validarCroqui($valorTemplate, $vistoria[$chaveTemplate]);
                    continue 2;
                    break;
                case 'assinaturas_peritos':
                    $this->validarAssinaturasPeritos($valorTemplate, $vistoria[$chaveTemplate]);
                    continue 2;
                    break;
                case 'assinaturas_agronomos':
                    $this->validarAssinaturasAgronomos($valorTemplate, $vistoria[$chaveTemplate]);
                    continue 2;
                    break;
                case 'fotos_vistoria':
                    $this->validarFotosVistoria($valorTemplate, $vistoria[$chaveTemplate]);
                    continue 2;
                    break;
            }

            $this->validarTipagem($vistoria, $chaveTemplate, $valorTemplate);
        }

        return $this->errors;
    }


    /**
     * Valida os dados das coordenadas das fotos da vistoria
     * 
     * @param array $dadosTemplateFotosVistoriaCoordenada
     * @param array $dadosFotosVistoriaCoordenada
     */
    private function validarFotosVistoriaCoordenada(array $dadosTemplateFotosVistoriaCoordenada, array $dadosFotosVistoriaCoordenada): void
    {
        foreach ($dadosTemplateFotosVistoriaCoordenada as $chaveTemplate => $valorTemplate) {

            if (!array_key_exists($chaveTemplate, $dadosFotosVistoriaCoordenada)) {
                $this->errors[] = "O campo '{$chaveTemplate}' não foi informado.";
                continue;
            }

            $this->validarTipagem($dadosFotosVistoriaCoordenada, $chaveTemplate, $valorTemplate);
        }
    }

    /**
     * Valida os dados das fotos da vistoria
     * 
     * @param array $dadosTemplateFotosVistoria
     * @param array $dadosFotosVistoria
     */
    private function validarFotosVistoria(array $dadosTemplateFotosVistoria, array $dadosFotosVistoria): void
    {
        foreach ($dadosTemplateFotosVistoria[0] as $chaveFotosVistoriaTemplate => $valorFotosVistoriaTemplate) {
            foreach ($dadosFotosVistoria as $dadoFotosVistoria) {
                if (!array_key_exists($chaveFotosVistoriaTemplate, $dadoFotosVistoria)) {
                    $this->errors[] = "O campo '{$chaveFotosVistoriaTemplate}' não foi informado.";
                    continue;
                }

                if ($chaveFotosVistoriaTemplate == 'ds_coordenada') {
                    $this->validarFotosVistoriaCoordenada($valorFotosVistoriaTemplate, $dadoFotosVistoria[$chaveFotosVistoriaTemplate]);
                    continue;
                }

                $this->validarTipagem($dadoFotosVistoria, $chaveFotosVistoriaTemplate, $valorFotosVistoriaTemplate);
            }
        }
    }

    /**
     * Valida os dados do acompanhante
     * 
     * @param array $dadosTemplateAcompanhante
     * @param array $dadosAcompanhante
     */
    private function validarAcompanhante(array $dadosTemplateAcompanhante, array $dadosAcompanhante): void
    {
        foreach ($dadosTemplateAcompanhante as $chaveTemplate => $valorTemplate) {

            if (!array_key_exists($chaveTemplate, $dadosAcompanhante)) {
                $this->errors[] = "O campo '{$chaveTemplate}' não foi informado.";
                continue;
            }

            if ($chaveTemplate == 'documentos') {
                $this->validarAcompanhanteDocumentos($valorTemplate, $dadosAcompanhante[$chaveTemplate]);
                continue;
            }

            $this->validarTipagem($dadosAcompanhante, $chaveTemplate, $valorTemplate);
        }
    }

    /**
     * Valida os dados dos documentos do acompanhante
     * 
     * @param array $dadosTemplateDocumentos
     * @param array $dadosDocumentos
     */
    private function validarAcompanhanteDocumentos(array $dadosTemplateDocumentos, array $dadosDocumentos): void
    {
        foreach ($dadosTemplateDocumentos as $chaveTemplate => $valorTemplate) {

            if (!array_key_exists($chaveTemplate, $dadosDocumentos)) {
                $this->errors[] = "O campo '{$chaveTemplate}' não foi informado.";
                continue;
            }

            if ($chaveTemplate == 'video' && !empty($dadosDocumentos[$chaveTemplate]))  {
                $this->validarAcompanhanteDocumentosVideo($valorTemplate, $dadosDocumentos[$chaveTemplate]);
                continue;
            }

            if ($chaveTemplate == 'arquivos') {
                $this->validarAcompanhanteDocumentosArquivos($valorTemplate, $dadosDocumentos[$chaveTemplate]);
                continue;
            }
        }
    }

    /**
     * Valida os dados dos arquivos dos documentos do acompanhante
     * 
     * @param array $dadosTemplateDocumentosArquivos
     * @param array $dadosArquivos
     */
    private function validarAcompanhanteDocumentosArquivos(array $dadosTemplateDocumentosArquivos, array $dadosArquivos): void
    {
        foreach ($dadosTemplateDocumentosArquivos[0] as $chaveArquivoTemplate => $valorArquivoTemplate) {
            foreach ($dadosArquivos as $dadosArquivo) {

                if (!array_key_exists($chaveArquivoTemplate, $dadosArquivo)) {
                    $this->errors[] = "O campo '{$chaveArquivoTemplate}' não foi informado.";
                    continue;
                }

                if ($chaveArquivoTemplate == 'ds_coordenada') {
                    $this->validarAcompanhanteDocumentosCoordenada($valorArquivoTemplate, $dadosArquivo[$chaveArquivoTemplate]);
                    continue;
                }

                if ($chaveArquivoTemplate == 'ds_tipo_arquivo') {
                    if (!in_array($dadosArquivo[$chaveArquivoTemplate], ['FOTO_ACOMPANHANTE_DOC', 'FOTO_DOC_FRENTE', 'FOTO_DOC_VERSO', 'FOTO_AUTORIZACAO', 'FOTO_LOCAL_OU_GPS'])) {
                        $this->errors[] = "O campo 'ds_tipo_arquivo' inválido. Valores aceitos: 'FOTO_ACOMPANHANTE_DOC', 'FOTO_DOC_FRENTE', 'FOTO_DOC_VERSO', 'FOTO_AUTORIZACAO' ou 'FOTO_LOCAL_OU_GPS'.";
                        continue;
                    }
                }

                $this->validarTipagem($dadosArquivo, $chaveArquivoTemplate, $valorArquivoTemplate);
            }
        }
    }

    /**
     * Valida os dados do vídeo dos documentos do acompanhante
     * 
     * @param array $dadosTemplateDocumentosVideo
     * @param array $dadosVideo
     */
    private function validarAcompanhanteDocumentosVideo(array $dadosTemplateDocumentosVideo, array $dadosVideo): void
    {
        foreach ($dadosTemplateDocumentosVideo as $chaveTemplate => $valorTemplate) {

            if (!array_key_exists($chaveTemplate, $dadosVideo)) {
                $this->errors[] = "O campo '{$chaveTemplate}' não foi informado.";
                continue;
            }

            if ($chaveTemplate == 'ds_coordenada') {
                $this->validarAcompanhanteDocumentosCoordenada($valorTemplate, $dadosVideo[$chaveTemplate]);
                continue;
            }
            
            $this->validarTipagem($dadosVideo, $chaveTemplate, $valorTemplate);
        }
    }

    /**
     * Valida os dados da coordenada dos arquivos dos documentos do acompanhante
     * 
     * @param array $dadosTemplateDocumentosCoordenada
     * @param array $dadosCoordenada
     */
    private function validarAcompanhanteDocumentosCoordenada(array $dadosTemplateDocumentosCoordenada, array $dadosCoordenada): void
    {
        foreach ($dadosTemplateDocumentosCoordenada as $chaveTemplate => $valorTemplate) {

            if (!array_key_exists($chaveTemplate, $dadosCoordenada)) {
                $this->errors[] = "O campo '{$chaveTemplate}' não foi informado.";
                continue;
            }

            $this->validarTipagem($dadosCoordenada, $chaveTemplate, $valorTemplate);
        }
    }

    /**
     * Valida os dados do segurado
     * 
     * @param array $dadosTemplateSegurado
     * @param array $dadosSegurados
     */
    private function validarSegurado(array $dadosTemplateSegurado, array $dadosSegurados): void
    {
        foreach ($dadosTemplateSegurado as $chaveTemplate => $valorTemplate) {
            if (!array_key_exists($chaveTemplate, $dadosSegurados)) {
                $this->errors[] = "O campo '{$chaveTemplate}' não foi informado.";
                continue;
            }

            if ($chaveTemplate == 'tp_envio_doc_acompanhante' || $chaveTemplate == 'tp_envio_laudo') {
                if (!empty($dadosSegurados[$chaveTemplate]) && !in_array($dadosSegurados[$chaveTemplate], ['WHATS', 'EMAIL'])) {
                    $this->errors[] = "O campo '{$chaveTemplate}' inválido. Valores aceitos: 'WHATS' ou 'EMAIL'.";
                    continue;
                }
            }

            $this->validarTipagem($dadosSegurados, $chaveTemplate, $valorTemplate);
        }
    }

    /**
     * Valida os dados dos itens
     * 
     * @param array $dadosTemplateItens
     * @param array $dadosItens
     */
    private function validarItens(array $dadosTemplateItens, array $dadosItens): void
    {
        foreach ($dadosTemplateItens[0] as $chaveItemTemplate => $valorItemTemplate) {
            foreach ($dadosItens as $dadosItem) {

                if (!array_key_exists($chaveItemTemplate, $dadosItem)) {
                    $this->errors[] = "O campo '{$chaveItemTemplate}' não foi informado.";
                    continue;
                }

                switch ($chaveItemTemplate) {
                    case 'id_tipo_cobertura':
                        if (!in_array($dadosItem[$chaveItemTemplate], [157, 170])) {
                            $this->errors[] = "O campo '{$chaveItemTemplate}' inválido. Valores aceitos: 157 ou 170.";
                        }
                        continue 2;
                        break;
                    case 'ds_tipo_amostragem':
                        //@todo pode este campos ser null??
                        if (!empty($dadosItem[$chaveItemTemplate]) && !in_array($dadosItem[$chaveItemTemplate], ['MANUAL', 'MECANIZADA'])) {
                            $this->errors[] = "O campo '{$chaveItemTemplate}' inválido. Valores aceitos: 'MANUAL' ou 'MECANIZADA'.";
                        }
                        continue 2;
                        break;
                    case 'fotos_item':
                        $this->validarFotosItem($valorItemTemplate, $dadosItem[$chaveItemTemplate]);
                        continue 2;
                        break;
                    case 'mecanizado':
                        if ($dadosItem['ds_tipo_amostragem'] == 'MECANIZADA' && !empty($dadosItem[$chaveItemTemplate])) {
                            $this->validarMecanizado($valorItemTemplate, $dadosItem[$chaveItemTemplate]);
                        }
                        continue 2;
                        break;
                    case 'manual':
                        if ($dadosItem['ds_tipo_amostragem'] == 'MANUAL' && !empty($dadosItem[$chaveItemTemplate])) {
                            $this->validarManual($valorItemTemplate, $dadosItem[$chaveItemTemplate]);
                        }
                        continue 2;
                        break;
                    case 'riscos_nao_cobertos':
                        $this->validarRiscosNaoCobertos($valorItemTemplate, $dadosItem[$chaveItemTemplate]);
                        continue 2;
                        break;
                    case 'avarias':
                        $this->validarAvarias($valorItemTemplate, $dadosItem[$chaveItemTemplate]);
                        continue 2;
                        break;
                }

                $this->validarTipagem($dadosItem, $chaveItemTemplate, $valorItemTemplate);
            }
        }
    }

    /**
     * Valida os dados das fotos de um item
     * 
     * @param array $dadosTemplateFotosItem
     * @param array $dadosFotosItem
     */
    private function validarFotosItem (array $dadosTemplateFotosItem, array $dadosFotosItem): void
    {
        foreach ($dadosTemplateFotosItem[0] as $chaveFotosItemTemplate => $valorFotosItemTemplate) {
            foreach ($dadosFotosItem as $dadosFotoItem) {

                if (!array_key_exists($chaveFotosItemTemplate, $dadosFotoItem)) {
                    $this->errors[] = "O campo '{$chaveFotosItemTemplate}' não foi informado.";
                    continue;
                }

                if ($chaveFotosItemTemplate == 'ds_tipo_arquivo') {
                    $tiposAceitos = [
                        'FOTO_LOCAL_INICIO', 'FOTO_LOCAL_ZONEAMENTO', 'FOTO_LOCAL_DISPENSA_VISTORIA', 'FOTO_LOCAL_NEGACAO_ITEM', 'FOTO_TELA_GPS', 'FOTO_VISTORIA_ITEM',
                        'FOTO_GPS_MECANIZADA_INICIO', 'FOTO_GPS_MECANIZADA_TERMINO', 'FOTO_INICIO_MANUAL', 'FOTO_GPS_MANUAL', 'FOTO_AMOSTRA_MANUAL', 'FOTO_PESAGEM_AMOSTRA_MANUAL',
                        'FOTO_AMOSTRA_MECANIZADA'
                    ];
                    if (!in_array($dadosFotoItem[$chaveFotosItemTemplate], $tiposAceitos)) {
                        $mensagem = "O campo 'ds_tipo_arquivo' inválido. Valores aceitos: 'FOTO_LOCAL_INICIO', 'FOTO_LOCAL_ZONEAMENTO', 'FOTO_LOCAL_DISPENSA_VISTORIA', 'FOTO_LOCAL_NEGACAO_ITEM', 'FOTO_TELA_GPS', 'FOTO_VISTORIA_ITEM'";
                        $mensagem .= " 'FOTO_GPS_MECANIZADA_INICIO', 'FOTO_GPS_MECANIZADA_TERMINO', 'FOTO_INICIO_MANUAL', 'FOTO_GPS_MANUAL', 'FOTO_AMOSTRA_MANUAL', 'FOTO_PESAGEM_AMOSTRA_MANUAL' ou 'FOTO_AMOSTRA_MECANIZADA'";
                        
                        $this->errors[] = $mensagem;
                        continue;
                    }
                }

                if ($chaveFotosItemTemplate == 'ds_coordenada') {
                    $this->validarFotosItemCoordenada($valorFotosItemTemplate, $dadosFotoItem[$chaveFotosItemTemplate]);
                    continue;
                }

                $this->validarTipagem($dadosFotoItem, $chaveFotosItemTemplate, $valorFotosItemTemplate);
            }
        }
    }

    /**
     * Valida os dados da coordenada das fotos dos itens
     * 
     * @param array $dadosTemplateFotosItemCoordenada
     * @param array $dadosCoordenada
     */
    private function validarFotosItemCoordenada(array $dadosTemplateFotosItemCoordenada, array $dadosCoordenada): void
    {
        foreach ($dadosTemplateFotosItemCoordenada as $chaveTemplate => $valorTemplate) {

            if (!array_key_exists($chaveTemplate, $dadosCoordenada)) {
                $this->errors[] = "O campo '{$chaveTemplate}' não foi informado.";
                continue;
            }

            $this->validarTipagem($dadosCoordenada, $chaveTemplate, $valorTemplate);
        }
    }

    /**
     * Valida os dados das amostragem mecanizadas
     * 
     * @param array $dadosTemplateMecanizado
     * @param array $dadosMecanizado
     */
    private function validarMecanizado(array $dadosTemplateMecanizado, array $dadosMecanizado): void
    {
        foreach ($dadosTemplateMecanizado as $chaveTemplate => $valorTemplate) {

            if (!array_key_exists($chaveTemplate, $dadosMecanizado)) {
                $this->errors[] = "O campo '{$chaveTemplate}' não foi informado.";
                continue;
            }

            if ($chaveTemplate == 'ds_coordenadas') {
                $this->validarMecanizadoCoordenadas($valorTemplate, $dadosMecanizado[$chaveTemplate]);
                continue;
            }

            $this->validarTipagem($dadosMecanizado, $chaveTemplate, $valorTemplate);
        }
    }

    /**
     * Valida as coordenadas das amostras mecanizadas
     * 
     * @param array $dadosTemplateMecanizadoCoordenadas
     * @param array $dadosMecanizadoCoordenadas
     */
    private function validarMecanizadoCoordenadas(array $dadosTemplateMecanizadoCoordenadas, array $dadosMecanizadoCoordenadas): void
    {
        foreach ($dadosTemplateMecanizadoCoordenadas[0] as $chaveMecanizadoCoordenadaTemplate => $valorMecanizadoCoordenadaTemplate) {
            foreach ($dadosMecanizadoCoordenadas as $dadosMecanizadoCoordenada) {
                if (!array_key_exists($chaveMecanizadoCoordenadaTemplate, $dadosMecanizadoCoordenada)) {
                    $this->errors[] = "O campo '{$chaveMecanizadoCoordenadaTemplate}' não foi informado.";
                    continue;
                }

                $this->validarTipagem($dadosMecanizadoCoordenada, $chaveMecanizadoCoordenadaTemplate, $valorMecanizadoCoordenadaTemplate);
            }
        }
    }

    /**
     * Valida os dados das amostragem manuais
     * 
     * @param array $dadosTemplateManual
     * @param array $dadosManual
     */
    private function validarManual(array $dadosTemplateManual, $dadosManual): void
    {
        foreach ($dadosTemplateManual as $chaveTemplate => $valorTemplate) {

            if (!array_key_exists($chaveTemplate, $dadosManual)) {
                $this->errors[] = "O campo '{$chaveTemplate}' não foi informado.";
                continue;
            }

            if ($chaveTemplate == 'amostras') {
                $this->validarAmostras($valorTemplate, $dadosManual[$chaveTemplate]);
                continue;
            }

            $this->validarTipagem($dadosManual, $chaveTemplate, $valorTemplate);
        }
    }

    /**
     * Valida os dados das amostras manuais
     * 
     * @param array $dadosTemplateAmostras
     * @param array $dadosAmostras
     */
    private function validarAmostras(array $dadosTemplateAmostras, array $dadosAmostras): void
    {
        foreach ($dadosTemplateAmostras[0] as $chaveAmostraTemplate => $valorAmostraTemplate) {
            foreach ($dadosAmostras as $dadosAmostra) {
                if (!array_key_exists($chaveAmostraTemplate, $dadosAmostra)) {
                    $this->errors[] = "O campo '{$chaveAmostraTemplate}' não foi informado.";
                    continue;
                }

                if ($chaveAmostraTemplate == 'ds_coordenada') {
                    $this->validarManualCoordenada($valorAmostraTemplate, $dadosAmostra[$chaveAmostraTemplate]);
                    continue;
                }

                $this->validarTipagem($dadosAmostra, $chaveAmostraTemplate, $valorAmostraTemplate);
            }
        }
    }

    /**
     * Valida a coordenada da amostra manual
     * 
     * @param array $dadosTemplateManualCoordenada
     * @param array $dadosCoordenada
     */
    private function validarManualCoordenada(array $dadosTemplateManualCoordenada, array $dadosCoordenada): void
    {
        foreach ($dadosTemplateManualCoordenada as $chaveTemplate => $valorTemplate) {

            if (!array_key_exists($chaveTemplate, $dadosCoordenada)) {
                $this->errors[] = "O campo '{$chaveTemplate}' não foi informado.";
                continue;
            }

            $this->validarTipagem($dadosCoordenada, $chaveTemplate, $valorTemplate);
        }
    }

    /**
     * Valida os dados dos riscos não cobertos de um item
     * 
     * @param array $dadosTemplateRiscosNaoCobertos
     * @param array $dadosRicosNaoCobertos
     */
    private function validarRiscosNaoCobertos(array $dadosTemplateRiscosNaoCobertos, array $dadosRicosNaoCobertos): void
    {
        foreach ($dadosTemplateRiscosNaoCobertos[0] as $chaveRiscoNaoCobertoTemplate => $valorRiscoNaoCobertoTemplate) {
            foreach ($dadosRicosNaoCobertos as $dadosRiscoNaoCoberto) {
                if (!array_key_exists($chaveRiscoNaoCobertoTemplate, $dadosRiscoNaoCoberto)) {
                    $this->errors[] = "O campo '{$chaveRiscoNaoCobertoTemplate}' não foi informado.";
                    continue;
                }

                $this->validarTipagem($dadosRiscoNaoCoberto, $chaveRiscoNaoCobertoTemplate, $valorRiscoNaoCobertoTemplate);
            }
        }
    }

    /**
     * Valida os dados das avarias de um item
     * 
     * @param array $dadosTemplateAvarias
     * @param array $dadosAvarias
     */
    private function validarAvarias(array $dadosTemplateAvarias, array $dadosAvarias): void
    {
        foreach ($dadosTemplateAvarias[0] as $chaveAvariasTemplate => $valorAvariasTemplate) {
            foreach ($dadosAvarias as $dadosAvaria) {
                if (!array_key_exists($chaveAvariasTemplate, $dadosAvaria)) {
                    $this->errors[] = "O campo '{$chaveAvariasTemplate}' não foi informado.";
                    continue;
                }

                $this->validarTipagem($dadosAvaria, $chaveAvariasTemplate, $valorAvariasTemplate);
            }
        }
    }

    /**
     * Valida os dados do croqui
     * 
     * @param array $dadosTemplateCroqui
     * @param array $dadosCroqui
     */
    private function validarCroqui(array $dadosTemplateCroqui, array $dadosCroqui): void
    {
        foreach ($dadosTemplateCroqui as $chaveTemplate => $valorTemplate) {
            if (!array_key_exists($chaveTemplate, $dadosCroqui)) {
                $this->errors[] = "O campo '{$chaveTemplate}' não foi informado.";
                continue;
            }

            if ($chaveTemplate == 'itens') {
                $this->validarCroquiItens($valorTemplate, $dadosCroqui[$chaveTemplate]);
                continue;
            }

            $this->validarTipagem($dadosCroqui, $chaveTemplate, $valorTemplate);
        }
    }

    /**
     * Valida os dados dos itens do croqui
     * 
     * @param array $dadosTemplateCroquiItens
     * @param array $dadosCroquiItens
     */
    private function validarCroquiItens(array $dadosTemplateCroquiItens, array $dadosCroquiItens): void
    {
        foreach ($dadosTemplateCroquiItens[0] as $chaveCroquiItemTemplate => $valorCroquiItemTemplate) {
            foreach ($dadosCroquiItens as $dadosCroquiItem) {
                if (!array_key_exists($chaveCroquiItemTemplate, $dadosCroquiItem)) {
                    $this->errors[] = "O campo '{$chaveCroquiItemTemplate}' não foi informado.";
                    continue;
                }

                if ($chaveCroquiItemTemplate == 'ds_coordenadas') {
                    $this->validarCroquiItemCoordenadas($valorCroquiItemTemplate, $dadosCroquiItem[$chaveCroquiItemTemplate]);
                    continue;
                }

                $this->validarTipagem($dadosCroquiItem, $chaveCroquiItemTemplate, $valorCroquiItemTemplate);
            }
        }
    }

    /**
     * Valida os dados das coordenadas de um item do croqui
     * 
     * @param array $dadosTemplateCroquiItemCoordenadas
     * @param array $dadosCroquiItemCoordenadas
     */
    private function validarCroquiItemCoordenadas(array $dadosTemplateCroquiItemCoordenadas, array $dadosCroquiItemCoordenadas): void
    {
        foreach ($dadosTemplateCroquiItemCoordenadas[0] as $chaveCroquiItemCoordenadaTemplate => $valorCroquiItemCoordenadaTemplate) {
            foreach ($dadosCroquiItemCoordenadas as $dadosCroquiItemCoordenada) {
                if (!array_key_exists($chaveCroquiItemCoordenadaTemplate, $dadosCroquiItemCoordenada)) {
                    $this->errors[] = "O campo '{$chaveCroquiItemCoordenadaTemplate}' não foi informado.";
                    continue;
                }

                $this->validarTipagem($dadosCroquiItemCoordenada, $chaveCroquiItemCoordenadaTemplate, $valorCroquiItemCoordenadaTemplate);
            }
        }
    }

    /**
     * Valida os dados das assinaturas dos peritos
     * 
     * @param $dadosTemplateAssinaturasPeritos
     * @param $dadosAssinaturasPeritos
     */
    private function validarAssinaturasPeritos(array $dadosTemplateAssinaturasPeritos, array $dadosAssinaturasPeritos): void
    {
        foreach ($dadosTemplateAssinaturasPeritos[0] as $chaveAssinaturaPeritoTemplate => $valorAssinaturaPeritoTemplate) {
            foreach ($dadosAssinaturasPeritos as $dadosAssinaturaPerito) {
                if (!array_key_exists($chaveAssinaturaPeritoTemplate, $dadosAssinaturaPerito)) {
                    $this->errors[] = "O campo '{$chaveAssinaturaPeritoTemplate}' não foi informado.";
                    continue;
                }

                $this->validarTipagem($dadosAssinaturaPerito, $chaveAssinaturaPeritoTemplate, $valorAssinaturaPeritoTemplate);
            }
        }
    }

    /**
     * Valida os dados das assinaturas dos agronomos
     * 
     * @param $dadosTemplateAssinaturasAgronomos
     * @param $dadosAssinaturasAgronomos
     */
    private function validarAssinaturasAgronomos(array $dadosTemplateAssinaturasAgronomos, array $dadosAssinaturasAgronomos): void
    {
        foreach ($dadosTemplateAssinaturasAgronomos[0] as $chaveAssinaturaAgronomoTemplate => $valorAssinaturaAgronomoTemplate) {
            foreach ($dadosAssinaturasAgronomos as $dadosAssinaturaAgronomo) {
                if (!array_key_exists($chaveAssinaturaAgronomoTemplate, $dadosAssinaturaAgronomo)) {
                    $this->errors[] = "O campo '{$chaveAssinaturaAgronomoTemplate}' não foi informado.";
                    continue;
                }

                $this->validarTipagem($dadosAssinaturaAgronomo, $chaveAssinaturaAgronomoTemplate, $valorAssinaturaAgronomoTemplate);
            }
        }
    }

    /**
     * Validar a tipagem dos dados que foram recebidos de acordo com o que foi definido no template
     * 
     * @param array $vistoria - Os dados que vieram na requisição
     * @param string $chaveTemplate - Qual chave está sendo validada
     * @param string $valorTemplate - O tipo que está definido no template
     */
    private function validarTipagem(array $vistoria, string $chaveTemplate, string $valorTemplate): void
    {
        $valorVistoria = $vistoria[$chaveTemplate];
        $tipoColunaVistoria = gettype($valorVistoria);

        //@todo verificar como posso validar o que pode ou não ser nulo
        if ($tipoColunaVistoria == 'NULL') {
            return;
        }
        
        switch ($valorTemplate) {
            case 'int':
                if ($tipoColunaVistoria != "integer") {
                    $this->errors[] = "O campo '{$chaveTemplate}' deve ser do tipo integer, {$tipoColunaVistoria} foi informado.";
                }
                break;
            case 'bool':
                if ($tipoColunaVistoria != "boolean") {
                    $this->errors[] = "O campo '{$chaveTemplate}' deve ser do tipo boolean, {$tipoColunaVistoria} foi informado.";
                }
                break;
            case 'string':
                if ($tipoColunaVistoria != "string") {
                    $this->errors[] = "O campo '{$chaveTemplate}' deve ser do tipo string, {$tipoColunaVistoria} foi informado.";
                }
                break;
            case 'datetime':
                $pattern = "/^([0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9]) (2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])GMT-(2[0-3]|[01][0-9]):([0-5][0-9])$/"; 
                if (!preg_match($pattern, $valorVistoria)) {
                    $this->errors[] = "O campo '{$chaveTemplate}' deve ser do tipo datetime.";
                }
                break;
            case 'date':
                $pattern = "/^([0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])$/";
                if (!preg_match($pattern, $valorVistoria)) {
                    $this->errors[] = "O campo '{$chaveTemplate}' deve ser do tipo date.";
                }
                break;
            case 'numeric':
                if ($tipoColunaVistoria != "double" && !is_numeric($valorVistoria)) {
                    $this->errors[] = "O campo '{$chaveTemplate}' deve ser do tipo numeric(double), {$tipoColunaVistoria} foi informado.";
                }
                break;
            default:
                $this->errors[] = "Tipagem do campo '{$chaveTemplate}' não mapeado.";
                break;
        }
    }

    public function validarSetLogVistoria($idVistoria, $idProposta, $itens): array
    {   
        $this->validarTipagem(['id_vistoria' => $idVistoria], 'id_vistoria', 'int');
        $this->validarTipagem(['id_proposta' => $idProposta], 'id_proposta', 'int');

        
        if (empty($itens)) {
            $this->errors[] = "Ao menos um item deve ser informado.";
        } else {
            foreach ($itens as $item) {

                if (empty($item['id_item_segurado'])) {
                    $this->errors[] = "ID do item segurado não informado.";
                }

                $this->validarTipagem($item, 'id_item_segurado', 'int');

                if (empty($item['dt_alteracao'])) {
                    $this->errors[] = "Data da alteração não informada.";
                }

                $this->validarTipagem($item, 'dt_alteracao', 'datetime');

                if (empty($item['campos'])) {
                    $this->errors[] = "Ao menos um campo de alteração deve ser informado.";
                }
            }
        }

        return $this->errors;
    }

    public function validarLimparVistorias($vistorias): array
    {
        if (empty($vistorias)) {
            throw new Exception("Nenhuma vistoria informada.");
        }

        foreach ($vistorias as $vistoria) {
            if (empty($vistoria['id_vistoria'])) {
                $this->errors[] = "ID da vistoria não informado.";
            }

            $this->validarTipagem($vistoria, 'id_vistoria', 'int');
        }

        return $this->errors;
    }

    public function validarAtualizarVistoria($vistoria): array
    {
        if (empty($vistoria)) {
            throw new Exception("Nenhuma vistoria informada.");
        }

        if (!array_key_exists('id_vistoria', $vistoria)) {
            $this->errors[] = "O campo 'id_vistoria' não foi informado.";
        } else {
            $this->validarTipagem($vistoria, 'id_vistoria', 'int');
        }

        if (!array_key_exists('id_status', $vistoria)) {
            $this->errors[] = "O campo 'id_status' não foi informado.";
        } else {

            $this->validarTipagem($vistoria, 'id_status', 'int');

            if (!in_array($vistoria['id_status'], [218, 219, 220, 221, 222, 223])) {
                $this->errors[] = "Valor do campo 'id_status' inválido.";
            }
        }

        return $this->errors;
    }
}
