<?php
/**
 * Credorax Payments For WooCommerce
 * https://www.credorax.com/
 *
 * @category Credorax
 * @package  WC_Credorax
 * @author   Girit-Interactive (https://www.girit-tech.com/)
 */

  if (! defined('ABSPATH')) {
      exit; // Exit if accessed directly.
  }

/**
 * Credorax Credorax abstract payment response model.
 */
abstract class WC_Credorax_Model_Response_AbstractPayment extends WC_Credorax_Model_AbstractResponse
{
    /**
     * Response handlers.
     */
    const PAYMENT_AUTH_HANDLER = 'payment_auth';
    const PAYMENT_AUTH_TOKENIZATION_HANDLER = 'payment_auth_tokenization';
    const PAYMENT_AUTH_USE_TOKEN_HANDLER = 'payment_auth_use_token';
    const PAYMENT_SALE_HANDLER = 'payment_sale';
    const PAYMENT_SALE_TOKENIZATION_HANDLER = 'payment_sale_tokenization';
    const PAYMENT_SALE_USE_TOKEN_HANDLER = 'payment_sale_use_token';

    /**
     * @var WC_Order
     */
    protected $_order;

    /**
     * @var string
     */
    protected $_transactionId;

    /**
     * @var string
     */
    protected $_cipher;

    /**
     * @var string|null
     */
    protected $_operationCode;

    /**
     * @var string
     */
    protected $_responseId;

    /**
     * @var int
     */
    protected $_responseCode;

    /**
     * @var string
     */
    protected $_responseDescription;

    /**
     * @var string
     */
    protected $_riskScore;

    /**
     * @var int
     */
    protected $_ccNumber;

    /**
     * @var string
     */
    protected $_ccExpMonth;

    /**
     * @var string
     */
    protected $_ccExpYear;

    /**
     * @var string
     */
    protected $_ccOwner;

    /**
     * @var string
     */
    protected $_3dsAcsurl;

    /**
     * @var string
     */
    protected $_3dsCavv;

    /**
     * @var string
     */
    protected $_3dsEci;

    /**
     * @var string
     */
    protected $_3dsStatus;

    /**
     * @var string
     */
    protected $_3dsTrxid;

    /**
     * @var string
     */
    protected $_3dsVersion;

    /**
     * @var string
     */
    protected $_smart3dsResult;

    /**
     * @method __construct
     * @param  array       $curlResponse
     * @param  WC_Order    $order
     */
    public function __construct(
        array $curlResponse,
        WC_Order $order
    ) {
        parent::__construct($curlResponse);
        $this->_order = $order;
    }

    /**
     * @return Dynamic3D
     */
    protected function processResponseData()
    {
        $body = $this->getBody();

        $this->_transactionId = (WC_Credorax_Model_Config::is3dSecureEnabled() && isset($body['3ds_status'])) ? null : $body['z13'];
        $this->_cipher = $body['K'];
        $this->_operationCode = (int)$body['O'];
        $this->_responseId = isset($body['z1']) ? $body['z1'] : null;
        $this->_responseCode = isset($body['z2']) ? (int)$body['z2'] : 0;
        $this->_responseDescription = isset($body['z3']) ? $body['z3'] : null;
        $this->_riskScore = isset($body['z21']) ? $body['z21'] : null;

        //CC info:
        $this->_ccNumber = isset($body['b1']) ? $body['b1'] : null;
        $this->_ccExpMonth = isset($body['b3']) ? $body['b3'] : null;
        $this->_ccExpYear = isset($body['b4']) ? $body['b4'] : null;
        $this->_ccOwner = isset($body['c1']) ? $body['c1'] : null;

        //3D Params:
        $this->_3dsAcsurl = isset($body['3ds_acsurl']) ? $body['3ds_acsurl'] : null;
        $this->_3dsCavv = isset($body['3ds_cavv']) ? $body['3ds_cavv'] : null;
        $this->_3dsEci = isset($body['3ds_eci']) ? $body['3ds_eci'] : null;
        $this->_3dsStatus = isset($body['3ds_status']) ? $body['3ds_status'] : null;
        $this->_3dsTrxid = isset($body['3ds_trxid']) ? $body['3ds_trxid'] : null;
        $this->_3dsVersion = isset($body['3ds_version']) ? $body['3ds_version'] : null;
        $this->_smart3dsResult = isset($body['smart_3ds_result']) ? $body['smart_3ds_result'] : null;

        return $this;
    }

    /**
     * @method is3dSecure
     * @return bool
     */
    public function is3dSecureResponse()
    {
        $body = $this->getBody();
        return (!WC_Credorax_Model_Config::is3dSecureEnabled() || (WC_Credorax_Model_Config::isUsingSmart3d() && isset($body['smart_3ds_result']) && $body['smart_3ds_result'] === '02'))? false : true;
    }

    /**
     * @return string
     */
    public function getResponseType()
    {
        return WC_Credorax_Model_AbstractResponse::RESPONSE_TYPE_PAYMENT;
    }

    /**
     * @return WC_Credorax_Model_AbstractResponse
     * @throws \Exception
     */
    public function process()
    {
        parent::process();

        $this
            ->processResponseData()
            ->updateTransaction();

        return $this;
    }

    /**
     * @return bool
     */
    protected function getErrorReason()
    {
        $body = $this->getBody();
        if (is_array($body)) {
            if (!empty($body['z3'])) {
                return $body['z3'];
            }
            if ($this->is3dSecureResponse() && isset($body['3ds_status']) && in_array($body['3ds_status'], ['N','U'])) {
                return $this->get3dStatusMessage($body['3ds_status']);
            }
        }
        return false;
    }

