<?php
$loader = $this->registry->get('load');
$loader->controller('payment/getnet_lib');

class ControllerPaymentGetnet extends ControllerPaymentGetnetLib
{

  public function __construct($registry)
  {
    parent::__construct($registry);
    parent::load();

    $this->paymentInfo = new PaymentInfo();
    $this->paymentInfo->clearParams();

    if (isset($this->session->data['payment_method']['code_type']) && isset($this->session->data['payment_method']['code'])) {
      $code_type = $this->session->data['payment_method']['code_type'];
      $code = $this->session->data['payment_method']['code']; // nome do controller

      $this->data['paymentRoute'] = "$code/pay_$code_type";
      $this->data['paymentName'] = $code;

      $this->load->dmodel('checkout/order');
      $getnet_fingerprint_id = $this->dmodel_checkout_order->getLastOrderId() + 1;
      $this->session->data['getnet_fingerprint_id'] = $getnet_fingerprint_id;

      $fingerPrintEnvironment = ($this->config->get('getnet_ambiente') == Type_Environment::Tp_Production ? Type_GetnetFingerPrint::Tp_Producao : Type_GetnetFingerPrint::Tp_Teste);
      $fingerPrintSession = preg_replace("/[^0-9]/", "", $this->config->get('config_cnpj')) . $this->session->data['getnet_fingerprint_id'];
      $this->data['fingerPrintScript'] = 'https://h.online-metrix.net/fp/tags.js?org_id=' . $fingerPrintEnvironment . '&session_id=' . $fingerPrintSession;
    }
  }

  public function credit_card()
  {
    $order_info = $this->dmodel_checkout_order->getOrder($this->session->data['order_id']);
    $this->load->helper('ftr_geral');
    $credit_card_config = $this->config->get('getnet_credit_card');
    if ($this->config->get('getnet_config_parcelamento') != Type_ConfigParcelamento::PorBandeira){
        foreach ($credit_card_config as &$value){
            $value['valor_minimo'] = '';
        }
    }
    $this->data['credit_cards'] = ftr_geral::getPaymentMethods($credit_card_config, $order_info['total']);

    $setting = [
      'display_cpf' => true,
      'Type_PaymentOption' => Type_PaymentOption::Tp_CreditCard,
      'payment_name' => 'getnet'
    ];

    $this->data['payment_address'] = $this->getChild('payment/getnet_payment_address', $setting);
    $this->data['captcha_tpl'] =  $this->getChild('payment/captcha');

    $fingerPrintEnvironment = ($this->config->get('getnet_ambiente') == Type_Environment::Tp_Production ? Type_GetnetFingerPrint::Tp_Producao : Type_GetnetFingerPrint::Tp_Teste);
    $fingerPrintSession     = preg_replace("/[^0-9]/", "", $this->config->get('config_cnpj')) . $this->session->data['order_id'];

    $this->data['fingerPrintEnvironment'] =  $fingerPrintEnvironment;
    $this->data['fingerPrintSession']     =  $fingerPrintSession;

    if (file_exists(DIR_TEMPLATE . $this->config->get('config_template') . '/template/payment/getnet/credit_card.twig')) {
      $this->template = $this->config->get('config_template') . '/template/payment/getnet/credit_card.twig';
    } else {
      $this->template = 'default/template/payment/getnet/credit_card.twig';
    }

    if ($this->ftrgeralregistry->isApp()) {
      $this->document->addScriptApp(array(
        'https://static.traycheckout.com.br/js/finger_print.js',
        'catalog/view/javascript/jquery.payment/jquery.payment.js',
        'catalog/view/theme/appmobile/js/payment.getnet_credit_card.js'
      ));
      $this->data['scriptsApp'] = json_encode($this->document->getScriptsApp());
    }

    $this->response->setOutput($this->render());

  }

