<?php
class Agro_LaudoXml {
    private array $data = [];
    private string $ds_nome_laudo_fisico = '';
    private int $id_item_segurado;
    private string $last_nome_laudo_fisico = '';

    function __construct(array $data) {
        $this->data = $data;
    }

    public function importarLaudo(?string &$error='') : bool {
        $strNomeLaudo = ucfirst(strtolower($this->data['params']['ds_laudo']));
        $modelLaudoFinal = new Sinistro2_Model_LaudosFinais();

        if (!$this->checkLaudoVersion($this->data['Versao'])) {
            $error = 'ATENÇÃO: A versão do laudo não está de acordo com a versão atual. Por favor verifique.';
            return false;
        }

        if ($this->data['N_Proposta'] !== $this->data['params']['id_proposta']) {
            $error = 'ATENÇÃO: A proposta selecionada não é a mesma do arquivo XML importado. Por favor verifique.';
            return false;
        }

        if (str_replace('_',',',trim($this->data['N_Aviso'])) !== trim($this->data['params']['id_aviso'])) {
            $error = 'ATENÇÃO: O(s) aviso(s) do arquivo XML não conferem com o(s) aviso(s) da vistoria. Por favor verifique.';
            return false;
        }

        Agro_Db_Table_Abstract::getDefaultAdapter()->beginTransaction();
        $items = $this->buildMoreThanOneItem($this->data);

        foreach ($items as $item) {
            $this->data['Item'] = $item;
            $toSave = $this->fromTo($this->data);

            if (count($toSave) > 0) {
                if ($this->isItemAlreadyImported($this->id_item_segurado)) {
                    $idLaudoFinal = $modelLaudoFinal->save($toSave);
                    if ($idLaudoFinal) {
                        $strClass = 'Regulacao_Model_'.$strNomeLaudo.'ItensSegurados';
                        $toSave['id_laudo_final'] = $idLaudoFinal;
                        $classItensSegurados = new $strClass;

                        $idLaudoFinalItemSegurado = $classItensSegurados->save($toSave);
                        $toSave['id_laudo_final_item_segurado'] = $idLaudoFinalItemSegurado;
                        
                        if ($idLaudoFinalItemSegurado) {
                            $strClass = 'Regulacao_Model_'.$strNomeLaudo.'ItensSeguradosAmostras';
                            $classItensSeguradosAmostras = new $strClass;
                            
                            if ($classItensSeguradosAmostras->save($toSave)) {
                                if ($this->saveLaudoFisico($this->getNomeLaudoFisico())) {
                                    if (($wasSaved = $this->save()) === true) {
                                        $this->setLastNomeLaudoFisico($this->getNomeLaudoFisico());
                                        Agro_Db_Table_Abstract::getDefaultAdapter()->commit();
                                    } else {
                                        $error = $wasSaved;
                                    }
                                } else {
                                    $error = 'Erro ao salvar laudo final físico.';
                                }
                            } else {
                                $error = 'Erro ao salvar amostras dos items do laudo final.';
                            }
                        } else {
                            $error = 'Erro ao salvar itens do laudo final.';
                        }
                    } else {
                        $error = 'Erro ao salvar laudo final.';
                    }
                } else {
                    $error = 'Item '. $this->id_item_segurado. ' já foi importado ou digitado. Por favor verifique.';
                }
            } else {
                $error = 'Item '. $this->data['Item'] .' não pertence a proposta. Por favor verifique.';
            }
        }

        $this->setLastNomeLaudoFisico('');

        if ($error == '') {
            return true;
        } else {
            Agro_Db_Table_Abstract::getDefaultAdapter()->rollBack();
        }
        return false;
    }

    private function buildMoreThanOneItem(array $data) : array {
        $foundItems = [];
        preg_match_all('/(\d+)/', $data['Item'], $items, PREG_SET_ORDER);
        if (count($items)>0) {
            foreach ($items as $item) {
                array_push($foundItems, $item[0]);
            }
        }
        return $foundItems;
    }

