<?php

use PhpAmqpLib\Message\AMQPMessage;

require_once __DIR__ . '/RpcServerBase.php';

class Agro_RabbitMQ_RcpServer extends Agro_RabbitMQ_RpcServerBase
{
    const PATH_LOG = __DIR__ . "/../../../application/upload_files/log_rabbitmq/";
    const SLEEP = 60;

    private $retry = 3;
    public $wsdl;

    /**
     * @params $func string - A função que irá ser chamada pelo serviço
     * @params $env string - Ambiente em qual o script deve consultar as configs
     */
    public function __construct(string $func, string $env)
    {
        parent::__construct($func, $env);
        $this->setWsdl();
        $this->nomeFila = 'i4pro';


        if (!file_exists($this::PATH_LOG)) {
            mkdir($this::PATH_LOG, '0755', true);
        }
    }

    private function setWsdl(): void
    {
        $statment = $this->pdo->prepare(
            "select ds_valor from sistema.configuracao_sistema
            where ds_nome = :ds_nome"
        );

        $statment->execute(['ds_nome' => ($this->env == 'production' ? 'WSDL_PROD' : 'WSDL_DEV')]);

        $this->wsdl = $statment->fetchColumn(0);
    }

    private function importarReservas($payload)
    {
        $result = false;
        $i = 1;

        try {
            $client = new SoapClient($this->wsdl, array('location' => explode('?', $this->wsdl)[0]));

            $args = [
                'ExecutarRow' => [
                    'Servico' => 'InserirMovimentoSinistro',
                    'conteudoXML' => "{$payload['soap']}"
                ]
            ];

            while (!$result && $i < $this->retry) {
                $result = $client->__soapCall('ExecutarRow', $args);
                $xml = simplexml_load_string($result->ExecutarRowResult);
                $this->efetivarReservas($payload, $xml);
                $i++;
            }
        } catch (SoapFault $e) {
            $this->efetivarReservas($payload, $e);
        }
    }

