<?php
namespace PortalPeople\redsys\models;

use Yii;

class Redsys extends \common\models\DynamicModel
{
    const SANDBOX_URL    = 'https://sis-t.redsys.es:25443/sis/rest/trataPeticionREST';
    const PRODUCTION_URL = 'https://sis.redsys.es/sis/rest/trataPeticionREST';
    const Ds_SignatureVersion = 'HMAC_SHA512_V2';

    // Kept for backwards compatibility; use getSecretKey() at runtime
    /** @deprecated Use getSecretKey() */
    const sandboxUrl    = self::SANDBOX_URL;
    /** @deprecated Use getSecretKey() */
    const productionUrl = self::PRODUCTION_URL;

    /**
     * Return the configured HMAC secret key from params, or empty string if not set.
     */
    public static function getSecretKey(): string
    {
        return Yii::$app->params['redsys']['secret_key'] ?? '';
    }

    public static function localAttributes()
    {
        return [
            "DS_MERCHANT_ORDER" => [
                'rules' => ['string'],
                'label' => '',
                'input' => 'default',
            ],
            "DS_MERCHANT_MERCHANTCODE" => [
                'rules' => ['string'],
                'label' => '',
                'input' => 'default',
            ],
            "DS_MERCHANT_TERMINAL" => [
                'rules' => ['string'],
                'label' => '',
                'input' => 'default',
            ],
            "DS_MERCHANT_CURRENCY" => [
                'rules' => ['string'],
                'label' => '',
                'input' => 'default',
            ],
            "DS_MERCHANT_TRANSACTIONTYPE" => [
                'rules' => ['string'],
                'label' => '',
                'input' => 'default',
            ],
            "DS_MERCHANT_AMOUNT" => [
                'rules' => ['string'],
                'label' => '',
                'input' => 'default',
            ],
            "DS_MERCHANT_IDENTIFIER" => [
                'rules' => ['string'],
                'label' => '',
                'input' => 'default',
            ],
            "DS_MERCHANT_COF_INI" => [
                'rules' => ['string'],
                'label' => '',
                'input' => 'default',
            ],
            "DS_MERCHANT_DIRECTPAYMENT" => [
                'rules' => ['string'],
                'label' => '',
                'input' => 'default',
            ],
            "DS_MERCHANT_EXCEP_SCA" => [
                'rules' => ['string'],
                'label' => '',
                'input' => 'default',
            ],
        ];
    }

    public function getDsSignatureVersion()
    {
        return self::Ds_SignatureVersion;
    }

    public function getDs_MerchantParameters(string $merchantUrl = '', string $urlOk = '', string $urlKo = '')
    {
        $params = Yii::$app->params['redsys'] ?? [];
        return [
            'DS_MERCHANT_ORDER'           => $this->DS_MERCHANT_ORDER,
            'DS_MERCHANT_MERCHANTCODE'    => $this->DS_MERCHANT_MERCHANTCODE,
            'DS_MERCHANT_TERMINAL'        => $this->DS_MERCHANT_TERMINAL,
            'DS_MERCHANT_CURRENCY'        => $this->DS_MERCHANT_CURRENCY,
            'DS_MERCHANT_TRANSACTIONTYPE' => $this->DS_MERCHANT_TRANSACTIONTYPE,
            'DS_MERCHANT_AMOUNT'          => $this->DS_MERCHANT_AMOUNT,
            'DS_MERCHANT_IDENTIFIER'      => $this->DS_MERCHANT_IDENTIFIER,
            'DS_MERCHANT_COF_INI'         => $this->DS_MERCHANT_COF_INI,
            'DS_MERCHANT_DIRECTPAYMENT'   => $this->DS_MERCHANT_DIRECTPAYMENT,
            'DS_MERCHANT_EXCEP_SCA'       => $this->DS_MERCHANT_EXCEP_SCA,
            'DS_MERCHANT_MERCHANTURL'     => $merchantUrl ?: ($params['notification_url'] ?? ''),
            'DS_MERCHANT_URLOK'           => $urlOk      ?: ($params['success_url'] ?? ''),
            'DS_MERCHANT_URLKO'           => $urlKo      ?: ($params['error_url'] ?? ''),
        ];
    }

    public function getDs_Signature()
    {
        $kc     = self::getSecretKey();
        $order  = $this->DS_MERCHANT_ORDER;
        $params = self::base64_url_encode_safe(json_encode($this->getDs_MerchantParameters()));
        return self::createMerchantSignature($kc, $params, $order);
    }

    public function getPayload()
    {
        $kc     = self::getSecretKey();
        $order  = $this->DS_MERCHANT_ORDER;
        $params = self::base64_url_encode_safe(json_encode($this->getDs_MerchantParameters()));
        $signature = self::createMerchantSignature($kc, $params, $order);
        return json_encode([
            'Ds_SignatureVersion'   => $this->getDsSignatureVersion(),
            'Ds_MerchantParameters' => $params,
            'Ds_Signature'          => $signature,
        ]);
    }

    /******  AES Function  ******/
    static function encrypt_AES($data, $key)
    {
        $fixedKey = str_pad(substr($key, 0, 16), 16, "0");
        return base64_encode(openssl_encrypt($data, "aes-128-cbc", $fixedKey, OPENSSL_RAW_DATA, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"));
    }

    static function mac512($data, $key)
    {
        return hash_hmac('sha512', $data, $key, true);
    }

    static function createMerchantSignature($key, $data, $diversifyingFactor)
    {
        // Diversify the key with the order number
        $key = self::encrypt_AES($diversifyingFactor, $key);
        // HMAC-SHA-512 of the Ds_MerchantParameters string
        $res = self::mac512($data, $key);
        return self::base64_url_encode_safe($res);
    }

    static function checkSignatures($sig1, $sig2)
    {
        if (!hash_equals(strtolower($sig1), strtolower($sig2))) {
            throw new \Exception("Integrity failure. The received signature does not match the calculated one.");
        }
    }

    	/******  Base64 Functions  ******/
	static function base64_url_encode($input) {
		return strtr(base64_encode($input), '+/', '-_');
	}

	static function base64_url_decode($input) {
		return base64_decode(strtr($input, '-_', '+/'));
	}

	static function base64_url_encode_safe($input) {
		return str_replace("=", "", strtr(base64_encode($input), '+/', '-_'));
	}

	static function base64_url_decode_safe($input) {
		$str = str_pad($input, strlen($input) + (4 - strlen($input) % 4) % 4, '=', STR_PAD_RIGHT);
		return base64_decode(strtr($str, '-_', '+/'));
	}
}