    // traduz dados recebidos do XML para array de insert da classe 
    private function fromTo(array $data) : array {

        $idPropostaVigente = (new Seguro_Model_Propostas())
            ->getPropostasVigentes([$data['params']['id_proposta']])[0]['id_proposta'];

        $itemSegurado = (new Seguro_Model_ItensSegurados()
            )->getItemByPropostaNroItemSegurado(
                $idPropostaVigente,
                $data['Item']
            );

        if (count($itemSegurado)<=0) {
            return [];
        }

        $this->id_item_segurado = $itemSegurado['id'];
        $this->setNomeLaudoFisico($itemSegurado['nr_item_segurado']);

        $return = [
            'id_laudo_final' => $data['params']['id_laudo_final'],
            'id_vistoria' => $data['params']['id_vistoria'],
            'id_cobertura' => $data['params']['id_cobertura'],
            'fl_vistoria_preliminar' => (
                new Sinistro2_Model_Processos()
            )
            ->getRow($data['params']['id_processo'])
            ->fl_vistoria_preliminar($data['params']['id_cobertura']) === false ? 0 : 1,
            'id_item_segurado' => $itemSegurado['id'],
            'id_proposta' => $idPropostaVigente,
            'id_processo' => $data['params']['id_processo'],
            'id_laudo_final_item_segurado' => (
                new Sinistro2_Model_LaudosFinaisItensSegurados()
            )->getRow($data['params']['id_laudo_final'], $itemSegurado['id'])['id'],//verificar
            'fl_dt_evento_em_cobertura' => strtoupper($data['Dentro_Cobertura']) == 'SIM' ? 1 : 0,
            'fl_area_declarada_representa_area_cultivada' => strtoupper($data['Toda_Area']) == 'SIM' ? 1 : 0,
            'fl_nao_vistoriada' => '', //buscar checagem
            'id_motivo_quadra_nao_vistoriada' => '', //buscar checagem
            'fl_avalia_danos_anteriores' => '',
            'vl_area' => $data['Area'],
            'vl_percent_colhido' => number_format(($data['Perc_Colhido'] * 100),2,'.',''),
            'ds_coordenadas_geograficas' => '-'.$data['Coordenada_S'].' , -'.$data['Coordenada_W'],
            'ds_coordenadas' => '-'.$data['Coordenada_S'].' , -'.$data['Coordenada_W'],
            'fl_amostragem_maquina' => ($data['Producao_Colhida_Mec']?1:0),
            'vl_largura_plataforma' => $data['Largura'],
            'vl_perda_colheita' => number_format(($data['Perdas_Colheita_Mec'] * 100),2,'.', ''),
            'vl_distancia_percorrida' => $data['Distancia'],
            'vl_producao_colhida_amostra' => $data['Producao_Colhida_Mec'],
            'vl_umidade_graos' => number_format(($data['Umidade_Mec'] * 100),2,'.',''),
            'vl_impurezas' => number_format(($data['Impureza'] * 100),2,'.', ''),
            'vl_graos_podres' => is_array($data['Podres'])?'':number_format(($data['Podres'] * 100),2,'.',''),
            'vl_graos_brotados' => is_array($data['Brotados'])?'':number_format(($data['Brotados'] * 100),2,'.',''),
            'vl_pragas_doencas_outros' => is_array($data['Pragas_Doencas'])?'':number_format(($data['Pragas_Doencas'] * 100),2,'.',''),
            'ds_observacao' => $data['Observacoes'],
            'fl_assinatura_segurado' => strtoupper($data['params']['is_signed']) == 'SIM' ? 1 : 0,
            'ds_observacao_assinatura_segurado' => '', //verificar
            'fl_assinatura_regulador' => 1, //questionar pois não tem previsto essa informacao na importacao
            'dt_vistoria_data' => $data['Data_Vist'],
            'dt_vistoria_hora' => (new DateTime(str_ireplace('h','',$data['Hora'])))->format('H:i'),
            'vistoriadores' => $data['params']['ds_nome_perito'], //verificar
            'ds_nome_perito' => $data['Perito'],
            'ds_nome_laudo_fisico' => $this->getNomeLaudoFisico(),
            'files_already_validated' => true
        ];

        for($i=1; $i<=10; $i++) {
            $return['vl_espacamento_entre_linhas_'.$i] = $data['A'.$i.'_Entre_Linhas'][0];
            $return['vl_metros_linhas_colhidos_'.$i] = $data['A'.$i.'_Metros_Colhidos'][0];
            $return['vl_producao_colhida_amostra_'.$i] = $data['A'.$i.'_Producao_Colhida'][0];
            $return['vl_umidade_graos_'.$i] = $data['A'.$i.'_Umidade'][0];
        }

        return $return;
    }

    private function saveLaudoFisico(string $fileName) : bool {
        if (file_exists($this->data['laudo_fisico']['tmp_name'])) {
            if(move_uploaded_file($this->data['laudo_fisico']['tmp_name'], PATH_LAUDOS . '/' . $fileName)) {
                return true;
            } elseif(rename($this->data['laudo_fisico']['tmp_name'], PATH_LAUDOS . '/' . $fileName)) {
                return true;
            }
        } elseif ($this->getLastNomeLaudoFisico() !== '') {
            if (symlink(PATH_LAUDOS . '/' . $this->getLastNomeLaudoFisico(), PATH_LAUDOS . '/' . $fileName)) {
                return true;
            } else {
                return false;
            }
        } else {
            return false;
        }
    }