  public function billet()
  {
    $setting = [
      'display_cpf' => true,
      'payment_name' => 'getnet',
      'load_customer_info' => true
    ];

    $this->data['payment_address'] = $this->getChild('payment/payment_address', $setting);
      $this->data['captcha_tpl'] =  $this->getChild('payment/captcha');

    if (file_exists(DIR_TEMPLATE . $this->config->get('config_template') . '/template/payment/getnet/billet.twig')) {
      $this->template = $this->config->get('config_template') . '/template/payment/getnet/billet.twig';
    } else {
      $this->template = 'default/template/payment/getnet/billet.twig';
    }

    if ($this->ftrgeralregistry->isApp()) {
      $this->document->addScriptApp(array(
        'catalog/view/theme/appmobile/js/payment.getnet_billet.js'
      ));
      $this->data['scriptsApp'] = json_encode($this->document->getScriptsApp());
    }

    $this->response->setOutput($this->render());

  }

  public function parcelamento($module='getnet',$html = true, $flag_params=array())
  {
    if ($this->config->get('getnet_config_parcelamento') == Type_ConfigParcelamento::PorBandeira){
      $json = array();
      $this->load->helper('ftr_geral');

      if (isset($this->request->get['bandeira'])) {
        $bandeira = Type_GetnetBandeira::getConstFromNickValue($this->request->get['bandeira']);
      } else if ($flag_params['bandeira'] != '') {
        $bandeira = Type_GetnetBandeira::getConstFromNickValue($flag_params['bandeira']);
      } else {
        $json['bandeira'] = 'Não foi possivel fazer o cálculo da parcela pois nenhuma bandeira foi encontrada!';
      }
      $credit_cards = $this->config->get('getnet_credit_card');

      $bandeira = current(array_filter($credit_cards, function($item) use ($bandeira) {
          return $item['key'] == $bandeira;
      }));

      $flag_params['juros'] = ftr_geral::isIsset($this->config->get('getnet_parcela_juros')) ? $this->config->get('getnet_parcela_juros') : 0;
      $flag_params['parcela_sem_juros']  = (isset($bandeira['parcela_juros']) && ($bandeira['parcela_juros'] != '')) ? $bandeira['parcela_juros'] : 0;
      $flag_params['parcela_maxima_qtd'] = (isset($bandeira['total_parcela']) && ($bandeira['total_parcela'] != '')) ? $bandeira['total_parcela'] : Type_GetnetConfigs::Tp_MaximoParcela;
      $flag_params['parcela_minima_val'] = $this->config->get('getnet_parcela_minima');
    }
    return parent::parcelamento($module,$html,$flag_params);
  }

