<?php
/* Biblioteca de integração com a API da Getnet */

class Getnet extends RestApi
{
    const urlGetnetProduction = 'https://api.getnet.com.br';
    const urlGetnetSandbox = 'https://api-sandbox.getnet.com.br';

    private $accessToken = null;
    private $tokenExpire;
    private $header;
    private $environment;

    public function __construct($registry)
    {
        $this->registry = $registry;
        $this->load = $registry->get('load');
        $this->config = $registry->get('config');
        $this->session = $registry->get('session');
        $this->db = $registry->get('db');
        $this->log = $registry->get('log');
        $this->url = $registry->get('url');

        $this->curlOpts = array(
            CURLOPT_ENCODING => '',
        );

        $this->setHeader();
        if ($this->config->get('getnet_ambiente') == Type_Environment::Tp_Production) {
            $this->environment = self::urlGetnetProduction;
        } else {
            $this->environment = self::urlGetnetSandbox;
        }

        $this->accessToken = trim($this->config->get('getnet_access_token'));
        $this->tokenExpire = trim($this->config->get('getnet_token_expire'));
    }

    public function __get($name){
        return $this->registry->get($name);
    }

    public function getEnvironment(){
        return $this->environment;
    }

    public function setHeader(){
        $this->header = array(
            "Accept: application/json",
            "Content-Type: application/json",
        );
    }

    public function getHeader(){
        return $this->header;
    }

    public function getAccessToken($client_id = false, $client_secret = false){
        $url = $this->environment . '/auth/oauth/v2/token';

        $client_id = ($client_id) ? $client_id : $this->config->get('getnet_client_id');
        $client_secret = ($client_secret) ? $client_secret : $this->config->get('getnet_client_secret');
        $header =  array(
            'Content-Type: application/x-www-form-urlencoded',
            'Authorization: Basic '.base64_encode($client_id.':'.$client_secret)
        );

        $param = array(
            "scope" => "oob",
            "grant_type" => "client_credentials",
        );

        $param = http_build_query($param);

        $data = parent::callAPI($url, 'POST', $param, $header, false, $retorno);

        if (is_object($data) && property_exists($data, 'access_token')) {
            $dateExpire = new DateTime();
            $dateExpire->add(new DateInterval('PT' . $data->expires_in . 'S'));

            $this->setAccess($data->access_token, $dateExpire->format('Y-m-d H:i:s'));
        }

        return $data;
    }

    public function setAccess($accessToken,  $tokenExpire){
        $this->load->model('setting/setting');

        $data = array(
            'getnet_access_token' => $accessToken,
            'getnet_token_expire' => $tokenExpire,
        );

        $this->model_setting_setting->editSettingForKey('getnet', $data);

        $this->accessToken = $accessToken;
        $this->tokenExpire = $tokenExpire;
    }

    public function getAccess(){
        if ($this->config->get('getnet_status') == Type_Status::Tp_Habilitado) {
            $dateNow = new DateTime();
            $dateNow->add(new DateInterval('PT1M'));

            $dateExpire = DateTime::createFromFormat('Y-m-d H:i:s', $this->tokenExpire);

            // se nao tem access token ou está expirado pega um novo, senão já está setado no construct
            if ((!$this->accessToken) || ($dateNow > $dateExpire)) {
                $this->getAccessToken();
            }
        }
    }

    public function getCardToken($dataSend){
        try {
            $this->getAccess();
            $header = [
                'Content-Type: application/json',
                'Authorization: Bearer '.$this->accessToken,
                'seller_id: '.$this->config->get('getnet_seller_id'),
            ];

            $url = $this->environment . '/v1/tokens/card';

            $data = parent::callAPI($url, 'POST', $dataSend, $header, false, $retorno, Type_DadosSend::TpDados_Json);


            if($retorno == '201'){
                return $data->number_token;
            } else {
                $msgError = 'Erro ao tokenizar o cartão usando Getnet. Erro da API: ' . $data->message;
                $this->setErrorLog($msgError, $data);
                throw new exception($msgError);
            }

        } catch (Exception $e) {
            throw $e;
        }
    }

    public function sendPaymentBillet($dataSend, $order_id){
        try {
            $this->getAccess();
            $header = [
                'Content-Type: application/json',
                'Authorization: Bearer '.$this->accessToken
            ];

            $url = $this->environment . '/v1/payments/boleto';

            // Por algum motivo a API obriga a mandar essa chave como objeto
            $dataSend['boleto'] = (Object) $dataSend['boleto'];

            $data = parent::callAPI($url, 'POST', $dataSend, $header, false, $retorno, Type_DadosSend::TpDados_Json);

            if($retorno == '201'){
                return $data;
            } else {
                $msgError = 'Erro ao finalizar o pedido '.$order_id.' usando Getnet Boleto. Erro da API: ' . $data->message;
                $this->setErrorLog($msgError, $data);
                throw new exception($msgError);
            }

        } catch (Exception $e) {
            throw $e;
        }
    }

