<?php
/* Biblioteca de integração com a SKD do paypal
https://developer.paypal.com/docs/checkout/reference/server-integration/
https://github.com/paypal/Checkout-PHP-SDK
*/

use PayPalCheckoutSdk\Core\PayPalHttpClient;
use PayPalCheckoutSdk\Core\SandboxEnvironment;
use PayPalCheckoutSdk\Core\AccessTokenRequest;
use PayPalCheckoutSdk\Core\ProductionEnvironment;

use PayPalCheckoutSdk\Orders\OrdersCreateRequest;
use PayPalCheckoutSdk\Orders\OrdersGetRequest;

use PayPalHttp\HttpException;

class paypal{
  private $url_return;
  private $url_cancel;
  private $registry;
  private $load;
  private $config;
  private $session;
  private $db;
  private $log;
  private $currency_code;

  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->currency_code = 'BRL';

  }

  public function setLogPaypal($textLog){
    $log = new Log('payment_error.txt');
    $logData = [
      'tag'      => '[' . get_class($this) . ']',
      'event'    => 'paypal_log',
      'message'  => 'Módulo Paypal log',
      'text'     => $textLog,
    ];
    $log->write(json_encode($logData, JSON_UNESCAPED_UNICODE));
  }


  public function getClient($environment = null){
    if ($environment) {
        return new PayPalHttpClient($environment);
    }
    return new PayPalHttpClient($this->getEnvironment());
}

  public function getEnvironment(){
    $clientId = $this->config->get('paypal_client_id');
    $clientSecret = $this->config->get('paypal_client_secret');

    if($this->config->get('paypal_test')){
      return new SandboxEnvironment($clientId, $clientSecret);
    }else{
      return new ProductionEnvironment($clientId, $clientSecret);
    }
  }

  public function buildRequestBody($dataOrder){
    /*https://developer.paypal.com/docs/api/orders/v2/#definition-order*/

    //Inicio Totais Ps. O value do amount tem que bater com o calculo total do breakdown
    $totais = array();
    $desconto = 0;
    $acrescimo = 0;
    $taxa = 0;
    foreach ($dataOrder['totals'] as $total){
      switch ($total['code']){
        case 'sub_total' : $totais['item_total'] = array('currency_code' => $this->currency_code, 'value' => number_format((float)$total['value'], 2 ,'.',''));
        break;
        case 'shipping' : $totais['shipping'] = array('currency_code' => $this->currency_code, 'value' => number_format((float)$total['value'], 2 ,'.',''));
        break;

        case 'total_fcpst' : $taxa += $total['value'];
        break;
        case 'total_ipi' : $taxa += $total['value'];
        break;
        case 'total_st' : $taxa += $total['value'];
        break;

        case 'total' : break; //Para não somar nos acréscimos

        default : if($total['value']<0){
          $desconto += $total['value'];
        }else{
          $acrescimo += $total['value'];
        }
        break;
      }
    }

	  $desconto = $desconto*-1;
    if ($desconto>0){
      $totais['discount'] = array('currency_code' => $this->currency_code, 'value' => number_format((float)$desconto, 2 ,'.',''));
    }
    if($taxa>0){
      $totais['tax_total '] = array('currency_code' => $this->currency_code, 'value' => number_format((float)$taxa, 2 ,'.',''));
    }
    if ($acrescimo>0){
      foreach ($dataOrder['products'] as $item){
        $total_quantity += $item['quantity'];
      }
      $acrescimo = $acrescimo/$total_quantity;
    }
    //Fim Totais

    //Inicio Itens
    $itens = array();
    foreach ($dataOrder['products'] as $item){
      $item_tax = 0;

      $item_tax =  ($item['ipi_valor'] != null) ? $item['ipi_valor'] : 0;
      $item_tax +=  ($item['st_valor'] != null) ? $item['st_valor'] : 0;
      $item_tax +=  ($item['fcpst_valor'] != null) ? $item['fcpst_valor'] : 0;

      $item_tax = $item_tax/$item['quantity'];

      $itens[] = array(
        'name' => $item['name'],
        'sku' => $item['product_id'],
        'unit_amount' =>
          array(
            'currency_code' => $this->currency_code,
            'value' => number_format((float)$item['price']+$acrescimo, 2 ,'.',''),
          ),
        'tax' =>
          array(
            'currency_code' => $this->currency_code,
            'value' => number_format((float)$item_tax, 2 ,'.',''),
          ),
        'quantity' => $item['quantity']
      );
    }
    //Fim Itens

    return array(
      'intent' => 'CAPTURE', /* Se ira autorizar para captura posterior AUTHORIZE(3dias) ou capturar imediatamente CAPTURE */
      'application_context' =>
        array(
          'brand_name' => $this->config->get('paypal_titulo_empresa'),/* label exibido na página do paypal Max: 127char */
          'locale' => 'pt-BR',
          'landing_page' => 'NO_PREFERENCE',//NO_PREFERENCE para ficar no padrão do ultimo acesso do cliente ao paypal (login ou direto para o pagamento)
          'shipping_preference' => 'SET_PROVIDED_ADDRESS',//SET_PROVIDED_ADDRESS para não permitir trocar o endereço no paypal
          'user_action' => 'PAY_NOW',//PAY_NOW para não permitir alteração no valor
        ),
        'purchase_units' =>
            array(
              0 =>
                array(
                  //'reference_id' => 'PUHF',
                  'description' => $this->config->get('paypal_descricao_compra'), //Descrição da compra
                  //'custom_id' => 'CUST-HighFashions',
                  'soft_descriptor' => $this->config->get('paypal_descricao_fatura'), //Descrição que mostra na fatura do cartão, maximo de 22 caracteres contando "paypal"
                  'amount' => array(
                    'currency_code' => $this->currency_code,
                    'value' =>  number_format((float)$dataOrder['total'], 2 ,'.',''),
                    'breakdown' => $totais
                  ),
                  'item' => $itens,
                  'shipping' =>
                    array(
                      'method' => $dataOrder['shipping_method'],
                      'name' =>
                        array(
                          'full_name' => $dataOrder['shipping_firstname'].' '.$dataOrder['shipping_lastname'],
                        ),
                      'address' =>
                        array(
                          'address_line_1' => $dataOrder['shipping_address_1'].','.$dataOrder['shipping_numero'],
                          'address_line_2' => $dataOrder['shipping_complemento'],
                          'admin_area_2' => $dataOrder['shipping_city'],
                          'admin_area_1' => $dataOrder['shipping_zone_code'],
                          'postal_code' => $dataOrder['shipping_city'],
                          'country_code' => 'BR',
                        ),
                    ),
                ),
            ),
      );
  }

  public function createOrder($data=array()) {
    /*https://developer.paypal.com/docs/checkout/reference/server-integration/set-up-transaction/*/
    try{
      $request = new OrdersCreateRequest();
      $request->prefer('return=representation');
      $request->body = $this->buildRequestBody($data);

      $client = $this->getClient();
      $response = $client->execute($request);
      if ($this->config->get('paypal_debug')){

        $this->setLogPaypal("Status Code: {$response->statusCode}\n
        Status: {$response->result->status}\n
        Order ID: {$response->result->id}\n
        Intent: {$response->result->intent}\n
        Links:\n");
        foreach($response->result->links as $link){
          $this->setLogPaypal("\t{$link->rel}: {$link->href}\tCall Type: {$link->method}\n");
        }

      }
      return $response;

    } catch (HttpException  $e) {
      $logData = [
        'tag'      => '[' . get_class($this) . ']',
        'event'    => 'paypal_error',
        'message'  => 'Módulo Paypal erro: Erro ao criar o pedido',
        'exception'=> [
            'type'    => get_class($e),
            'message' => $e->getMessage(),
            'code'    => $e->getCode(),
            'file'    => $e->getFile(),
            'line'    => $e->getLine(),
        ],
      ];
      $this->log->write(json_encode($logData, JSON_UNESCAPED_UNICODE));
    }


  }

  public function validateAccesToken($paypal_client_id, $paypal_client_secret){
    try{
        if($this->config->get('paypal_test')){
            $environment = new SandboxEnvironment($paypal_client_id, $paypal_client_secret);
        }else{
            $environment = new ProductionEnvironment($paypal_client_id, $paypal_client_secret);
        }

        $client = $this->getClient($environment);

        $accessTokenResponse = $client->execute(new AccessTokenRequest($environment));

        $result = array('type' => 'success', 'status_code' => $accessTokenResponse->statusCode, 'result' => $accessTokenResponse->result);
    } catch (HttpException  $e) {
        $result = array('type' => 'error', 'status_code' => $e->statusCode, 'message' => $e->getMessage());
    }

    return $result;
  }

}