  public function pay_credit_card()
  {

    $this->load->helper('Ftr_sql');
    $this->language->load('payment/getnet');

    $json['error'] = $this->validate();

    if (!$json['error']) {

      try {

        $this->saveRequiedCustomerInfos();

        //validação feita somente para cartão de credito
        if (isset($this->request->post['creditcard_cctype'])) {

          $payment_method_id = Type_GetnetBandeira::getConstFromNickValue($this->request->post['creditcard_cctype']);
          $getnet_credit_card = $this->config->get('getnet_credit_card');
          $qtd_parcela = $this->request->post['qtd_parcela'];

          if (isset($getnet_credit_card[$payment_method_id])) {

            if (($this->config->get('getnet_config_parcelamento') == Type_ConfigParcelamento::PorBandeira)&&($this->request->post['qtd_parcela'] > $getnet_credit_card[$payment_method_id]['total_parcela'])) {
              throw new exception('Quantidade de parcela não suportada para a bandeira' . $this->request->post['creditcard_cctype']);
            }

            $parcelas = $this->parcelamento(Type_CreditCardModule::getNickFromConstValue(Type_CreditCardModule::Getnet),false, array("bandeira" => $this->request->post['creditcard_cctype']));

            if (!in_array($this->request->post['qtd_parcela'], array_keys($parcelas))) {
              throw new exception('Quantidade de parcela não suportada para a bandeira' . $this->request->post['creditcard_cctype']);
            }

          } else {
            throw new exception('Bandeira ' . $this->request->post['creditcard_cctype'] . ' não habilitado para getnet.');
          }

        } else {
          throw new exception('Bandeira não encontrada.');
        }

        $order_info = parent::getOrder();

        //calcula novamente as parcelas para evitar que venha valor modificado do javascript
        $cartao_recalculo = $this->parcelamento(Type_CreditCardModule::getNickFromConstValue(Type_CreditCardModule::Getnet),false);
        $valor = $cartao_recalculo[$qtd_parcela]['valor_parcela'];
        $valorPedido = number_format($valor * $qtd_parcela, 2, '.', '');
        $this->paymentInfo->setParam('amount', $valorPedido);

        //calcula o juros das parcelas
        $juros_parcela = 0;
        $desconto_parcela = 0;
        if (isset($parcelas[$this->request->post['qtd_parcela']])) {
          $total_parcelas = $parcelas[$this->request->post['qtd_parcela']]['valor_parcela'] * $this->request->post['qtd_parcela'];
          if ($total_parcelas > $order_info['total']) {
            $juros_parcela = number_format($total_parcelas - $order_info['total'], 2, '.', '');
          }else if ($total_parcelas < $order_info['total']) {
            $desconto_parcela = $order_info['total']-$total_parcelas;
          }
        }

        $total_sobra = $order_info['total'] % $this->request->post['qtd_parcela'] / 100;

        if (parent::setOrderIncrease($this->order_info['order_id'])||$juros_parcela) {
          $juros_total = $juros_parcela+parent::getOrderIncreaseValue();
          $this->paymentInfo->setParam('price_additional', $juros_total);
        }

        if (parent::setOrderDiscount($this->order_info['order_id'])||$desconto_parcela) {
          $desconto_total = $desconto_parcela + parent::getOrderDiscountValue();
          $this->paymentInfo->setParam('price_discount', $desconto_total);
        }

        if(isset($this->request->post['cpf'])){
          $this->paymentInfo->setParam('cpf', $this->request->post['cpf']);
        }

        //seta a opção escolhida pelo usuario
        $this->paymentInfo->setParam('payment_method_id', $payment_method_id);
        //seta as opções de pagamentos disponiveis
        $this->paymentInfo->setParam('available_payment_methods', implode(',', Type_GetnetBandeira::getEnumListConst()));

        $paymentData = parent::getTransactionInfo();
        parent::setPaymentCreditCard();

        $cardData = array(
          'card_number' => $this->paymentInfo->getCreditCard()->getNumero(),
          'customer_id' => $order_info['customer_id'],
        );
        $cardToken = $this->getnet->getCardToken($cardData);

        $card = array(
          'number_token' => $cardToken,
          'cardholder_name' => $this->paymentInfo->getCreditCard()->getNome(),
          'security_code' => $this->paymentInfo->getCreditCard()->getCodigo(),
//          'brand' => $this->paymentInfo->getCreditCard()->getBandeira(), // Senão mandar eles pegam automaticamente
          'expiration_month' => $this->paymentInfo->getCreditCard()->getDataExp()->mes,
          'expiration_year' => substr($this->paymentInfo->getCreditCard()->getDataExp()->ano, 2),
        );

        if ($this->paymentInfo->getCreditCard()->getParcelas() == 1){
            $transactionType = Type_GetnetTipoTransacao::Tp_Avista;
        } else if (($juros_parcela == 0) || ($total_sobra >= $juros_parcela)){
            $transactionType = Type_GetnetTipoTransacao::Tp_ParceladoSemJuros;
        } else {
            $transactionType = Type_GetnetTipoTransacao::Tp_ParceladoComJuros;
        }

        $paymentData['credit_card']['credit'] = array(
          'delayed' => false,
          'pre_authorization' => false,
          'save_card_data' => false,
          'transaction_type' => $transactionType,
          'number_installments' => $this->paymentInfo->getCreditCard()->getParcelas(),
          'card' => $card,
        );

        $result = $this->getnet->sendPaymentCreditCard($paymentData['credit_card'], $order_info['order_id']);

        $this->load->model('payment/getnet');
        $this->model_payment_getnet->setStatusOrder($order_info['order_id'], $result->status);

        $sqlUpdParam = Ftr_sql::generateUpdate('oc_order', ['codigo_integracao_pagamento'], 'order_id = ' . $order_info['order_id']);
        $this->db->executeSql($sqlUpdParam, [$result->payment_id]);

        $data = new DateTime($result->received_at);
        $data->setTimezone(new DateTimeZone('America/Sao_Paulo'));
        $creditcard_ccno = str_replace(' ', '', $this->request->post['creditcard_ccno']);

        $paymentinfo = array();
        $paymentinfo['tid'] = $result->credit->transaction_id;
        $paymentinfo['payment_id'] = $result->payment_id;
        $paymentinfo['numero_autorizacao'] = $result->credit->authorization_code;
        $paymentinfo['cod_autorizacao'] = $result->credit->authorization_code;
        $paymentinfo['mensagem_retorno'] = $result->credit->reason_message;
        $paymentinfo['order_id'] = $order_info['order_id'];
        $paymentinfo['valor_pagamento'] = $result->amount/100;
        $paymentinfo['data_pagamento'] = $data->format("Y-m-d H:i:s");
        $paymentinfo['tipo_cartao'] = Type_Card::Tp_Credito;
        $paymentinfo['cartao_mascara'] = ftr_geral::MaskCard(strlen($creditcard_ccno), substr($creditcard_ccno, 0, 6), substr($creditcard_ccno, 12, strlen($creditcard_ccno)));
        $paymentinfo['cartao_bandeira'] = Type_GetnetBandeira::getConstFromNickValue(strtolower($this->request->post['creditcard_cctype']));
        $paymentinfo['cartao_bandeira_text'] = ucfirst($this->request->post['creditcard_cctype']);
        $paymentinfo['qtd_parcela'] = $qtd_parcela;
        $paymentinfo['valor_acrescimo'] = (isset($juros_parcela) && ($juros_parcela > 0)) ? $juros_parcela : null;
        $paymentinfo['moeda'] = $result->currency;
        $paymentinfo['nsu'] = $result->credit->terminal_nsu;

        $this->load->dmodel('payment/payment_info');
        $this->dmodel_payment_payment_info->addPaymentCreditCard($paymentinfo);

        if ($juros_parcela) {
              $valorPedido = $order_info['total'] + $juros_parcela;
              $this->dmodel_checkout_order->InsertOrderTotal($this->session->data['order_id'], array(
                  'module_code' => 'getnet_acrescimo',
                  'module_title' => 'Acréscimo Getnet (' . $parcelas[$this->request->post['qtd_parcela']]['percentual_calculo'] . '% de juros ao mês no parcelamento)',
                  'value' => $juros_parcela,
                  'order' => '2'
              ));
              $this->dmodel_checkout_order->updateTotalOrder($this->session->data['order_id'], $valorPedido);
              $this->dmodel_checkout_order->updateApportionment($this->session->data['order_id'],$juros_parcela,Type_Apportionment::Increase);
        }
        if ($desconto_parcela) {
          $valorPedido = $order_info['total']-$desconto_parcela;
          $this->dmodel_checkout_order->InsertOrderTotal($this->session->data['order_id'], array(
              'module_code' => 'getnet_desconto',
              'module_title' => 'Desconto Getnet (' . $parcelas[$this->request->post['qtd_parcela']]['percentual_calculo'] . '% de desconto)',
              'value' => $desconto_parcela*-1,
              'order' => '2'
          ));
          $this->dmodel_checkout_order->updateTotalOrder($this->session->data['order_id'], $valorPedido);
          $this->dmodel_checkout_order->updateApportionment($this->session->data['order_id'],$desconto_parcela,Type_Apportionment::Discount);
        }

      } catch (Exception $e) {
        $this->dmodel_checkout_order->update($this->session->data['order_id'], $this->config->get('getnet_order_status_canceled'), '');
      }

      $json['redirect'] = $this->url->link('checkout/success');

    }

    $this->response->setOutputJson($json);

  }

