<?php

use IpagWoocommerce\IpagResponseException;

class WC_Gateway_iPag_Boleto extends WC_iPag_Loader
{
    public $days_pay;
    public $pagseguro_ambiente;
    public $checkout_message;
    public $bank_emitter;
    public $pagseguro_email;
    public $pagseguro_token;

    public function __construct()
    {
        $this->id = 'ipag-gateway_boleto';
        $this->has_fields = true;
        $this->method_title = __('iPag - Billet', 'ipag-gateway');
        $this->method_description = __('iPag Secure Payment', 'ipag-gateway');
        $this->supports = array('products', 'refunds');

        $this->init_form_fields();
        $this->init_settings();

        $this->enabled = $this->get_option('enabled');
        $this->title = $this->get_option('title');
        $this->identification = $this->get_option('identification');
        $this->pagseguro_ambiente = $this->get_option('psenvironment');
        $this->pagseguro_email = $this->get_option('pagseguro_email');
        $this->pagseguro_token = $this->get_option('pagseguro_token');
        $this->apikey = $this->get_option('apikey');
        $this->bank_emitter = $this->get_option('bank_emitter');
        $this->days_pay = $this->get_option('days_pay');
        $this->checkout_message = $this->get_option('checkout_message');
        $this->environment = $this->get_option('environment');
        $this->debug = $this->get_option('debug');
        $this->icon = $this->getIpagLogo($this);

        add_action('wp_enqueue_scripts', array($this, 'checkout_scripts'));

        add_action('woocommerce_admin_order_data_after_shipping_address', array($this, 'orderInfo'));
        add_action('woocommerce_update_options_payment_gateways_' . $this->id, array($this, 'process_admin_options'));
        add_action('woocommerce_thankyou_' . $this->id, array($this, 'order_received'));
    }

