<?php
require_once __DIR__ . '/../../../../vendor/autoload.php';
require_once 'Zend/Loader/Autoloader.php';
require_once __DIR__ .'/ReportsSinistro.php';
require_once __DIR__ .'/ReportsTecnica.php';

$loader = Zend_Loader_Autoloader::getInstance();

//Esse require precisa ficar depois do autoloader do Zend.
require_once __DIR__ . '../../../Db/Table/Adapter/Auth.php';
require_once __DIR__ . '/../../Db/Table/Abstract.php';
require_once __DIR__ . "/../../RabbitMQ/RcpClient.php";
require_once __DIR__ . '/../../../../application/modules/produto/models/ProdutosCoberturas.php';

use Firebase\JWT\BeforeValidException;
use Firebase\JWT\ExpiredException;
use \Firebase\JWT\JWT;
use Firebase\JWT\Key;
use Firebase\JWT\SignatureInvalidException;

class Agro_Reports {
    private const IT_USER = 1008;
    private $config = null;
    private $userId = null;
    private $mail = null;
    private $db = null;
    private $Auth = null;

    public function __construct() {
		$this->config = new Zend_Config_Ini('../application/config/application.ini', getenv('APPLICATION_ENV'));
	}
    
    protected function setDb() {
		$Adapter = Zend_Db::factory('PDO_PGSQL', $this->config->resources->db->params);
		Zend_Db_Table_Abstract::setDefaultAdapter($Adapter);
		$this->db = Zend_Db_Table::getDefaultAdapter();
	}

    protected function getDb() {
        return $this->db;
    }

    // verifica usuário e senha no banco
    private function checkIdentity($usuario, $senha) {
		$filter = new Zend_Filter_StripTags();
		$f_usuario = $filter->filter($usuario);
		$f_senha = $filter->filter($senha);

		$this->setDb();
		$this->Auth = Zend_Auth::getInstance();

        $AuthAdapter = new Agro_Db_Table_Adapter_Auth();
		$AuthAdapter->setTablename('sistema.v_login');
		$AuthAdapter->setIdentityColumn('ds_nome_usuario');
		$AuthAdapter->setCredentialColumn('ds_senha');
		$AuthAdapter->setIdentity($f_usuario);
		$AuthAdapter->setCredential($f_senha);

		if ($this->Auth->authenticate($AuthAdapter)->isValid()) {
			$data = $AuthAdapter->getResultRowObject(null, 'ds_senha');
			$this->Auth->getStorage()->write($data);
            $this->userId = $data->id;
            $this->mail = $data->ds_email;

			return true;
		} else {
			return false;
		}
	}

    // gera o jwt token
    private function generateJWT(string $user) {
        $dt = (new DateTime())->setTimestamp(time());
        $secret = base64_encode($this->config->constants->JWT_REPORTS_SECRET);
        $issuer = "http://reports.agrobrasilseguros.com.br";
        $audience = "reports_power_bi";
        $token = [
            "iss" => $issuer,
            "aud" => $audience,
            "iat" => $dt->getTimestamp(),
            "nbf" => $dt->getTimestamp(), //começa a valer instantaneamente
            "exp" => $dt->add(new DateInterval('P1Y'))->getTimestamp(), //expira em 1 ano
            "data" => [
                "user" => $user,
                "id" => $this->userId,
                "mail" => $this->mail
            ]
        ];

        return JWT::encode($token, $secret, 'HS512');
    }

    // valida o jwt token
    private function validateJWT() : stdClass {
        if (apache_request_headers()['Authorization'] == '') {
            http_response_code(401);
            throw new Exception('Autorization header não informado.');
        }

        try {
            return JWT::decode(
                explode(' ',apache_request_headers()['Authorization'])[1], 
                new Key(
                    base64_encode($this->config->constants->JWT_REPORTS_SECRET), 
                    'HS512'
                )
            );
        } catch (ExpiredException $e) {
            throw new Exception('Token expirado.');
            http_response_code(401);
        } catch (SignatureInvalidException $e) {
            throw new Exception('Assinatura inválida do token.');
            http_response_code(401);
        } catch (BeforeValidException $e) {
            throw new Exception('Token não vigente.');
            http_response_code(401);
        } catch (Exception $e) {
            throw new Exception('Token inválido.');
        }
    }