  public function pay_billet()
  {
    $this->load->helper('Ftr_sql');
    $this->load->controller('payment/payment_address');
    $controllerPaymentPaymentAddress = new ControllerPaymentPaymentAddress($this->registry);
    $json['error'] = $controllerPaymentPaymentAddress->validate();

    if (!$json['error']) {
      try {
        $order_info = parent::getOrder();

        //seta as opções de pagamentos disponiveis
        if(isset($this->request->post['cpf'])){
          $this->paymentInfo->setParam('cpf', $this->request->post['cpf']);
        }

        if (parent::setOrderIncrease($order_info['order_id'])) {
          $this->paymentInfo->setParam('price_additional', number_format(parent::getOrderIncreaseValue(), 2, '.', ''));
        }

        if (parent::setOrderDiscount($order_info['order_id'])) {
          $this->paymentInfo->setParam('price_discount', number_format(parent::getOrderDiscountValue(), 2, '.', ''));
        }

        $valor = $order_info['total'];
        $valorPedido = number_format($valor, 2, '.', '');
        $this->paymentInfo->setParam('amount', $valorPedido);

        $paymentData = parent::getTransactionInfo();

        $getnet_billet = $this->config->get('getnet_billet');

        $paymentData['billet']['boleto'] = [];
        if (isset($getnet_billet['validade']) && (!empty($getnet_billet['validade']))) {
            $date = new DateTime('+' . $getnet_billet['validade'] . ' day');
            $paymentData['billet']['boleto']['expiration_date'] = $date->format('d/m/Y');
        }

        $result = $this->getnet->sendPaymentBillet($paymentData['billet'], $order_info['order_id']);

        $json['boleto'] = $result->boleto;

        $this->load->model('payment/getnet');
        $this->model_payment_getnet->setStatusOrder($order_info['order_id'], $result->status);

        $sqlUpdParam = Ftr_sql::generateUpdate('oc_order', ['codigo_integracao_pagamento'], 'order_id = ' . $order_info['order_id']);
        $this->db->executeSql($sqlUpdParam, [$result->boleto->boleto_id]);

        $paymentInfo = array();
        $paymentInfo['data_criacao'] = $result->boleto->issue_date;
        $paymentInfo['data_vencimento'] = $result->boleto->expiration_date;
        $paymentInfo['link_boleto'] = $this->getnet->getEnvironment() . $result->boleto->_links[0]->href;
        $paymentInfo['link_digitavel'] = $result->boleto->typeful_line;
        $paymentInfo['order_id'] = $order_info['order_id'];

        $this->load->dmodel('payment/payment_info');
        $this->dmodel_payment_payment_info->addPaymentBillit($paymentInfo);

      } catch (Exception $e) {
        $this->dmodel_checkout_order->update($this->session->data['order_id'], $this->config->get('getnet_order_status_canceled'), '');
      }

      $json['redirect'] = $this->url->link('checkout/success');
    }

    $this->response->setOutputJson($json);

  }