    public function init_form_fields()
    {
        $this->form_fields = array(
            'enabled' => array(
                'title' => __('Enable iPag Payment Gateway', 'ipag-gateway'),
                'type' => 'checkbox',
                'label' => __('Enable', 'ipag-gateway'),
                'default' => 'no',
            ),
            'title' => array(
                'title' => __('iPag Title', 'ipag-gateway'),
                'type' => 'text',
                'description' => __('This controls the title that users will see during checkout.', 'ipag-gateway'),
                'default' => __('iPag - Billet', 'ipag-gateway'),
                'desc_tip' => true,
            ),
            'environment' => array(
                'title' => __('Environment', 'ipag-gateway'),
                'type' => 'select',
                'desc_tip' => false,
                'default' => 'production',
                'options' => array(
                    'local' => __('Local', 'ipag-gateway'),
                    'test' => __('Test', 'ipag-gateway'),
                    'production' => __('Production', 'ipag-gateway'),
                ),
            ),
            'identification' => array(
                'title' => __('Store Identification', 'ipag-gateway'),
                'type' => 'text',
                'description' => __('Your store identification registered at iPag Panel.', 'ipag-gateway'),
                'default' => '',
                'desc_tip' => true,
            ),
            'apikey' => array(
                'title' => __('Ipag API KEY', 'ipag-gateway'),
                'type' => 'text',
                'description' => __('Your store API KEY at iPag Panel.', 'ipag-gateway'),
                'default' => '',
                'desc_tip' => true,
            ),
            'bank_emitter' => array(
                'title' => __('Bank Billet\'s Emitter', 'ipag-gateway'),
                'type' => 'select',
                'description' => __('Select the bank billet\'s emitter.', 'ipag-gateway'),
                'desc_tip' => true,
                'class' => 'wc-enhanced-select',
                'default' => 'boleto',
                'options' => array(
                    'boleto' => 'Boleto Configurado no Painel iPag (Recomendado)',
                    'boleto_bb' => '(Sem Registro) Banco do Brasil',
                    'boleto_bradesco' => '(Sem Registro) Bradesco',
                    'boleto_itau' => '(Sem Registro) Boleto via Itaú',
                    'boletosicredi' => 'Boleto Bancário via Sicredi Cobrança Online',
                    'boleto_banespasantander' => 'Boleto Bancário via Santander Cobrança XML',
                    'boletoitaushopline' => 'Boleto Bancário via Itaú Shopline',
                    'boletozoop' => 'Boleto Bancário via iPag/Zoop',
                    'boletosicoob' => 'Boleto Bancário via Sicoob (Online)',
                    'boletoshopfacil' => 'Boleto Bancário via Bradesco Shopfácil',
                    'boletobb' => 'Boleto Bancário via Banco do Brasil Cobrança Eletrônica',
                    'boletopagseguro' => 'Boleto Bancário via PagSeguro',
                    'boletosimulado' => 'Boleto Simulado (Apenas para teste em Homologação)'
                ),
            ),
            'days_pay' => array(
                'title' => __('Days To Pay', 'ipag-gateway'),
                'type' => 'text',
                'description' => __('Quantity of days that your client has to pay the billet.', 'ipag-gateway'),
                'default' => '3',
                'desc_tip' => true,
            ),
            'checkout_message' => array(
                'title' => __('Checkout Message', 'ipag-gateway'),
                'type' => 'text',
                'description' => __('This controls the message that users will see before print the billet.', 'ipag-gateway'),
                'default' => __('Confirm your order to print the billet.', 'ipag-gateway'),
                'desc_tip' => true,
            ),
            'require_document' => array(
                'type' => 'checkbox',
                'title' => __('Exibe campo de documento (CPF/CNPJ)', 'ipag-gateway'),
                'label' => __('Enable', 'ipag-gateway'),
                'desc_tip' => true,
                'default' => 'no',
            ),
            'debug' => array(
                'title' => __('Enable Debug', 'ipag-gateway'),
                'label' => __('Enable', 'ipag-gateway'),
                'type' => 'checkbox',
                'desc_tip' => false,
                'default' => 'no',
            ),
            'psenvironment' => array(
                'title' => 'PagSeguro ' . __('Environment', 'ipag-gateway'),
                'type' => 'select',
                'desc_tip' => false,
                'default' => 'production',
                'options' => array(
                    '0' => __('Test', 'ipag-gateway'),
                    '1' => __('Production', 'ipag-gateway'),
                ),
            ),
            'pagseguro_email' => array(
                'title' => __('PagSeguro Email', 'ipag-gateway'),
                'type' => 'text',
                'desc_tip' => true,
                'description' => __('E-mail para integração com PagSeguro', 'ipag-gateway'),
                'default' => '',
            ),
            'pagseguro_token' => array(
                'title' => __('PagSeguro Token', 'ipag-gateway'),
                'type' => 'text',
                'desc_tip' => true,
                'description' => __('Token para integração com PagSeguro', 'ipag-gateway'),
                'default' => '',
            ),
        );
    }

    public function admin_options()
    {
        ?>
        <h2><?php _e('iPag Payment Gateway - Billet', 'ipag-gateway'); ?></h2>
        <table class="form-table">
            <?php $this->generate_settings_html(); ?>
        </table>
        <?php
    }

    public function orderInfo()
    {
        if (self::getRequestId()) {
            $order_id = self::getRequestId();
            $order = new WC_Order($order_id);
            $method = self::getProp($order, 'payment_method');

            if ($method === 'ipag-gateway_boleto')
                $this->order_info();
        }
    }

    public function order_received($order_id)
    {
        $order = new WC_Order($order_id);
        $method = self::getProp($order, 'payment_method');

        if ($method == $this->id && ($order->needs_payment() || $order->has_status('on-hold'))) {
            $urlBoleto = get_post_meta($order_id, '_billet_url', true);

            if (!empty($urlBoleto)) {
                $html = '<div class="woocommerce-info">';
                $html .= sprintf('<a class="button" href="%s" target="_blank" style="display: block !important; visibility: visible !important;">%s</a>', esc_url($urlBoleto), __('Imprimir Boleto') . ' &rarr;');
                $html .= __('Clique no link ao lado para imprimir o boleto.') . '<br />';
                $html .= '</div>';
                echo $html;
            }
        }
    }

