<?php
//Hugo: 22/10/2015- comunica��o com webservice gera parcela pagseguro
/*include_once 'catalog/controller/payment/PagSeguroLibrary/PagSeguroLibrary.php';*/

class pagseguro extends RestApi
{
    private $config;
    private $session;
    private $db;
    private $registry;
    private $log;
    private $load;
    private $key = "9247yf9othh0534985794gsgfr-38ecpijh24368u0r55";
    private $method = "aes-256-cbc";

    public function __construct($registry)
    {
        $this->config = $registry->get('config');

        if (!$this->config->get('pagseguro_status')){
            return false;
        }

        $this->db = $registry->get('db');
        $this->session = $registry->get('session');
        $this->registry = $registry;
        $this->log = $this->config->get('pagseguro_log');
        $this->load = $registry->get('load');
    }

    /**
    * Get the API environment based on configuration.
    *
    * @return string The API environment URL.
    */
    public function getEnvironment(){
        if($this->config->get('pagseguro_environment_status') == 'sandbox'){
            return "https://sandbox.api.pagseguro.com";
        }else{
            return "https://api.pagseguro.com";
        }
    }


    /**
    * Create the header for API requests.
    *
    * @return array An array containing the header information.
    */
    public function setHeader() {
        return [
            'Authorization: Bearer ' . $this->decryptData($this->config->get('pagseguro_token')),
            'Content-Type: application/json',
            'Accept: application/json'
        ];
    }


