<?php

use Sibs2\sibsConfig;
use Sibs2\sibsConstants;
use Sibs2\sibsFunctions;
use Sibs2\sibsGeneralModels;
use Sibs2\sibsLogger;

defined('ABSPATH') || exit;

class SibsPaymentCore
{
    protected static $ack_patterns = [
        '/^(000)/',
    ];

    /**
     * SIBS Get Checkout URL.
     *
     * @param string $server_mode
     * @param array $checkout_endpoints
     * @return string
     */
    private static function sibs_get_checkout_url($server_mode, $checkout_endpoints)
    {
        sibsLogger::debug('Entrou em sibs_get_checkout_url', sibsConstants::SIBS_LOG);
        return $checkout_endpoints[$server_mode];
    }

    /**
     * SIBS Get Payment Status URL.
     *
     * @param string $server_mode
     * @param string $transaction_id
     * @param array $checkout_endpoints
     * @return string
     */
    private static function sibs_get_payment_status_url($server_mode, $transaction_id, $checkout_endpoints)
    {
        sibsLogger::debug('Entrou em sibs_get_payment_status_url', sibsConstants::SIBS_LOG);
        return $checkout_endpoints[$server_mode] . "/$transaction_id/status";
    }

    /**
     * SIBS Get BackOffice URL.
     *
     * @param string $server_mode
     * @param string $reference_id
     * @param array $back_office_endpoints
     * @return string
     */
    private static function sibs_get_back_office_url($server_mode, $reference_id, $back_office_endpoints)
    {
        sibsLogger::debug('Entrou em sibs_get_back_office_url', sibsConstants::SIBS_LOG);
        return $back_office_endpoints[$server_mode] . $reference_id;
    }

    /**
     * SIBS Get SPG BackOffice URL.
     *
     * @param mixed $order
     * @param string $reference_id
     * @param string $server_mode
     * @param array $backoffice
     * @return string
     */
    private static function sibs_get_spg_back_office_url($order, $reference_id, $server_mode, $backoffice)
    {
        sibsLogger::debug('Entrou em sibs_get_spg_back_office_url', sibsConstants::SIBS_LOG);
        $end_url = self::get_endpoint($order['payment_type']);
        return $backoffice[$server_mode] . $reference_id . $end_url;
    }

    /**
     * Get Endpoint.
     *
     * @param string $payment_type
     * @return string
     */
    private static function get_endpoint($payment_type)
    {
        sibsLogger::debug('Entrou em get_endpoint', sibsConstants::SIBS_LOG);
        switch($payment_type) {
            case sibsConstants::SPG_PAYMENT_TYPE_CAPT:
                return '/capture';

                break;
            case sibsConstants::SPG_PAYMENT_TYPE_RFND:
                return '/refund';

                break;
            case sibsConstants::SPG_PAYMENT_TYPE_CAUT:
                return '/cancellation';

                break;
            default:
                return '/none';
        }
    }

    /**
     * SIBS Get SSL Verify.
     *
     * @param string $server_mode
     * @return bool
     */
    private static function sibs_get_ssl_verify($server_mode)
    {
        sibsLogger::debug('Entrou em sibs_get_ssl_verify', sibsConstants::SIBS_LOG);
        if (in_array($server_mode, ['DEV', 'TST', 'QLY', 'CER'])) {
            return false;
        }
        return true;
    }

    /**
     * SIBS Get WP Response.
     *
     * @param mixed $response
     * @return array
     */
    private static function sibs_get_wp_response($response)
    {
        sibsLogger::debug('Entrou em sibs_get_wp_response', sibsConstants::SIBS_LOG);
        if (is_wp_error($response)) {
            $result['response'] = __('Unfortunately, your transaction has failed. Please try again', sibsConstants::SIBS_TRANSLATE);
            $result['is_valid'] = false;
            $error_code         = $response->get_error_code();
            $error_message      = $response->get_error_message();
            sibsLogger::error('Error Code: ' . sibsLogger::prettify($error_code), sibsConstants::SIBS_LOG);
            sibsLogger::error('Error Message: ' . sibsLogger::prettify($error_message), sibsConstants::SIBS_LOG);

            if (strpos($error_message, 'cURL error 60') !== false) {
                $result['response'] = 'ERROR_MERCHANT_SSL_CERTIFICATE';
            }

            return $result;
        }

        $response      = wp_remote_retrieve_body($response);
        $json_response = json_decode($response, true);

        $result['response'] = isset($json_response) ? $json_response : $response;
        $result['is_valid'] = true;

        sibsLogger::debug('result: ' . sibsLogger::prettify($result), sibsConstants::SIBS_LOG);

        return $result;
    }