    public function payment_fields()
    {
        echo '<fieldset id="ipag-boleto-payment-form" class="ipag-payment-form">';
        echo '<h2>' . $this->checkout_message . '</h2>';

        if ($this->bank_emitter == 'boletopagseguro' && !empty($this->pagseguro_email) && !empty($this->pagseguro_token)) {

            ?>
            <input type="hidden" name="boleto_hashpagseguro" id="boleto_hashpagseguro" />
            <script>
                var $j = window.$ || jQuery.noConflict();

                function getSenderHashBoleto() {
                    PagSeguroDirectPayment.onSenderHashReady(function (response) {
                        $j('#boleto_hashpagseguro').val(response.senderHash);
                    });
                }

                callPagSeguroBoleto = function () {
                    console.log("Boleto Pagseguro sendo ativado.")
                    var session = "<?php echo $this->pagsegurosession($this->pagseguro_email, $this->pagseguro_token, $this->pagseguro_ambiente); ?>";
                    console.log("Session Id: " + session);
                    PagSeguroDirectPayment.setSessionId(session);
                    getSenderHashBoleto();

                }

                $j(document).ready(function () {
                    callPagSeguroBoleto();
                });

                $j('form.checkout').on('checkout_place_order_ipag-gateway_boleto', function (e) {
                    return iPagFormValidator('boleto', '<?php echo $this->environment; ?>', true);
                });

                $j('form#order_review').submit(function (e) {
                    return iPagFormValidator('boleto', '<?php echo $this->environment; ?>', true);
                });
            </script>

            <?php
        }

        if ($this->get_option('require_document') === 'yes') {
            ?>
            <p class="form-row form-row-wide">
                <label for="ipag_boleto_document"><?php _e('CPF/CNPJ', 'ipag-gateway'); ?> <span class="required">*</span></label>
                <input required type="text" class="input-text" name="ipag_boleto_document" id="ipag_boleto_document" maxlength="18"
                    placeholder="<?php _e('Digite seu CPF ou CNPJ', 'ipag-gateway'); ?>"
                    value="<?php echo (isset($_POST['ipag_boleto_document']) ? esc_attr($_POST['ipag_boleto_document']) : ''); ?>" />
            </p>
            <script src="<?= plugins_url('js/masks.js', dirname(__FILE__)) ?> "></script>
            <script src="<?= plugins_url('js/cpf_cnpj.js', dirname(__FILE__)) ?> "></script>
            <script>
                var $j = window.$ || jQuery.noConflict();

                $j(document).ready(function ($) {
                    $j('#ipag_boleto_document').on('input', function (e) {
                        let v = e.target.value;
                        v = v.replace(/\D/g, '');

                        if (v.length > 11) {
                            e.target.value = window.maskCnpj(v);
                            return;
                        }

                        e.target.value = window.maskCpf(v);
                    });
                });
            </script>
            <?php
        }

        echo '</fieldset>';
    }

    public function process_payment($order_id)
    {
        $result = $this->process_ipag_payment($order_id);

        if (!$result['success']) {
            wc_add_notice(__('Payment error: ' . $result['message'], 'ipag-gateway'), 'error');
            self::addDataLog(">>> FIM_PROCESSO_PGTO_BOLETO ORDER #{$order_id} <<<");

            $is_blocks = isset($_POST['ipag_woo_payments_blocks']) && $_POST['ipag_woo_payments_blocks'] === 'yes';

            if ($is_blocks) {
                throw new Exception('Payment error: ' . $result['message']);
            }

            return array(
                'result' => 'fail',
                'redirect' => $result['message'],
            );
        }

        global $woocommerce;
        $order = new WC_Order($order_id);
        $order->set_total($result['total']);

        version_compare($woocommerce->version, '3.0', '>=') ?
            wc_reduce_stock_levels($order_id) :
            $order->reduce_order_stock();

        $woocommerce->cart->empty_cart();

        self::addDataLog(">>> FIM_PROCESSO_PGTO_BOLETO ORDER #{$order_id} <<<");

        return array(
            'result' => 'success',
            'redirect' => $this->get_return_url($order),
        );
    }