    /**
    * Create a checkout in PagSeguro based on the provided transaction data.
    *
    * @param array $dadosTransacao The transaction data.
    * @return object The response from the PagSeguro API or an error message.
    */
    public function createCheckout($dadosTransacao) {
        $environment = $this->getEnvironment();

        $this->load->type('tipopagseguro');
        $this->load->type('tipocomum');

        $headers = $this->setHeader();
        
        $dataSend = $this->mountCheckoutPayload($dadosTransacao);
        
        $data = parent::callAPI($environment.'/checkouts/', 'POST', $dataSend, $headers, false, $retorno, Type_DadosSend::TpDados_Identificar);
        $data = is_string($data) ? json_decode($data, true) : $data;
        if ($this->log) {
            $this->setLog(['url' => 'create_checkout', 'data' => $dataSend, 'result' => $data]);
        }
        if (!$data || $retorno != 201) {
            $error = isset($data->error_messages) ? json_encode($data->error_messages, JSON_UNESCAPED_UNICODE) : 'Unknown error';
            $this->setLogError('Error creating checkout: ' . $error);
        }
        return $data;
    }

    
    /**
    * Mount payload for checkout creation based on transaction data.
    *
    * @param array $dadosTransacao Transaction data including order info and customer details.
    * @return string JSON-encoded payload ready to be sent to PagSeguro API.
    */
    public function mountCheckoutPayload($dadosTransacao) {
       // Processar número de telefone para garantir que esteja no formato correto (Obrigatório para o PagSeguro)
        $phoneData = $this->checkPhoneNumber($dadosTransacao['celular'] ?? $dadosTransacao['telephone']);

        $dataSend = [
            "reference_id" => "#Pedido_" . $dadosTransacao['order_id'],
            "expiration_date" => (date('Y-m-d\TH:i:sP', strtotime('+' . (int)($dadosTransacao['pagseguro_expiration'] ?? 120) . ' minutes'))),
            "customer_modifiable" => false,
            "address_modifiable" => false,
            "items" => [],
            "payment_methods" => [
                ["type" => "CREDIT_CARD"],
                ["type" => "DEBIT_CARD"],
                ["type" => "BOLETO"],
                ["type" => "PIX"]
            ],
            "soft_descriptor" => "xxxx"
        ];

        $dataSend['shipping'] = $this->mountShippingData($dadosTransacao);
        $dataSend['customer'] = $this->mountCustomerData($dadosTransacao, $phoneData);
        $dataSend['payment_methods_configs'] = $this->mountPaymentMethodsConfigs();
        $this->mountUrlsData($dataSend, $dadosTransacao);
            
        if ($this->config->get('pagseguro_additional') > 0) {
            $dataSend['additional_amount'] = $this->config->get('pagseguro_additional') * 100;
        }

        if ($this->config->get('pagseguro_discount') > 0) {
            $dataSend['discount_amount'] = $this->config->get('pagseguro_discount') * 100;
        }

        $this->mountProductsData($dataSend, $dadosTransacao);

        return json_encode($dataSend, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
    }


    /**
    * Mount payload for checkout creation based on transaction data.
    *
    * @param string $checkoutId The ID of the checkout to fetch.
    * @return object Decoded JSON response from PagSeguro API containing checkout details, or null if an error occurred.
    */
    public function getCheckout($checkoutId) {
        $environment = $this->getEnvironment();

        $this->load->type('tipopagseguro');
        $this->load->type('tipocomum');

        $headers = $this->setHeader();

        $data = parent::callAPI($environment.'/checkouts/' . $checkoutId, 'GET', null, $headers, false, $retorno, Type_DadosSend::TpDados_Identificar);
        $data = is_string($data) ? json_decode($data, true) : $data;
        if ($this->log) {
            $this->setLog(['url' => 'get_checkout', 'data' => $checkoutId, 'result' => $data]);
        }
        if (!$data || $retorno != 200) {
            $error = isset($data->error_messages) ? json_encode($data->error_messages, JSON_UNESCAPED_UNICODE) : 'Unknown error';
            $this->setLogError('Error fetching checkout: ' . $error);
        }
        return $data;
    }


    /**
    * Activate a checkout by its ID.
    *
    * @param string $checkoutId The ID of the checkout to activate.
    * @return object Decoded JSON response from PagSeguro API indicating success or failure of activation, or null if an error occurred.
    */
    public function activateCheckout($checkoutId) {
        $environment = $this->getEnvironment();

        $this->load->type('tipopagseguro');
        $this->load->type('tipocomum');

        $headers = $this->setHeader();

        $data = parent::callAPI($environment.'/checkouts/' . $checkoutId. '/activate', 'POST', null, $headers, false, $retorno, Type_DadosSend::TpDados_Identificar);
        $data = is_string($data) ? json_decode($data, true) : $data;
        if ($this->log) {
            $this->setLog(['url' => 'activate', 'data' => $checkoutId, 'result' => $data]);
        }
        if (!$data || $retorno != 200) {
            $error = isset($data->error_messages) ? json_encode($data->error_messages, JSON_UNESCAPED_UNICODE) : 'Unknown error';
            $this->setLogError('Error activating checkout: ' . $error);
        }
        return $data;
    }


    /**
    * Inactivate a checkout by its ID.
    *
    * @param string $checkoutId The ID of the checkout to inactivate.
    * @return object Decoded JSON response from PagSeguro API indicating success or failure of inactivation, or null if an error occurred.
    */
    public function inactivateCheckout($checkoutId) {
        $environment = $this->getEnvironment();

        $this->load->type('tipopagseguro');
        $this->load->type('tipocomum');

        $headers = $this->setHeader();

        $data = parent::callAPI($environment.'/checkouts/' . $checkoutId. '/inactivate', 'POST', null, $headers, false, $retorno, Type_DadosSend::TpDados_Identificar);
        $data = is_string($data) ? json_decode($data, true) : $data;
        if ($this->log) {
            $this->setLog(['url' => 'inactivate', 'data' => $checkoutId, 'result' => $data]);
        }
        if (!$data || $retorno != 200) {
            $error = isset($data->error_messages) ? json_encode($data->error_messages, JSON_UNESCAPED_UNICODE) : 'Unknown error';
            $this->setLogError('Error inactivating checkout: ' . $error);
        }
        return $data;
    }

    /**
    * Create an error log
    *
    * @param mixed $logData The data to log.
    */
    private function setLogError($logData){
        $log = new Log('payment_error.txt');
        $log->write(json_encode($logData, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
    }

    /**
    * Create a transaction log
    *
    * @param mixed $logData The data to log.
    */
    public function setLog($logData){
        $log = new Log($this->config->get('pagseguro_directory'));
        $log->write(json_encode($logData, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
    }


    /**
    * Check and format a phone number to ensure it meets PagSeguro's requirements.
    *
    * @param string $phoneNumber The phone number to check and format.
    * @return array An array containing the formatted phone number with area code and number.
    */
    public function checkPhoneNumber($phoneNumber) {
        $phoneNumber = preg_replace('/\D/', '', $phoneNumber); // Remove caracteres não numéricos
        $phoneCode = str_pad(substr($phoneNumber, 0, 2), 2, '9', STR_PAD_LEFT);
        $phoneNumber = str_pad(substr($phoneNumber, 2), 9, '9', STR_PAD_LEFT);
        if ($phoneNumber[0] != '9') {
            $phoneNumber = (($phoneNumber[0] != '9') ? substr_replace($phoneNumber, '9', 0, 1) : $phoneNumber); //O número de telefone deve sempre começar com 9, caso contrário, o número ficará inválido. Para corrigir isso, verificamos se o número já começa com 9 e, se não começar, adicionamos um 9 no início.]
        }
        return [
            'area' => $phoneCode,
            'number' => $phoneNumber
        ];
    }


    /**
    * Mount shipping data for checkout creation.
    *
    * @param array $dadosTransacao The transaction data.
    * @return array An array containing the shipping data.
    */
    public function mountShippingData($dadosTransacao) {
        return [
            "address" => [
                "street" => $dadosTransacao['shipping_address_1'] ?? $dadosTransacao['payment_address_1'],
                "number" => $dadosTransacao['shipping_numero'] ?? $dadosTransacao['payment_numero'],
                "complement" => empty($dadosTransacao['shipping_complemento'] ?? $dadosTransacao['payment_complemento']) ? 'Não informado' : ($dadosTransacao['shipping_complemento'] ?? $dadosTransacao['payment_complemento']),
                "locality" => $dadosTransacao['shipping_address_2'] ?? $dadosTransacao['payment_address_2'],
                "city" => $dadosTransacao['shipping_city'] ?? $dadosTransacao['payment_city'],
                "region_code" => strtoupper($dadosTransacao['shipping_zone_code'] ?? $dadosTransacao['payment_zone_code']),
                "country" => "BRA",
                "postal_code" => $dadosTransacao['shipping_postcode'] ?? $dadosTransacao['payment_postcode']
            ],
            "type" => "FIXED",
            "address_modifiable" => false,
            "amount" => ($dadosTransacao['shipping_value'] ?? 0) * 100
        ];
    }


    /**
    * Formats and mounts customer data for checkout creation based on transaction data and phone information.
    *
    * @param array $dadosTransacao The transaction data.
    * @param array $phoneData The formatted phone number data.
    * @return array An array containing the customer data.
    */
    public function mountCustomerData($dadosTransacao, $phoneData) {
        return [
            "name"  => $dadosTransacao['firstname'] . ' ' . $dadosTransacao['lastname'],
            "email" => $dadosTransacao['email'],
            "tax_id" => $dadosTransacao['cpf'] ?? $dadosTransacao['cnpj'],
            "phone" => [
                "country" => "+55",
                "area" => $phoneData['area'],
                "number" => $phoneData['number']
            ],
        ];
    }


    /**
    * Mount payment method configurations for checkout creation based on module settings.
    *
    * @return array An array containing the payment method configurations.
    */
    public function mountPaymentMethodsConfigs() {
        $configs = [];

        if ($this->config->get('pagseguro_parcela_qtd')) {
            $configs[] = [
                "config_options" => [
                    [
                        "option" => "INSTALLMENTS_LIMIT",
                        "value" => $this->config->get('pagseguro_parcela_qtd')
                    ]
                ],
                "type" => "CREDIT_CARD"
            ];
        }

        if ($this->config->get('pagseguro_parcela_vendedor_qtd') > 1) {
            if (!isset($configs[0])) {
                $configs[0] = [
                    "config_options" => [],
                    "type" => "CREDIT_CARD"
                ];
            }
            $configs[0]['config_options'][] = [
                "option" => "INTEREST_FREE_INSTALLMENTS",
                "value" => $this->config->get('pagseguro_parcela_vendedor_qtd')
            ];
        }

        return $configs;
    }

    /**
    * Mount URL data for checkout creation.
    *
    * @param array $dataSend The data array to populate.
    * @param array $dadosTransacao The transaction data.
    * @return void
    */
    public function mountUrlsData(&$dataSend, $dadosTransacao) {
        $dataSend["redirect_url"] = defined('AMBIENTE_TESTE') ? "https://efutura.futurasistemas.com.br/pagseguro/pagseguroredirect.php" : $dadosTransacao['redirect_url'];
        $dataSend["notification_urls"] = defined('AMBIENTE_TESTE') ? ["https://efutura.futurasistemas.com.br/payment/pagseguro_notification.php"] : [$dadosTransacao['notification_urls']];
        $dataSend["payment_notification_urls"] = defined('AMBIENTE_TESTE') ? ["https://efutura.futurasistemas.com.br/payment/pagseguro_notification.php"] : [$dadosTransacao['payment_notification_urls']];
        $dataSend["return_url"] = defined('AMBIENTE_TESTE') ? "https://efutura.futurasistemas.com.br/pagseguro/pagseguroredirect.php" : $dadosTransacao['return_url'];;
    }


    /**
    * Mount product data for checkout creation.
    *
    * @param array $dataSend The data array to populate.
    * @param array $dadosTransacao The transaction data.
    * @return void
    */
    public function mountProductsData(&$dataSend, $dadosTransacao) {
        if (isset($dadosTransacao['products']) && is_array($dadosTransacao['products'])) {
            foreach ($dadosTransacao['products'] as $product) {
                $dataSend['items'][] = [
                    "reference_id" => "REF-" . $product['product_id'],
                    "name" => $product['name'],
                    "description" => $product['model'],
                    "quantity" => (int)$product['quantity'],
                    "unit_amount" => (int)($product['price'] * 100),
                    "image_url" => (defined("AMBIENTE_TESTE") ? "https://picsum.photos/200/300" : ($dadosTransacao['image_url'] . $product['image']))
                ];
            }
        }
    }

    /**
    * Encryt the passed string
    *
    * @param string $data The string to encrypt.
    * @return string
    */
    public function encryptData($data){
        if ($data) {
            $ivlen = openssl_cipher_iv_length($this->method);
            $iv = random_bytes($ivlen);

            $encryptData = openssl_encrypt($data, $this->method, $this->key, 0, $iv);

            return base64_encode($iv . $encryptData);
        }
        return "";
    }

    /**
    * Decryt the passed string
    *
    * @param string $data The string to decrypt.
    * @return string
    */
    public function decryptData($data){
        if ($data) {
            $decode = base64_decode($data);
            $ivlen = openssl_cipher_iv_length($this->method);

            $ivFromMessage = substr($decode, 0, $ivlen);

            $textoCripto = substr($decode, $ivlen);

            $decryptData = openssl_decrypt($textoCripto, $this->method, $this->key, 0, $ivFromMessage);

            return $decryptData;
        }
        return "";
    }
}