    /**
     * SIBS Get Headers.
     *
     * @param string $token
     * @param string $clientId
     * @return array
     */
    private static function sibs_get_headers($token = null, $clientId = null)
    {
        sibsLogger::debug('Entrou em sibs_get_headers', sibsConstants::SIBS_LOG);
        $headers = [
            'content-type' 	=> 'application/json',
            'charset' 			   => 'UTF-8',
        ];

        if (! empty($token)) {
            $headers = array_merge($headers, [
                'Authorization' => "Bearer $token",
            ]);

            if (! empty($clientId)) {
                $headers = array_merge($headers, [
                    'X-IBM-Client-Id' => $clientId,
                ]);
            }
        }

        return $headers;
    }

    /**
     * SIBS Get Response Data.
     *
     * @param string $url
     * @param array $data
     * @param string $server_mode
     * @param string $token
     * @param string $clientId
     * @return array
     */
    private static function sibs_get_response_data($url, $data, $server_mode, $token = null, $clientId = null)
    {
        sibsLogger::debug('Entrou em sibs_get_response_data', sibsConstants::SIBS_LOG);
        $data_json = json_encode($data);
        $headers   = self::sibs_get_headers($token, $clientId);

        $args = [
            'headers'   => $headers,
            'body'      => $data_json,
            'sslverify' => self::sibs_get_ssl_verify($server_mode),
            'timeout'   => 200,
        ];

        sibsLogger::debug('sibs_get_response_data', sibsConstants::SIBS_LOG);
        sibsLogger::debug("url: $url", sibsConstants::SIBS_LOG);
        sibsLogger::debug('args: ' . sibsLogger::prettify($args), sibsConstants::SIBS_LOG);

        $response = wp_remote_post($url, $args);

        return self::sibs_get_wp_response($response);
    }

    /**
     * SIBS GET Payment Widget Content.
     *
     * @param string $url
     * @param string $server_mode
     * @return array
     */
    public static function sibs_get_payment_widget_content($url, $server_mode)
    {
        sibsLogger::debug('Entrou em sibs_get_payment_widget_content', sibsConstants::SIBS_LOG);
        $args = [
            'sslverify' => self::sibs_get_ssl_verify($server_mode),
            'timeout'   => 200,
        ];

        sibsLogger::debug("url: $url", sibsConstants::SIBS_LOG);
        sibsLogger::debug('args: ' . sibsLogger::prettify($args), sibsConstants::SIBS_LOG);

        $response = wp_remote_get($url, $args);

        return self::sibs_get_wp_response($response);
    }

    /**
     * SIBS Get Payment Response.
     *
     * @param string $url
     * @param string $token
     * @param string $clientId
     * @return string|false
     */
    private static function sibs_get_payment_response($url, $token = null, $clientId = null)
    {
        sibsLogger::debug('Entrou em sibs_get_payment_response', sibsConstants::SIBS_LOG);
        $headers = self::sibs_get_headers($token, $clientId);

        $args = [
            'headers'   => $headers,
            'sslverify' => false,
        ];

        sibsLogger::debug("url: $url", sibsConstants::SIBS_LOG);
        sibsLogger::debug('args: ' . sibsLogger::prettify($args), sibsConstants::SIBS_LOG);

        $response = wp_remote_get($url, $args);

        if (is_wp_error($response)) {
            sibsLogger::debug('response: error', sibsConstants::SIBS_LOG);

            return false;
        }

        $response = json_decode(wp_remote_retrieve_body($response), true);

        sibsLogger::debug('response: ' . sibsLogger::prettify($response), sibsConstants::SIBS_LOG);

        return $response;
    }