  public function sendPaymentDebitCard($dataSend, $order_id){
    try {
      $this->getAccess();
      $header = [
        'Content-Type: application/json; charset=utf-8',
        'Authorization: Bearer '.$this->accessToken,
      ];

      $url = $this->environment . '/v1/payments/debit';

      $data = parent::callAPI($url, 'POST', $dataSend, $header, false, $retorno, Type_DadosSend::TpDados_Json);

      if($retorno == '200' || $retorno == '201'){
//                $this->log->write('Pedido finalizado com sucesso, retorno da API: '.PHP_EOL.json_encode($data));
        return $data;
      } else {
        $messageGenerica = 'Erro ao finalizar o pedido ' . $order_id . ' usando Getnet Cartão de Débito';

        if (isset($data->details[0]->error_code)) {
          $messageGenerica .= $data->details[0]->description == 'Unauthorized' ? 'Transação não autorizada ' : ' ';
        }

        $msgError = ['message'=> $data->message,
          'HTTPCODE'=> $retorno.PHP_EOL,
          'REQUEST' => json_encode($dataSend).PHP_EOL,
          'RESPONSE' => json_encode($data)];

        $this->setErrorLogDb($msgError, Type_paymentLogError::TpGetnetDebitCard ,$data, $dataSend['customer']['customer_id']);
        throw new exception($messageGenerica);
      }

    } catch (Exception $e) {
      throw $e;
    }
  }

    public function sendPaymentCreditCard($dataSend, $order_id){
        try {
            $this->getAccess();
            $header = [
                'Content-Type: application/json',
                'Authorization: Bearer '.$this->accessToken,
            ];

            $url = $this->environment . '/v1/payments/credit';

            $data = parent::callAPI($url, 'POST', $dataSend, $header, false, $retorno, Type_DadosSend::TpDados_Json);

            if($retorno == '200'){
//                $this->log->write('Pedido finalizado com sucesso, retorno da API: '.PHP_EOL.json_encode($data));
                return $data;
            } else {
              $messageGenerica = 'Erro ao finalizar o pedido ' . $order_id . ' usando Getnet Cartão de Crédito';
              if (isset($data->details[0]->error_code)) {
                $messageGenerica .= $data->details[0]->description == 'Unauthorized' ? 'Transação não autorizada ' : ' ';
              }

              $msgError = ['message'=> $data->message,
                'HTTPCODE'=> $retorno.PHP_EOL,
                'REQUEST' => json_encode($dataSend).PHP_EOL,
                'RESPONSE' => json_encode($data)];

              $this->setErrorLogDb($msgError, Type_paymentLogError::TpGetnetCreditCard ,$data, $dataSend['customer']['customer_id']);
              throw new exception($messageGenerica);
            }

        } catch (Exception $e) {
            throw $e;
        }
    }

    public function sendPaymentPix($dataSend, $order_id){
      try{
        $this->getAccess();

        $header = [
          'Content-type: application/json',
          'Authorization: Bearer '.$this->accessToken,
          'seller_id: '.$dataSend['pix']['seller_id']
        ];

        $url = $this->environment . '/v1/payments/qrcode/pix';

        $json = array(
          "amount"      => $dataSend['pix']['amount'],
          "currency"    => $dataSend['pix']['currency'],
          "order_id"    => $dataSend['pix']['order']['order_id'],
          "customer_id" => $dataSend['pix']['customer']['customer_id'],
        );

        $data = parent::callAPI($url, 'POST', $json, $header, false, $retorno, Type_DadosSend::TpDados_Json);

        if($data){
          switch ($retorno) {
            case '500':
            case '200':
            case '201':
              return $data;
              break;
            case '401':
            case '403':
              $error = 'Erro ao carregar módulo Getnet:';
              is_array($data->message) ? $dataerror = $data->message[0] : $dataerror = $data->message;
              $error .= 'Código HTTP: ' . $retorno;
              $error .= 'Mensagem: ' . $dataerror;
              throw new exception($error);
              break;
            default :
              $error = 'Erro no módulo de pagamento';
              $error .= 'Mensagem: Erro na conexão com o Kangu';
              throw new exception($error);
          }
        } else {
          $msgError = 'Erro ao finalizar o pedido '.$order_id.' usando Getnet Boleto. Erro da API: ' . $data->message;
          $this->setErrorLog($msgError, $data);
          throw new exception($msgError);
        }

      }catch (Exception $e) {
        throw $e;
      }
    }

    protected function setErrorLogDb($msgError, $code ,$data, $customer){
        if ($this->config->get('getnet_log_error')){
            if (isset($data->details)){
                $this->log->write(print_r($data->details,true));
            }
        }
        $json = "'".json_encode($msgError). "'";
        $sql = "INSERT INTO oc_log_payment_error VALUES(NULL, NOW(), $code, $customer , $json)";
        $this->db->query($sql);
    }

  protected function setErrorLog($msgError, $data){
    if ($this->config->get('getnet_log_error')){
      if (isset($data->details)){
        $this->log->write($msgError.PHP_EOL.print_r($data->details,true));
      }
    }
  }

}