    /**
     * {@inheritdoc}
     *
     * @return bool
     */
    protected function getRequestStatus()
    {
        if (parent::getRequestStatus() === false) {
            return false;
        }

        $body = $this->getBody();

        if ($this->is3dSecureResponse() && !(isset($body['3ds_status']) && (in_array($body['3ds_status'], ['Y','A']) || (isset($body['3ds_acsurl']) && $body['3ds_acsurl'])))) {
            return false;
        }
        if (isset($body['z2']) && $body['z2'] && (!isset($body['3ds_status']) || !(isset($body['3ds_acsurl']) && $body['3ds_acsurl']))) {
            return false;
        }

        return true;
    }

    /**
     * @return WC_Credorax_Model_AbstractPayment
     * @throws \Exception
     */
    protected function updateTransaction()
    {
        $body = $this->getBody();
        ksort($body);

        $this->_order->add_meta_data(
            WC_Credorax_Gateway::KEY_RAW_TRANSACTION_DETAILS,
            array_merge(
                (array) $this->_order->get_meta(WC_Credorax_Gateway::KEY_RAW_TRANSACTION_DETAILS),
                $body
            ),
            true
        );

        $this->_order->add_meta_data(
            WC_Credorax_Gateway::KEY_CREDORAX_LAST_OPERATION_CODE,
            $this->_operationCode,
            true
        );

        if ($this->_transactionId) {
            $this->_order->add_meta_data(
                WC_Credorax_Gateway::KEY_CREDORAX_TRANSACTION_ID,
                $this->_transactionId,
                true
            );
        }

        if ($this->_responseId) {
            $this->_order->add_meta_data(
                WC_Credorax_Gateway::KEY_CREDORAX_RESPONSE_ID,
                $this->_responseId,
                true
            );
        }

        if ($this->_riskScore) {
            $this->_order->add_meta_data(
                WC_Credorax_Gateway::KEY_CREDORAX_RISK_SCORE,
                $this->_riskScore,
                true
            );
        }

        if ($this->_3dsCavv) {
            $this->_order->add_meta_data(
                WC_Credorax_Gateway::KEY_CREDORAX_3DS_CAVV,
                $this->_3dsCavv,
                true
            );
        }

        if ($this->_3dsEci) {
            $this->_order->add_meta_data(
                WC_Credorax_Gateway::KEY_CREDORAX_3DS_ECI,
                $this->_3dsEci,
                true
            );
        }

        if ($this->_3dsStatus) {
            $this->_order->add_meta_data(
                WC_Credorax_Gateway::KEY_CREDORAX_3DS_STATUS,
                $this->_3dsStatus,
                true
            );
        }

        if ($this->_3dsTrxid) {
            $this->_order->add_meta_data(
                WC_Credorax_Gateway::KEY_CREDORAX_3DS_TRXID,
                $this->_3dsTrxid,
                true
            );
        }

        if ($this->_3dsVersion) {
            $this->_order->add_meta_data(
                WC_Credorax_Gateway::KEY_CREDORAX_3DS_VERSION,
                $this->_3dsVersion,
                true
            );
        }

        $this->_order->add_meta_data(WC_Credorax_Gateway::KEY_CC_LAST_4, substr($this->getCcNumber(), -4), true);
        $this->_order->add_meta_data(WC_Credorax_Gateway::KEY_CC_NUMBER, $this->getCcNumber(), true);
        $this->_order->add_meta_data(WC_Credorax_Gateway::KEY_CC_EXP_MONTH, $this->getCcExpMonth(), true);
        $this->_order->add_meta_data(WC_Credorax_Gateway::KEY_CC_EXP_YEAR, $this->getCcExpYear(), true);
        $this->_order->add_meta_data(WC_Credorax_Gateway::KEY_CC_OWNER, $this->getCcOwner(), true);

        return $this;
    }

    /**
     * @return string
     */
    public function getTransactionId()
    {
        return $this->_transactionId;
    }

    /**
     * @return string
     */
    public function getOperationCode()
    {
        return $this->_operationCode;
    }

    /**
     * @return string
     */
    public function getResponseId()
    {
        return $this->_responseId;
    }

    /**
     * @return int
     */
    public function getResponseCode()
    {
        return $this->_responseCode;
    }

    /**
     * @return string
     */
    public function getResponseDescription()
    {
        return $this->_responseDescription;
    }

    /**
     * @return string
     */
    public function getCcNumber()
    {
        return $this->_ccNumber;
    }

    /**
     * @return string
     */
    public function getCcExpMonth()
    {
        return $this->_ccExpMonth;
    }

    /**
     * @return string
     */
    public function getCcExpYear()
    {
        return $this->_ccExpYear;
    }

    /**
     * @return string
     */
    public function getCcOwner()
    {
        return $this->_ccOwner;
    }

    /**
     * @return string
     */
    public function get3dsAcsurl()
    {
        return $this->_3dsAcsurl;
    }

    /**
     * @return string
     */
    public function get3dsCavv()
    {
        return $this->_3dsCavv;
    }

    /**
     * @return string
     */
    public function get3dsEci()
    {
        return $this->_3dsEci;
    }

    /**
     * @return string
     */
    public function get3dsStatus()
    {
        return $this->_3dsStatus;
    }

    /**
     * @return string
     */
    public function get3dsTrxid()
    {
        return $this->_3dsTrxid;
    }

    /**
     * @return string
     */
    public function get3dsVersion()
    {
        return $this->_3dsVersion;
    }

    /**
     * @return bool
     */
    public function is3dsChallengeRequired()
    {
        return WC_Credorax_Model_Config::is3dSecureEnabled() && $this->get3dsAcsurl();
    }

    public function get3dStatusMessage()
    {
        return WC_Credorax_Model_Config::get3dStatusMessage($this->_3dsStatus);
    }
}