    /**
     * Get Token.
     *
     * @return mixed
     */
    public static function getToken()
    {
        sibsLogger::debug('Entrou em getToken', sibsConstants::SIBS_LOG);
        $authetication             = [];
        $authetication['token']    = sibsConfig::getToken();
        $authetication['clientId'] = sibsConfig::getClientId();

        return $authetication;
    }

    /**
     * SIBS Get Payment Credential.
     *
     * @param array $status_parameters
     * @return array
     */
    private static function sibs_get_payment_credential($status_parameters)
    {
        sibsLogger::debug('Entrou em sibs_get_payment_credential', sibsConstants::SIBS_LOG);
        $payment_credential             = [];
        $payment_credential['entityId'] = $status_parameters['channel_id'];

        if (! empty($status_parameters['test_mode'])) {
            $payment_credential['testMode'] = $status_parameters['test_mode'];
        }

        return $payment_credential;
    }

    /**
     * SIBS set SPG Back Office Parameters.
     *
     * @param mixed $order
     * @param string $reference_id
     * @param int $order_id
     * @return array
     */
    private static function sibs_set_spg_back_office_parameters($order, $reference_id, $order_id)
    {
        sibsLogger::debug('Entrou em sibs_set_spg_back_office_parameters', sibsConstants::SIBS_LOG);
        sibsLogger::debug("order_id: $order_id", sibsConstants::SIBS_LOG);
        sibsLogger::debug('BO order: ' . sibsLogger::prettify($order), sibsConstants::SIBS_LOG);

        $transaction_log = sibsGeneralModels::sibs_get_db_transaction_log($order_id);

        $parameters = [
            'merchant' => [
                'terminalId'            => sibsConfig::getTerminalId(),
                'channel'               => sibsConfig::getChannel(),
                'merchantTransactionId' => $transaction_log['order_no'],
            ],
            'transaction' => [
                'amount' => [
                    'value'    => floatval(sibsFunctions::sibs_set_number_format($order['amount'])),
                    'currency' => $order['currency'],
                ],
                'description'          => sibsConfig::getEcommerceName(),
                'transactionTimestamp' => wp_date('Y-m-d\TH:i:s.vP'),
                'originalTransaction'  => [
                    'id'       => $reference_id,
                    'datetime' => $transaction_log['date'],
                ],
            ],
        ];

        return $parameters;
    }

    /**
     * SIBS Is Payment Get Response.
     *
     * @param string $payment_status_url
     * @param mixed &$payment_response
     * @param string $token
     * @param string $clientId
     * @return bool
     */
    private static function sibs_is_payment_get_response($payment_status_url, &$payment_response, $token, $clientId)
    {
        sibsLogger::debug('Entrou em sibs_is_payment_get_response', sibsConstants::SIBS_LOG);
        for ($i = 0; $i < 3; $i++) {
            $response = true;

            try {
                $payment_response = self::sibs_get_payment_response($payment_status_url, $token, $clientId);
            } catch (Exception $e) {
                $response = false;
            }

            if ($response && $payment_response) {
                return true;
            }
        }

        return false;
    }

    /**
     * SIBS Get Checkout Result.
     *
     * @param array $post_data
     * @param string $server_mode
     * @return array
     */
    public static function sibs_get_checkout_result($post_data, $server_mode)
    {
        sibsLogger::debug('Entrou em sibs_get_checkout_result', sibsConstants::SIBS_LOG);
        $environment_file   = sibsFunctions::get_environment();
        $checkout_endpoints = $environment_file['checkout_endpoints'];

        $checkout_url  = self::sibs_get_checkout_url($server_mode, $checkout_endpoints);
        $authetication = self::getToken();

        return self::sibs_get_response_data($checkout_url, $post_data, $server_mode, $authetication['token'], $authetication['clientId']);
    }