  public function success()
  {

    if (isset($this->session->data['payment_session']['code']) && ($this->session->data['payment_session']['code'] == Type_getnetConfigs::Tp_NameModule)) {

      $this->load->dmodel('payment/payment_info');
      $this->load->language('payment/' . $this->session->data['payment_session']['code']);

      switch ($this->session->data['payment_session']['code_type']) {
        case Type_PaymentOption::Tp_CreditCard :
          $query = $this->db->query('SELECT pcc.tid, o.order_status_id  FROM oc_order o LEFT JOIN oc_payment_credit_card pcc ON (o.order_id = pcc.order_id) WHERE o.order_id = ' . $this->session->data['payment_session']['order_id'])->row;
          if (isset($query['tid'])) {
            $this->data['tid'] = $query['tid'];
          }
          break;
        case Type_PaymentOption::Tp_Billet:
          $query = $this->db->query('SELECT pb.link_boleto, pb.link_digitavel, o.order_status_id  FROM oc_order o LEFT JOIN oc_payment_billet pb ON (o.order_id = pb.order_id) WHERE o.order_id = ' . $this->session->data['payment_session']['order_id'])->row;
          if (isset($query['link_boleto'])) {
            $this->data['link_boleto'] = $query['link_boleto'];
          }
          if (isset($query['link_digitavel'])) {
            $this->data['link_digitavel'] = $query['link_digitavel'];
          }
          $this->data['link_order'] = $this->url->link('account/order/info', 'order_id=' . $this->session->data['payment_session']['order_id']);
          break;
        case Type_PaymentOption::Tp_BankTransfer:
          $query = $this->db->query('SELECT pbt.link_payment, o.order_status_id  FROM oc_order o LEFT JOIN oc_payment_bank_transfer pbt ON (o.order_id = pbt.order_id) WHERE o.order_id = ' . $this->session->data['payment_session']['order_id'])->row;
          if (isset($query['link_payment'])) {
            $this->data['link_payment'] = $query['link_payment'];
          }
          break;
      }

      $this->load->dmodel('checkout/order');
      $status_info = $this->dmodel_checkout_order->getOrderStatus($query['order_status_id']);
      $this->data['status_descricao'] = $status_info['descricao'];
      if ($status_info['order_status_id'] == $this->config->get('getnet_order_status_canceled')) {
        $this->session->data['orderPaymentCanceled'] = 'Pedido cancelado';
      }

      $this->template = $this->config->get('config_template') . '/template/success/' . $this->session->data['payment_session']['code_type'] . '.twig';
      $this->response->setOutput($this->render());

    } else {
      return false;
    }

  }