    public function process_ipag_payment($order_id)
    {
        $order = new WC_Order($order_id);
        $date = new DateTime();
        $date->modify('+' . $this->days_pay . ' days');
        $args = $this->getOrderData($order);

        self::addDataLog(">>> INICIO_PROCESSO_PGTO_BOLETO ORDER #{$order_id} <<<");

        update_post_meta($order_id, '_venc_date', (string) $date->format('d/m/Y'));
        update_post_meta($order_id, '_ipag_process_started', true);

        $documento = $args['documento'];
        $produtos = $this->getDescricaoPedido($order);

        $v_date = get_post_meta($order_id, '_venc_date', true);
        $venc_date = !empty($v_date) ? $v_date : '';
        $total = (float) $order->get_total();

        $fingerprintPS = (isset($_POST['boleto_hashpagseguro'])) ? $_POST['boleto_hashpagseguro'] : '';

        if (!empty($this->pagseguro_email) && !empty($this->pagseguro_token)) {
            self::addDataLog("Verificando dados do PagSeguro para o pedido #{$order_id}", [
                'bank_emitter' => $this->bank_emitter,
                'fingerprintPS' => $fingerprintPS,
            ], 'info');
            if ($this->bank_emitter == 'boletopagseguro') {
                if (!isset($_POST['boleto_hashpagseguro'])) {
                    $error_message = __(' Erro ao processar boleto PagSeguro, entre em contato com o lojista!', 'ipag-gateway');
                    return [
                        'success' => false,
                        'message' => $error_message,
                    ];
                } else {
                    $fingerprintPS = $_POST['boleto_hashpagseguro'];
                    self::addDataLog("Boleto PagSeguro hash de segurança recebido para o pedido #{$order_id}", [
                        'fingerprintPS' => $fingerprintPS,
                    ], 'info');
                }
            }
        }

        $payload = array(
            'identificacao' => $this->identification,
            'metodo' => $this->bank_emitter,
            'operacao' => 'Pagamento',
            'pedido' => $order_id,
            'valor' => number_format($total, 2, '.', ''),
            'fingerprint' => $fingerprintPS,
            'nome' => $args['billingName'],
            'documento' => preg_replace('/[\D]/', '', $documento),
            'email' => $args['billingEmail'],
            'fone' => preg_replace('/[\D]/', '', $args['billingPhone']),
            'endereco' => trim($args['billingAddress']),
            'numero_endereco' => str_replace(' ', '', $args['billingNumber']),
            'bairro' => empty($args['billingNeighborhood']) ? 'bairro' :
                trim(preg_replace("/[^a-zA-Z ]/", "", $args['billingNeighborhood'])),
            'complemento' => empty($args['billingAddress2']) ? '' :
                trim(preg_replace("/[^a-zA-Z ]/", "", $args['billingAddress2'])),
            'cidade' => $args['billingCity'],
            'estado' => substr($args['billingState'], 0, 2),
            'pais' => 'Brasil',
            'cep' => preg_replace('/[\D]/', '', $args['billingPostcode']),
            'endereco_entrega' => trim($args['shippingAddress']),
            'numero_endereco_entrega' => str_replace(' ', '', $args['shippingNumber']),
            'bairro_entrega' => empty($args['shippingNeighborhood']) ? 'bairro' :
                trim(preg_replace("/[^a-zA-Z ]/", "", $args['shippingNeighborhood'])),
            'complemento_entrega' => empty($args['shippingAddress2']) ?:
                trim(preg_replace("/[^a-zA-Z ]/", "", $args['shippingAddress2'])),
            'cidade_entrega' => $args['shippingCity'],
            'estado_entrega' => substr($args['shippingState'], 0, 2),
            'cep_entrega' => preg_replace('/[\D]/', '', $args['shippingPostcode']),
            'boleto_tipo' => 'XML',
            'retorno_tipo' => 'XML',
            'url_retorno' => self::isLocal() ? self::getLocalCallbackUrl() . "?wc-api=wc_gateway_ipag&id={$order_id}" : home_url('/wc-api/wc_gateway_ipag/?id=' . $order_id),
            'descricao_pedido' => $produtos,
            'ip' => $this->getClientIp(),
            'vencto' => $venc_date,
        );

        return $this->processBillet($payload, $order, $total);
    }

    public function checkout_scripts()
    {
        if (is_checkout() && $this->enabled == 'yes') {
            wp_enqueue_script('ipag-cartao-js', plugins_url('js/cartao.js', dirname(__FILE__)), array(), null, true);

            wp_localize_script(
                'ipag-cartao-js',
                'errors',
                array(
                    'invalid_card' => __('Invalid credit card number.', 'ipag-gateway'),
                    'invalid_cvv' => __('Invalid CVV.', 'ipag-gateway'),
                    'invalid_name' => __('Invalid name.', 'ipag-gateway'),
                    'invalid_expiry' => __('Invalid expiry date.', 'ipag-gateway'),
                    'expired_card' => __('Expired card.', 'ipag-gateway'),
                    'invalid_cpf' => __('Invalid CPF.', 'ipag-gateway'),
                    'invalid_installment' => __('Please choose an installment option.', 'ipag-gateway'),
                )
            );
        }
    }