    private function setNomeLaudoFisico(int $nroItem) : void {
        try {
            $sufixo = ((new Sistema_Model_Vistorias())->isNovaAvaliacao($this->data['params']['id_vistoria']) ? '_NA_' : '_VF_');
            $count = count((new Sinistro2_Model_LaudosFinaisItensSegurados())->contaLaudosByProcesso($this->data['params']['id_processo'])) + 1;

            $this->ds_nome_laudo_fisico = strtoupper(
                str_pad($this->data['params']['id_proposta'], 6, "0", STR_PAD_LEFT).
                $sufixo.
                str_pad($count, 3, "0", STR_PAD_LEFT)."_".
                $nroItem.".pdf"
            );
        } catch (Exception $e) {
            die($e->getMessage());
        }
            
    }

    private function getNomeLaudoFisico() : string {
        return $this->ds_nome_laudo_fisico;
    }

    private function saveFileXml() : bool {
        if (file_exists($this->data['file_xml']['tmp_name'])) { 
            if (!is_dir(PATH_XML)) mkdir(PATH_XML);
            if(move_uploaded_file($this->data['file_xml']['tmp_name'], PATH_XML. '/'. $this->data['file_xml']['name'])) {
                return true;
            } elseif(rename($this->data['file_xml']['tmp_name'], PATH_XML. '/'. $this->data['file_xml']['name'])) {
                return true;
            }
        } elseif (file_exists(PATH_XML. '/'. $this->data['file_xml']['name'])) {
            return true;
        } else {
            return false;
        }
    }

    private function save() {
        try {
            $data = [
                'id_laudo_final' => $this->data['params']['id_laudo_final'],
                'id_vistoria' => $this->data['params']['id_vistoria'],
                'ds_nome_arquivo_xml' => $this->data['file_xml']['name'],
                'id_proposta' => $this->data['params']['id_proposta'],
                'ds_nome_laudo' => $this->getNomeLaudoFisico(),
                'id_item_segurado' => $this->id_item_segurado,
                'id_status' => (
                    strtoupper($this->data['params']['is_signed']) == 'SIM' ?
                    (new Sistema_Model_Status)->getIdByChaveTipoChave('ENVIADO', 'LAUDO_XML') :
                    (new Sistema_Model_Status)->getIdByChaveTipoChave('ENVIADO_NAO_ASSINADO', 'LAUDO_XML')
                ),
                'id_motivo_nao_vistoriado' => '',
                'id_aviso' => $this->data['params']['id_aviso']
            ];

            if ($this->saveFileXml()) {
                if (is_int($data['id_laudo_xml_importacao'] = (new Sinistro2_Model_LaudoXMLImportacao)->save($data)) && $data['id_item_segurado']) {
                    if ((new Sinistro2_Model_LaudoXMLImportacaoItem)->save($data)) {
                        if ((new Sinistro2_Model_LaudoXMLImportacaoAviso)->save($data)) {
                            $data['fl_sucesso'] = true;
                            $data['ds_mensagem'] = 'Item importado com sucesso.';
                            if ((new Sinistro2_Model_LaudoXMLImportacaoItemHistorico)->save($data)) {
                                return true;
                            } else {
                                throw new Exception('Erro ao guardar histórico da importação do arquivo XML.');
                            }
                        } else {
                            throw new Exception('Erro ao importar dados do aviso do arquivo XML.');
                        }
                    } else {
                        throw new Exception('Erro ao importar dados dos itens do arquivo XML.');
                    }
                } else {
                    throw new Exception($data['id_laudo_xml_importacao']);
                }
            } else {
                throw new Exception('Erro ao salvar arquivo XML.');
            }
        } catch (Exception $e) {
            return $e->getMessage();
        }
        return false;
    }

    private function setLastNomeLaudoFisico(string $nome) : void {
        $this->last_nome_laudo_fisico = $nome;
    }

    private function getLastNomeLaudoFisico() : string {
        return $this->last_nome_laudo_fisico;
    }

    private function checkLaudoVersion(string $versao) : bool {
        $tipoLaudoFinal = (new Sinistro_Model_TipoLaudoFinal)->fetchRow("ds_versao = '$versao'");
        $tipoLaudoPreliminar = (new Sinistro_Model_TipoLaudoPreliminar)->fetchRow("ds_versao = '$versao'");

        if ($tipoLaudoFinal->id || $tipoLaudoPreliminar->id) {
            return true;
        }

        return false;
    }

    private function isItemAlreadyImported(int $idItem) : bool {                   
        if ((empty((new Sinistro2_Model_LaudoXMLImportacaoItem())
            ->fetchRow('id_item_segurado = ' . $idItem)
            ->id)) && (empty((new Sinistro2_Model_LaudosFinaisItensSegurados())
            ->fetchRow('id_item_segurado = ' . $idItem)
            ->id))) {
                return true;
        }

        return true;
    }
}