    private function gravaLogTransmissao($data)
    {
        try {
            $this->pdo->beginTransaction();

            $statment = $this->pdo->prepare("
                insert into log.propostas_transmissao(
                    id_proposta,
                    ds_retorno,
                    fl_sucesso,
                    ds_tipo_transmissao,
                    ds_xml_transmissao
                ) values (?,?,?,?,?)
            ");

            $statment->execute([
                $data['id_proposta'],
                $data['ds_retorno'],
                $data['fl_sucesso'],
                $data['ds_tipo_transmissao'],
                $data['ds_xml_transmissao']
            ]);

            $this->pdo->commit();
        } catch (PDOException $e) {
            $this->pdo->rollback();
            die($e->getMessage());
        }
    }

    private function getAvisoReserva(int $idAviso, int $idCobertura)
    {
        $i = 0;
        $result = [];

        $statment = $this->pdo->prepare("
            select ats.*, av.id_proposta
            from sinistro.avisos_transmissao_seguradora ats
            join sinistro.avisos av
            on ats.id_aviso = av.id
            where ats.id_aviso = :id_aviso
            and ats.id_cobertura = :id_cobertura
        ");

        $statment->execute(['id_aviso' => $idAviso, 'id_cobertura' => $idCobertura]);

        return $statment->fetchObject();
    }

    private function gravaAvisoTransmissao($vlReserva, $idUsuario, $idAviso, $idCobertura)
    {
        try {
            $this->pdo->beginTransaction();

            $st = $this->pdo->prepare("
                update sinistro.avisos_transmissao_seguradora set
                    vl_reserva = :vl_reserva,
                    dt_alteracao = 'now()',
                    id_usuario_alteracao = :id_usuario_alteracao
                where id_aviso = :id_aviso and id_cobertura = :id_cobertura
            ");

            $st->bindValue(':vl_reserva', $vlReserva);
            $st->bindValue(':id_usuario_alteracao', $idUsuario);
            $st->bindValue(':id_aviso', $idAviso);
            $st->bindValue(':id_cobertura', $idCobertura);

            $st->execute();

            $this->pdo->commit();
        } catch (PDOException $e) {
            $this->pdo->rollBack();
            die($e->getMessage());
        }
    }

    private function efetivarReservas(array $payload, object $obj)
    {
        if (get_class($obj) == 'SoapFault') {
            $this->gravaLogTransmissao(
                [
                    'id_proposta' => $payload['line']['proposta'],
                    'ds_retorno' => "Aviso de Sinistro: " . $payload['line']['aviso'] . " - " . $obj->getMessage(),
                    'fl_sucesso' => 'f',
                    'ds_tipo_transmissao' => 'InserirMovimentoSinistro - Ajuste de Reserva',
                    'ds_xml_transmissao' => $payload['soap']
                ]
            );

            $this->logging([
                $payload['line']['proposta'],
                $payload['line']['apolice'],
                $payload['line']['aviso'],
                $payload['line']['cobertura'],
                $payload['line']['valor'],
                $payload['line']['tipo'],
                $obj->getMessage(),
                date('d/m/Y h:i:s')
            ]);

        } else {
            if ($obj->cd_retorno) {
                $this->gravaLogTransmissao(
                    [
                        'id_proposta' => $payload['line']['proposta'],
                        'ds_retorno' => $obj->cd_retorno,
                        'fl_sucesso' => 't',
                        'ds_tipo_transmissao' => 'InserirMovimentoSinistro - Ajuste de Reserva',
                        'ds_xml_transmissao' => $payload['soap']
                    ]
                );

                $rsAviso = $this->getAvisoReserva($payload['line']['aviso'], $payload['line']['cobertura']);

                if ($payload['line']['tipo'] == 'AJUSTE_MAIS') {
                    $vl_reserva = $rsAviso->vl_reserva + str_replace(',', '.', $payload['line']['valor']);
                } else {
                    $vl_reserva = $rsAviso->vl_reserva - str_replace(',', '.', $payload['line']['valor']);
                }

                //$payload['line']['id_usuario_alteracao'] = explode(',', $payload['line']['id_usuario_alteracao']);
                //$payload['line']['id_usuario_alteracao'] = end($payload['line']['id_usuario_alteracao']);

                $this->gravaAvisoTransmissao(
                    $vl_reserva,
                    $payload['line']['id_usuario_alteracao'],
                    $payload['line']['aviso'],
                    $payload['line']['cobertura']
                );

                $this->logging([
                    $payload['line']['proposta'],
                    $payload['line']['apolice'],
                    $payload['line']['aviso'],
                    $payload['line']['cobertura'],
                    $payload['line']['valor'],
                    $payload['line']['tipo'],
                    $obj->cd_retorno,
                    date('d/m/Y h:i:s'),
                ]);

            } else {
                $this->gravaLogTransmissao(
                    [
                        'id_proposta' => $payload['line']['proposta'],
                        'ds_retorno' => 'Ajuste de Reserva: ' . $payload['line']['aviso'] . ' - ' . $obj->erro->attributes()->nm_retorno,
                        'fl_sucesso' => 'f',
                        'ds_tipo_transmissao' => 'InserirMovimentoSinistro - Ajuste de Reserva',
                        'ds_xml_transmissao' => $payload['soap']
                    ]
                );

                $this->logging([
                    $payload['line']['proposta'],
                    $payload['line']['apolice'],
                    $payload['line']['aviso'],
                    $payload['line']['cobertura'],
                    $payload['line']['valor'],
                    $payload['line']['tipo'],
                    $obj->erro->attributes()->nm_retorno,
                    date('d/m/Y h:i:s')
                ]);
            }
        }
    }

    public function process(AMQPMessage $msg)
    {
        $payload = json_decode($msg->getBody(), true);

        /**
         * Condição criada para que haja uma pausa quando há muitos registros a serem enviados, pois o i4Pro estava
         * derrubando conexões por considerar um ataque
         */
        if (!empty($payload['line']['restando']) && $payload['line']['restando'] % 400 === 0) {
            sleep($this::SLEEP);
        }

        $this->{$this->func}($payload);

        if ($payload['line']['restando'] == 0) {
            //envia e-mail notificando
            if (isset($payload['line']['usuarios_sinistro_notificados']) && is_array($payload['line']['usuarios_sinistro_notificados'])) {
                foreach ($payload['line']['usuarios_sinistro_notificados'] as $idUsuario) {
                    $this->notificaFilaVazia($idUsuario, false);
                }
            }
            $this->notificaFilaVazia($payload['line']['id_usuario_alteracao']);
        }

        $msg->get('channel')->basic_ack(
            $msg->get('delivery_tag')
        );
    }

    private function logging(array $msg)
    {
        //$destination = $this::PATH_LOG. $this->func . date('Ymd') . ".csv";
        $destination = $this::PATH_LOG . $this->func . ".csv";
        $file = fopen($destination, "a");
        fputcsv($file, $msg, ';');
        fclose($file);
    }

    private function notificaFilaVazia(int $idUsuario, bool $renomearArquivo = true)
    {
        $logFile = $this::PATH_LOG . $this->func . ".csv";

        $st = $this->pdo->prepare(
            "select ds_email from sistema.funcionarios where id_usuario = :id_usuario"
        );
        $st->execute(['id_usuario' => $idUsuario]);
        $to = $st->fetchColumn(0);

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

        $transport = new Zend_Mail_Transport_Smtp($this->settings[$this->env]['constants.MAIL_SMTP'], $config);

        $mail = new Zend_Mail('UTF-8');
        $mail->setFrom($this->settings[$this->env]['constants.MAIL_USERNAME'], 'AgroBrasil - Agronet 2.0');

        $mail->addTo($to);

        $mail->setSubject("$this->func finalizado.");
        $mail->setBodyHtml("As tarefas de $this->func foram finalizadas.");

        $at = new Zend_Mime_Part(
            file_get_contents($logFile)
        );
        $at->type = 'text/csv';
        $at->disposition = Zend_Mime::DISPOSITION_INLINE;
        $at->encoding = Zend_Mime::ENCODING_BASE64;
        $at->filename = basename($logFile);

        $mail->addAttachment($at);

        try {
            if ($mail->send($transport)) {
                if ($renomearArquivo) {
                    rename($logFile, $this::PATH_LOG . "_" . $this->func . date('Ymdhis') . '.csv');
                    if (file_exists($logFile)) {
                        unlink($logFile);
                    }
                }
            }
        } catch (Zend_Mail_Protocol_Exception $err) {
            print_r($err->getMessage());
        } catch (Exception $e) {
            print_r($e->getMessage());
        }
    }
}