    private function doValidate() : bool {
        if (!is_object($payload = $this->validateJWT(apache_request_headers()))) {
            throw new Exception('Erro inesperado.');
            http_response_code(401);
        }

        if (!$payload->data->user) {
            throw new Exception('Erro inesperado.');
            http_response_code(401);
        }
        
        return true;
    }

    private function getIdSafra(string $safra) : int {
        $this->setDb();
        $safra = strtolower($safra);

        if ($safra == 'atual') {
            $sql = '';
        } elseif ($safra == 'anterior') {
            $sql = '-1';
        } else {
            throw new Exception('Safra inválida');
        }
        
        return $this->getDb()->fetchOne("
            select id$sql from produto.safras where fl_vigente = true    
        ");
    }

    public function ola() {
        return [ 'status' => true,  'data' => 'Estou aqui!' ];
    }

    //Efetua o login e retorna o token jwt caso sucesso
    public function doLogin(string $user, string $pass) {
        if (!$this->checkIdentity($user, $pass)) {
            http_response_code(401);
            return ['status' => false, 'data' => 'Usuário ou senha inválidos.'];
        }

        return ['status' => true, 'data' => $this->generateJWT($user)];
    }

    public function sinistralidadepg(string $safra) {
        try {
            if ($this->doValidate())
                return [
                    'status' => true, 
                    'data' => (new Agro_ReportsSinistro)->sinistralidadepg($this->getIdSafra($safra))
                ];
        } catch (Exception $e) {
            http_response_code(500);
            return [
                'status' => false,
                'data' => $e->getMessage()
            ]; 
        }
    }

    public function vendas(string $safra) {
        if ($this->doValidate())
            return ['status' => true, 'data' => (new Agro_ReportsTecnica)->vendas($this->getIdSafra($safra))];
    }

    public function vendasSinistroItemCobertura(string $descricaoSafra, $codigoCultura) {
        if ($this->doValidate()) {
            return [
                'status' => true,
                'data' => (new Agro_ReportsTecnica)->vendasSinistroItemCobertura($descricaoSafra, $codigoCultura)
            ];
        }
    }

    public function processos(string $safra) {
        if ($this->doValidate())
            return ['status' => true, 'data' => (new Agro_ReportsSinistro)->processos($this->getIdSafra($safra))];
    }

    public function sinistralidade(string $safra) {
        if ($this->doValidate())
            return ['status' => true, 'data' => (new Agro_ReportsSinistro)->sinistralidade($this->getIdSafra($safra))];
    }

    public function propostasCanceladas(string $safra) {
        if ($this->doValidate())
            return ['status' => true, 'data' => (new Agro_ReportsTecnica)->propostasCanceladas($this->getIdSafra($safra))];
    }

    public function liquidacoesItem(string $safra) {
        if ($this->doValidate())
            return ['status' => true, 'data' => (new Agro_ReportsSinistro)->liquidacoesItem($this->getIdSafra($safra))];
    }

    public function vistoriasPreliminares(string $safra) {
        if ($this->doValidate())
            return ['status' => true, 'data' => (new Agro_ReportsSinistro)->vistoriasPreliminares($this->getIdSafra($safra))];
    }

    public function ajusteReservas(string $safra) {
        if ($this->doValidate())
            return ['status' => true, 'data' => (new Agro_ReportsSinistro)->ajusteReservas($this->getIdSafra($safra))];
    }

    // Sinistro -> Rotinas -> Importar Ajustes de Reservas (aba Importação Ajuste de Reservas)
    public function importarReserva($json) {
        try {
            if ($this->doValidate()) {
                $i = 0;
                $rows = $json['body']['results'][0]['tables'][0]['rows'];
                
                if (count($rows)>0) {
                    foreach ($rows as $row) {
                        $data['proposta'] = $row['ID1392_Final[Proposta]'];
                        $data['apolice'] = $row['ID1392_Final[Apólice]'];
                        $data['aviso'] = $row['[MinAviso]'];
                        $data['cobertura'] = $row['ID1392_Final[Id Cobertura]'];
                        $data['valor'] = number_format($row['Exportar[Reserva]'],2, '.', '');
                        $data['tipo'] = $row['Exportar[Tipo]'];
                        $data['id_usuario_alteracao'] = self::IT_USER;
                        $data['restando'] = count($rows)-$i-1;

                        $soap = $this->montaXMLTransmissao(
                            $data['aviso'],
                            $data['cobertura'],
                            $data['valor'],
                            $data['tipo']
                        );

                        $clt = new Agro_RabbitMQ_RcpClient($_SERVER['APPLICATION_ENV']);
                        $clt->execute($soap, $data);
                        $i++;
                    }
                }
                return ['status' => true, 'message' => 'Reservas adicionadas na fila de importação com sucesso.'];
            }
        } catch (Exception $e) {
            http_response_code(500);
            return [
                'status' => false,
                'data' => $e->getMessage()
            ]; 
        }
    }
 
    private function montaXMLTransmissao($idAviso, $idCobertura, $valor, $tipo) {
        $reportSinistro = new Agro_ReportsSinistro();
        $rsAviso = $reportSinistro->getAvisoReserva($idAviso, $idCobertura)[0];
        $rsProposta = $reportSinistro->getProposta($rsAviso['id_proposta'])[0];

        $cpf_cnpj_sinistrada = str_replace('.', '', str_replace('/', '', str_replace('-', '', $rsProposta['cpf_cnpj'])));
        if ($rsProposta['tp_pessoa'] == 'F') {
            $tp_pessoa_sinistrada = 1;
        } else {
            $tp_pessoa_sinistrada = 2;
        }


        switch ($rsAviso['ds_nome_cobertura']) {

            case 'GRANIZO':
                $idCoberturaSeguradora = 240;
                break;
            case 'GEADA':
                $idCoberturaSeguradora = 239;
                break;
            case 'PRODUÇÃO MÍNIMA':
                $idCoberturaSeguradora = 245;
                break;
            case 'QUEDA DE PARREIRAL':
                $idCoberturaSeguradora = 252;
                break;
            case 'MULTIRISCO':
                $idCoberturaSeguradora = 244;
                break;
            default:
                $idCoberturaSeguradora = 240;
        }

        $tipoMovimento = '';

        switch ($tipo) {
            case 'AJUSTE_MAIS':
                $idTipoAjuste = 10102;
                break;
            case 'AJUSTE_MENOS':
                $idTipoAjuste = 10104;
                break;
                
            case 'CANCELAMENTO':
                $idTipoAjuste = 10105;
                $tipoMovimento = 17;
                break;
        }

        $xml = "
		<i4proerp>
			<insereMovimentoSinistroRural>
				<insereMovimento>
					<apolice>" . $rsProposta['nr_apolice'] . "</apolice>
					<dtMovimento></dtMovimento>
					<endosso>" . $rsProposta['ds_identificador_seguradora'] . "</endosso>
					<sinistro>" . $rsAviso['cd_identificador_seguradora'] . "</sinistro>
					<evento>" . $idTipoAjuste . "</evento>
					<cobertura>" . Produto_Model_ProdutosCoberturas::deParaI4Pro($rsAviso['id_proposta'], $idCoberturaSeguradora) . "</cobertura>
					<valorOperacao>" . $valor . "</valorOperacao>
					<observacao>Ajuste de Reserva</observacao>
					<tipoMovimento>{$tipoMovimento}</tipoMovimento>
					<nomeFavorecido>" . $rsProposta['ds_nome_proponente'] . "</nomeFavorecido>
					<tipoPessoaFavorecido>" . $tp_pessoa_sinistrada . "</tipoPessoaFavorecido>
					<nrCnpjCpfFavorecido>" . $cpf_cnpj_sinistrada . "</nrCnpjCpfFavorecido>
					<dtNascimentoFavorecido>1980-01-01</dtNascimentoFavorecido>
					<sexoFavorecido>1</sexoFavorecido>
					<nrDocumentoFavorecido>" . $cpf_cnpj_sinistrada . "</nrDocumentoFavorecido>
					<dtAgendamento></dtAgendamento> 
					<nrCi></nrCi> 
					<ajusta></ajusta> 
					<descontaPremioPendente></descontaPremioPendente> 
					<liberaConsistencias>1</liberaConsistencias>
					<tributaIndenizacao>0</tributaIndenizacao>
					<meioPagamento></meioPagamento>
					<nrBanco></nrBanco>
					<nrAgencia></nrAgencia>
					<nrDacAgencia></nrDacAgencia>
					<nrContaCorrente></nrContaCorrente>
					<nrDacContaCorrente></nrDacContaCorrente>
					<nrCheque></nrCheque>
					<nrEventoSequenciaEstorno></nrEventoSequenciaEstorno>
					<tipoDocumento></tipoDocumento>
					<serieDocumento></serieDocumento>
					<nrDocumento></nrDocumento>
					<dtNotaFiscal></dtNotaFiscal>
					<encerraSinistro>0</encerraSinistro>
				</insereMovimento>
			</insereMovimentoSinistroRural>
		</i4proerp>";

        return $xml;
    }
    
    // Sinistro -> Rotinas -> Importar Ajustes de Reservas (aba Atualizar Indenizações)
    public function atualizarIndenizacao($json) {
        try {
            if ($this->doValidate()) {
                $rows = $json['body']['results'][0]['tables'][0]['rows'];
                if (!(new Agro_ReportsSinistro)->updateAvisoTransmissaoSeguradora($rows)) {
                    return ['status' => false, 'message' => 'Erro ao atualizar indenizações.'];
                }
                return ['status' => true, 'message' => 'Indenizações atualizadas com sucesso!'];
            }
        } catch (Exception $e) {
            http_response_code(500);
            return [
                'status' => false,
                'data' => $e->getMessage()
            ];
        } 
    }

    // Sinistro -> Rotinas -> Importar Ajustes de Reservas (aba Atualizar Reservas)
    public function atualizarReserva($json)
    {
        try {
            if ($this->doValidate()) {
                $rows = $json['body']['results'][0]['tables'][0]['rows'];

                if (!(new Agro_ReportsSinistro())->updateValorReserva($rows)) {
                    return ['status' => false, 'message' => 'Erro ao atualizar os valores de reservas.'];
                }

                return ['status' => true, 'message' => 'Valores de reservas atualizados com sucesso!'];
            }
        } catch (Exception $e) {
            http_response_code(500);
            return [
                'status' => false,
                'data' => $e->getMessage()
            ];
        }
    }

    public function informacoesBancarias($dt_atualizacao = null) {
        try {
            $modelReportsTecnica = new Agro_ReportsTecnica();
            $modelReportsTecnica->setDb();
            $modelReportsTecnica->getDb()->beginTransaction();

            if ($this->doValidate()) {
                
                $rs = $modelReportsTecnica->informacoesBancarias($dt_atualizacao);
                $modelReportsTecnica->getDb()->commit();

                return [
                    'status' => true,
                    'data' => $rs
                ];
            }
        } catch (Exception $e) {
            $modelReportsTecnica->getDb()->rollback();

            http_response_code(500);
            return [
                'status' => false,
                'data' => $e->getMessage()
            ];
        }
    }

    public function parcelas(string $safra){
        if ($this->doValidate())
            return ['status' => true, 'data' => (new Agro_ReportsTecnica)->parcelas($this->getIdSafra($safra))];
    }
 
    public function itensCar(string $id_proposta_erp)
    {
        try {
            if ($this->doValidate()) {
                return (new Agro_ReportsTecnica())->getItensCarByIdPropostaERP($id_proposta_erp);
            }
        } catch (Exception $e) {
            return [
                'status' => false,
                'message' => $e->getMessage()
            ];
        }
    }
}