    public function processBillet($payload, $order, $total = null)
    {
        $order_id = self::getProp($order, 'id');

        $url = self::buildRequestUrl('service/payment', $this->environment);

        $headers = $this->buildRequestHeaders([
            'Accept' => 'application/xml',
        ]);

        $args = $this->buildRequestPayload(
            array(
                'body' => $payload,
                'headers' => $headers,
            )
        );

        $parser = !$this->isPayloadV1($args) ? null : $this->findEndpointV2Parser($url);

        if ($parser) {
            $url = $this->transformParserRequestUrl($parser, $url) ?: $url;
            $args = $this->transformParserRequestPayload($parser, $args) ?: $args;
        }

        try {
            $result = $this->wp_remote_post_wrapper($url, $args);
            $result = $this->transformParserResponse($parser, $result);

            $xml = simplexml_load_string($result['body'], 'SimpleXMLElement');

            if (!empty($xml) && is_object($xml)) {
                $order->update_status('pending', 'Aguardando o pagamento do boleto');

                update_post_meta($order_id, '_transaction_message', (string) $xml->mensagem_transacao);
                update_post_meta($order_id, '_billet_url', (string) $xml->url_autenticacao);
                update_post_meta($order_id, '_status_payment', (string) $xml->status_pagamento);
                update_post_meta($order_id, '_transaction_id', (string) $xml->id_transacao);
                update_post_meta($order_id, '_operator_message', (string) $xml->operadora_mensagem);
                update_post_meta($order_id, '_digitable_line', (string) $xml->linha_digitavel);
                update_post_meta($order_id, '_metodo', (string) $xml->metodo);

                self::addDataLog("processo de pagamento do pedido #{$order_id} finalizado com sucesso", [
                    'order_id' => $order_id,
                    'id_transacao' => (string) $xml->id_transacao,
                    'payment_link' => (string) $xml->url_autenticacao
                ], 'info');

                return [
                    'success' => true,
                    'message' => '',
                    'total' => $total,
                ];
            }

            self::addDataLog("erro ao processar dados recebido do iPag referente ao pedido #{$order_id}", compact('xml'), 'erro');
            throw new Exception('Error processing payment');
        } catch (Exception $e) {
            $dataLog = [
                'url' => $url,
                'exception' => strval($e)
            ];

            if ($e instanceof IpagResponseException)
                $dataLog['response'] = $e->getResponse();

            self::addDataLog("erro de comunicação com a api do iPag (processamento de pagamento do pedido #{$order_id}): {$e->getMessage()}", $dataLog, 'erro');

            $error_message = $e->getMessage();

            $error_message = wp_unslash($error_message);
            $decoded = json_decode($error_message, true);
            $error_message = $decoded;

            $error_message = html_entity_decode($error_message);

            $order->update_status('failed', __('Payment error: ' . $error_message, 'ipag-gateway'));

            return [
                'success' => false,
                'message' => $error_message,
            ];
        }
    }

    /**
     * Display pending payment message in order details.
     *
     * @param  int $order_id Order id.
     *
     * @return void        Message HTML.
     */
    public static function pending_payment_message($order_id)
    {
        $html = '';
        $order = new WC_Order($order_id);
        $codboleto = 'ipag-gateway_boleto';
        $order_id = self::getProp($order, 'id');
        $method = self::getProp($order, 'payment_method');

        $status = $order->get_status();
        if ('on-hold' === $status && $method == $codboleto) {
            $url = get_post_meta($order_id, '_billet_url', true);
            $html = '<div class="woocommerce-info">';
            $html .= sprintf('<a class="button" href="%s" target="_blank" style="display: block !important; visibility: visible !important;">%s</a>', esc_url($url), __('Imprimir Boleto') . ' &rarr;');
            $html .= __('Clique no link ao lado para imprimir o boleto.') . '<br />';
            $html .= '</div>';
        }

        echo $html;
    }
}