    /**
     * SIBS Get Payment Widget URL.
     *
     * @param string $environment
     * @param string $checkout_id
     * @param array $widget_endpoints
     * @return string
     */
    public static function sibs_get_payment_widget_url($environment, $checkout_id, $widget_endpoints)
    {
        sibsLogger::debug('Entrou em sibs_get_payment_widget_url', sibsConstants::SIBS_LOG);
        return $widget_endpoints[$environment] . $checkout_id;
    }

    /**
     * SIBS Get Payment Status.
     *
     * @param string $transaction_id
     * @param array $status_parameters
     * @return false
     */
    public static function sibs_get_payment_status($transaction_id, $status_parameters)
    {
        sibsLogger::debug('Entrou em sibs_get_payment_status', sibsConstants::SIBS_LOG);
        $environment_file   = sibsFunctions::get_environment();
        $checkout_endpoints = $environment_file['checkout_endpoints'];

        $payment_status_url = self::sibs_get_payment_status_url($status_parameters['server_mode'], $transaction_id, $checkout_endpoints);
        $payment_status_url .= '?' . http_build_query(self::sibs_get_payment_credential($status_parameters), '', '&');

        $authetication = self::getToken();

        $response = self::sibs_is_payment_get_response($payment_status_url, $payment_response, $authetication['token'], $authetication['clientId']);

        if ($response) {
            return $payment_response;
        }

        return false;
    }

    /**
     * SIBS Back Office Operation.
     *
     * @param string $reference_id
     * @param array $parameters
     * @param string $order_id
     * @return string
     */
    public static function sibs_back_office_operation($reference_id, $parameters, $order_id)
    {
        sibsLogger::debug('Entrou em sibs_back_office_operation', sibsConstants::SIBS_LOG);
        $environment_file = sibsFunctions::get_environment();

        $back_office_url = self::sibs_get_spg_back_office_url($parameters, $reference_id, $parameters['server_mode'], $environment_file['back_office_endpoints']);
        $post_data       = self::sibs_set_spg_back_office_parameters($parameters, $reference_id, $order_id);
        $authetication   = self::getToken();

        $response_data = self::sibs_get_response_data($back_office_url, $post_data, $parameters['server_mode'], $authetication['token'], $authetication['clientId']);

        return $response_data;
    }

    /**
     * SIBS Update Status.
     *
     * @param string $reference_id
     * @param array $status_parameters
     * @return string|false
     */
    public static function sibs_update_status($reference_id, $status_parameters)
    {
        sibsLogger::debug('Entrou em sibs_update_status', sibsConstants::SIBS_LOG);
        $environment_file      = sibsFunctions::get_environment();
        $back_office_endpoints = $environment_file['back_office_endpoints'];

        $status_url  = self::sibs_get_back_office_url($status_parameters['server_mode'], $reference_id, $back_office_endpoints);
        $status_url .= '?' . http_build_query(self::sibs_get_payment_credential($status_parameters), '', '&');

        $authetication = self::getToken();

        return self::sibs_get_payment_response($status_url, $authetication['token'], $authetication['clientId']);
    }

    /**
     * SIBS Get Transaction Result.
     *
     * @param bool $return_code
     * @return string
     */
    public static function sibs_get_transaction_result($return_code = false)
    {
        sibsLogger::debug('Entrou em sibs_get_transaction_result', sibsConstants::SIBS_LOG);
        sibsLogger::debug("return_code: $return_code", sibsConstants::SIBS_LOG);

        if ($return_code === false) {
            sibsLogger::debug('transaction_result: ' . sibsConstants::SIBS_NOK, sibsConstants::SIBS_LOG);

            return sibsConstants::SIBS_NOK;
        }

        foreach (self::$ack_patterns as $pattern) {
            if (preg_match($pattern, $return_code)) {
                sibsLogger::debug('transaction_result: ' . sibsConstants::SIBS_ACK, sibsConstants::SIBS_LOG);

                return sibsConstants::SIBS_ACK;
            }
        }

        sibsLogger::debug('transaction_result: ' . sibsConstants::SIBS_NOK, sibsConstants::SIBS_LOG);

        return sibsConstants::SIBS_NOK;
    }
}