  public function validate()
  {

    $this->load->controller('payment/payment_address');

    $error = parent::validate();
    $error = $error ? $error :  array() ;

    if (!isset($this->request->post['qtd_parcela']) || $this->request->post['qtd_parcela'] < 1   ) {
      $error['qtd_parcela'] = $this->language->get('error_parcelas');
    }

    if ($error) {
      return $error;
    } else {
      return false;
    }

  }

  public function callback()
  {
      $paymentData = $this->request->get;

      if (isset($paymentData['payment_id']) || isset($paymentData['id'])) {

        $this->load->dmodel('payment/payment_info');

        if (isset($paymentData['payment_type']) && ($paymentData['payment_type'] == 'credit')) {
            $paymentId = $paymentData['payment_id'];
        } else {
            $paymentId = $paymentData['id'];
        }

        $data = array('codigo_integracao_pagamento' => $paymentId);

        $results = $this->dmodel_payment_payment_info->getOrderByToken($data);

        if ($results) {
          try {
            $this->load->model('payment/getnet');
            $this->model_payment_getnet->setStatusOrder($results['order_id'], $paymentData['status']);

            ob_start();
            header($_SERVER["SERVER_PROTOCOL"] . " 200 OK");
            ob_end_flush();
          } catch (Exception $e) {
            $this->log->write('Erro retorno callback getnet. Erro: ' . $e->getMessage() . '. Pedido ' . $results['order_id']);
          }
        }
      }

      if (headers_sent()) {
        echo "Header Sent to getnet";
      } else {
        echo "Header Not Sent to getnet";
      }

  }

}
