<?php
/**
 * This file handles Payment Gateway Core Action
 *
 * @package WkwcAdyen
 * @version 1.2.0
 */
namespace WkwcAdyen\Helper\Adyen;

defined( 'ABSPATH' ) || exit; // Exit if access directly.

use Adyen\AdyenException;
use Adyen\Client;
use Adyen\Environment;
use Adyen\Service\Checkout;
use Adyen\Service\Modification;
/**
 * Adyen Main Execution class
 */
class Wkwc_Adyen_Helper {

	/**
	 * $test_api_key
	 *
	 * @var string
	 */
	public $test_api_key;

	/**
	 * $test_merchant
	 *
	 * @var string
	 */
	public $test_merchant;

	/**
	 * $test_origin_key
	 *
	 * @var string
	 */
	public $test_origin_key;

	/**
	 * $capture_immediately
	 *
	 * @var string
	 */
	public $capture_immediately;

	/**
	 * $refund_in_adyen
	 *
	 * @var string
	 */
	public $refund_in_adyen;

	/**
	 * $hmac_key
	 *
	 * @var string
	 */
	public $hmac_key;

	/**
	 * $endpoint_url
	 *
	 * @var string
	 */
	public $endpoint_url;

	/**
	 * $adyen_config
	 *
	 * @var Wkwc_Adyen_Config
	 */
	public $adyen_config;

	/**
	 * Whether or not is marked as authorized.
	 *
	 * @var bool|null
	 */
	protected $is_authorized = null;

	/**
	 * Adyen constructor.
	 *
	 * @param Wkwc_Adyen_Config $adyen_config .
	 */
	public function __construct() {
		$this->adyen_config = $this->wkwc_adyen_get_adyen_payment_config();
	}


	/**
	 * Get Payment Config
	 *
	 * @return mixed
	 */
	public function wkwc_adyen_get_adyen_payment_config() {

		$admin_data = $this->wkwc_adyen_get_config();

		$test_mode            = empty( $admin_data['test_mode'] ) ? '' : $admin_data['test_mode'];
		$api_key              = empty( $admin_data['live_api_key'] ) ? '' : $admin_data['live_api_key'];
		$live_merchant        = empty( $admin_data['live_merchant_account'] ) ? '' : $admin_data['live_merchant_account'];
		$origin_key           = empty( $admin_data['live_origin_key'] ) ? '' : $admin_data['live_origin_key'];
		$live_endpoint_prefix = empty( $admin_data['live_endpoint_prefix'] ) ? '' : $admin_data['live_endpoint_prefix'];
		$test_api_key         = empty( $admin_data['test_api_key'] ) ? '' : $admin_data['test_api_key'];
		$test_merchant        = empty( $admin_data['test_merchant'] ) ? '' : $admin_data['test_merchant'];
		$test_origin_key      = empty( $admin_data['test_origin_key'] ) ? '' : $admin_data['test_origin_key'];
		$capture_immediately  = empty( $admin_data['immediate_capturing'] ) ? '' : $admin_data['immediate_capturing'];
		$refund_in_adyen      = empty( $admin_data['refund_enabled'] ) ? '' : $admin_data['refund_enabled'];
		$hmac_key             = empty( $admin_data['hmac_key'] ) ? '' : $admin_data['hmac_key'];

		$merchant = ! empty( $live_merchant ) ? $live_merchant : $test_merchant;

		$this->endpoint_url = 'https://checkout-test.adyen.com/v71';

		if ( ! empty( $live_endpoint_prefix ) ) {
			$this->endpoint_url = $live_endpoint_prefix . '-checkout-live.adyenpayments.com/checkout/v71';
		}

		$settings = array(
			'test_mode'            => $test_mode,
			'api_key'              => $api_key,
			'merchant'             => $merchant,
			'origin_key'           => $origin_key,
			'live_endpoint_prefix' => $live_endpoint_prefix,
			'test_api_key'         => $test_api_key,
			'test_merchant'        => $test_merchant,
			'test_origin_key'      => $test_origin_key,
			'capture_immediately'  => $capture_immediately,
			'refund_in_adyen'      => $refund_in_adyen,
			'hmac_key'             => $hmac_key,
		);

		$adyen_config = new Wkwc_Adyen_Config( $settings );

		return $adyen_config;
	}

	/**
	 * Get original Adyen domain
	 *
	 * @return string
	 */
	public function wkwc_adyen_get_test_domain() {
		return 'adyen.com';
	}



	/**
	 * Get second original Adyen domain
	 *
	 * @return string
	 */
	public function wkwc_adyen_get_live_domain() {
		return 'adyenpayments.com';
	}

	/**
	 * Get All Required Settings.
	 *
	 * @return mixed
	 */
	public function wkwc_adyen_get_config() {

		$option_settings = array(
			'enabled'               => get_option( '_wkwc_adyen_enabled' ),
			'test_mode'             => get_option( '_wkwc_adyen_test_mode_enabled' ),
			'immediate_capturing'   => get_option( '_wkwc_adyen_immediate_capturing_enabled' ),
			'refund_enabled'        => get_option( '_wkwc_adyen_refund_enabled' ),
			'test_api_key'          => get_option( '_wkwc_adyen_test_api_key' ),
			'test_merchant'         => get_option( '_wkwc_adyen_test_merchant_account' ),
			'test_origin_key'       => get_option( '_wkwc_adyen_test_origin_key' ),
			'live_api_key'          => get_option( '_wkwc_adyen_live_api_key' ),
			'live_merchant_account' => get_option( '_wkwc_adyen_live_merchant_account' ),
			'live_origin_key'       => get_option( '_wkwc_adyen_live_origin_key' ),
			'live_origin_key'       => get_option( '_wkwc_adyen_live_origin_key' ),
			'live_endpoint_prefix'  => get_option( '_wkwc_adyen_live_endpoint_prefix' ),
		);

		return $option_settings;
	}

	/**
	 * Apply Curl Operation
	 *
	 * @param string $url action url.
	 * @param array  $data post data.
	 * @param string $method .
	 * @return object| json object request data
	 */
	public function wkwc_adyen_remote_request( $url, $data, $method ) {
		$url = $this->endpoint_url . $url;

		$get_api_key = $this->adyen_config->wkwc_adyen_get_apikey();
		$merchant    = $this->adyen_config->wkwc_adyen_get_merchantcode();

		if ( $get_api_key ) {
			$headers = array(
				'Content-Type: application/json',
				'X-API-key:' . $get_api_key,
				'x-wkwc-domain'              => parse_url( home_url(), PHP_URL_HOST ),
				'x-wkwc-plugin-slug'         => plugin_basename( WKADYEN_FILE ),
				'x-wkwc-plugin-version'      => WKADYEN_VERSION,
				'x-wkwc-adyen-merchant-name' => $merchant,
			);
		}

		$ch = curl_init();
		curl_setopt( $ch, CURLOPT_URL, $url );
		curl_setopt( $ch, CURLOPT_HTTPHEADER, $headers );
		curl_setopt( $ch, CURLOPT_CUSTOMREQUEST, $method );
		curl_setopt( $ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC );
		curl_setopt( $ch, CURLOPT_POSTFIELDS, wp_json_encode( $data ) );
		curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, false );
		curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );

		$response = curl_exec( $ch );
		$response = json_decode( $response, true );

		curl_close( $ch );

		return $response;
	}


	/**
	 * Get Client Info
	 *
	 * @return Client .
	 * @throws AdyenException .
	 */
	public function wkwc_adyen_get_client() {
		$client      = new Client();
		$live_prefix = ( $this->adyen_config->wkwc_adyen_get_live_endpoint_prefix() !== '' ) ? $this->adyen_config->wkwc_adyen_get_live_endpoint_prefix() : null;
		$client->setXApiKey( $this->adyen_config->wkwc_adyen_get_apikey() );
		$client->setEnvironment( $this->adyen_config->wkwc_adyen_get_environment(), $live_prefix );
		$client->setTimeout( 60 );

		return $client;
	}

	/**
	 * Checks whether or not the current env is configured.
	 *
	 * @since 1.0.1
	 * @return boolean
	 */
	public function wkwc_adyen_is_configured() {

		if ( ! $this->wkwc_adyen_is_authorized() ) {
			return false;
		}

		return true;
	}

	/**
	 * Checks whether or not it's marked as authorized.
	 *
	 * @var bool
	 */
	public function wkwc_adyen_is_authorized() {
		if ( is_null( $this->is_authorized ) ) {
			$this->is_authorized = $this->adyen_config->wkwc_adyen_env_flag();
		}

		return apply_filters( WKWC_ADN_PREFIX . '_authorization_is_authorized', $this->is_authorized, $this );
	}

	/**
	 * Returns the information about our plugin and the CMS.
	 *
	 * @return array
	 */
	public function wkwc_adyen_app_info() {
		return array(
			'applicationInfo' => array(
				'merchantApplication' => array(
					'name'    => WKADYEN_NAME,
					'version' => WKADYEN_VERSION,
				),
				'externalPlatform'    => array(
					'name'       => 'WordPress',
					'version'    => get_bloginfo( 'version' ),
					'integrator' => 'WebKul',
				),
			),
		);
	}

	/**
	 * Returns the information about our plugin and the CMS.
	 *
	 * @return array
	 */
	public function wkwc_adyen_capture_immediately() {
		if ( $this->adyen_config->wkwc_adyen_is_capture_immediately() ) {
			return array(
				'captureDelayHours' => 0,
			);
		}

		return array();
	}

	/**
	 * Authorized Payment Method
	 *
	 * @param object $order WC_Order.
	 * @param string $redirect_url redirect Link.
	 *
	 * @return mixed
	 *
	 * @throws AdyenException .
	 */
	public function wkwc_adyen_pay_via_link( $order, $redirect_url ) {
		try {
			$service = new Checkout( $this->wkwc_adyen_get_client() );
		} catch ( AdyenException $exception ) {
			wkwc_adn_log( $exception->getMessage() );
			return array();
		}

		$shipping        = $order->get_shipping_methods();
		$name            = $order->get_billing_first_name() . ' ' . $order->get_billing_last_name();
		$billing_address = array(
			'street'            => $order->get_billing_address_1(),
			'postalCode'        => $order->get_billing_postcode(),
			'city'              => $order->get_billing_city(),
			'houseNumberOrName' => $name,
			'stateOrProvince'   => $order->get_billing_state(),
			'country'           => $order->get_billing_country(),
		);

		if ( empty( $shipping ) ) {
			$shipping_address = $billing_address;
		} else {
			$shipping_address = array(
				'postalCode'        => $order->get_shipping_postcode(),
				'city'              => $order->get_shipping_city(),
				'houseNumberOrName' => $name,
				'street'            => $order->get_shipping_address_1(),
				'stateOrProvince'   => $order->get_shipping_state(),
				'country'           => $order->get_shipping_country(),
			);
		}
		$params = array(
			'reference'        => strval( $order->get_id() ),
			'amount'           => array(
				'value'    => $order->get_total() * 100,
				'currency' => get_woocommerce_currency(),
			),
			'returnUrl'        => $redirect_url,
			'merchantAccount'  => $this->adyen_config->wkwc_adyen_get_merchantcode(),
			'countryCode'      => $order->get_shipping_country(),
			'shopperReference' => 'wkcust_ref-' . $order->get_customer_id(),
			'shopperEmail'     => $order->get_billing_email(),
			'shopperLocale'    => $order->get_shipping_country(),
			'billingAddress'   => $billing_address,
			'deliveryAddress'  => $shipping_address,
		);

		if ( $this->adyen_config->wkwc_adyen_is_capture_immediately() ) {
			$params['captureDelayHours'] = 0;
		}

		$params['applicationInfo'] = array(
			'merchantApplication' => array(
				'name'    => WKADYEN_NAME,
				'version' => WKADYEN_VERSION,
			),
			'externalPlatform'    => array(
				'name'       => 'WordPress',
				'version'    => get_bloginfo( 'version' ),
				'integrator' => 'WebKul',
			),
		);

		$result = $service->paymentLinks( $params );

		if ( isset( $result['url'] ) && $result['url'] ) {
			$linkid = $result['id'];
			WC()->session->set( 'adyen_linked_id', trim( $linkid ) );
		}
		return $result;
	}

	/**
	 * Refund Order Amount
	 *
	 * @param object $order Order Data.
	 * @param float  $amount Order Total Amount.
	 * @param string $reason Refund Reason.
	 *
	 * @return bool
	 */
	public function wkwc_adyen_refund( $order, $amount = null, $reason = '' ) {
		$adyen_payment_info = $order->get_meta( '_woocommerce_adyen_payment_data' );
		$refund_amount      = ( is_null( $amount ) ) ? $adyen_payment_info['amount']['value'] : $amount;

		if ( ! isset( $adyen_payment_info['pspReference'] ) ) {
			return false;
		}

		try {
			$service = new Modification( $this->wkwc_adyen_get_client() );
		} catch ( AdyenException $exception ) {
			wkwc_adn_log( $exception->getMessage() );
			return false;
		}

		$params = array(
			'merchantAccount'    => $this->adyen_config->wkwc_adyen_get_merchantcode(),
			'modificationAmount' => array(
				'value'    => intval( ( $refund_amount * 100 ) . '' ),
				'currency' => $adyen_payment_info['amount']['currency'],
			),
			'originalReference'  => $adyen_payment_info['pspReference'],
			'reference'          => $adyen_payment_info['merchantReference'],
		);
		try {
			$result = $service->refund( $params );
		} catch ( AdyenException $exception ) {
			wkwc_adn_log( $exception->getMessage() );
			return false;
		}

		if ( isset( $result['pspReference'] ) ) {
			/* translators: %s: is Refund Reference */
			$order->add_order_note( sprintf( __( 'Payment was refunded via Adyen (PSP Reference: %s)', 'wkwc-adyen' ), $this->wkwc_adyen_get_adyen_transaction_url( $result['pspReference'] ) ) );
			return true;
		}

		return false;
	}

	/**
	 * Get Payment Detail
	 *
	 * @param string $md Payment Schema $md .
	 * @param string $pares payment Reference.
	 * @param string $payment_data Payment data.
	 *
	 * @return bool
	 */
	public function wkwc_adyen_get_payment_details( $md, $pares, $payment_data ) {
		$params = array(
			'paymentData' => $payment_data,
			'details'     => array(
				'MD'    => $md,
				'PaRes' => $pares,
			),
		);

		$service = new Checkout( $this->wkwc_adyen_get_client() );

		return $service->paymentsDetails( $params );
	}

	/**
	 * Get Transaction Url
	 *
	 * @param string $psp_reference payment reference.
	 *
	 * @return string
	 */
	public function wkwc_adyen_get_adyen_transaction_url( $psp_reference ) {
		if ( $this->adyen_config->wkwc_adyen_get_environment() === Environment::TEST ) {
			return sprintf( '<a href="https://ca-test.adyen.com/ca/ca/accounts/showTx.shtml?pspReference=%s&txType=Payment">%s</a>', $psp_reference, $psp_reference );
		}

		return sprintf( '<a href="https://ca-live.adyen.com/ca/ca/accounts/showTx.shtml?pspReference=%s&txType=Payment">%s</a>', $psp_reference, $psp_reference );
	}

	/**
	 * Retrieves the shop domain used for generating origin keys.
	 *
	 * @since 1.2.0 - check if the server port should included or not.
	 * @since 1.0.7
	 * @return string
	 */
	public static function get_origin_domain() {
		$incl_port = get_option( 'incl_server_port', 'yes' );
		$protocol  = isset( $_SERVER['HTTPS'] ) && $_SERVER['HTTPS'] === 'on' ? 'https://' : 'http://';
		$port      = in_array( $_SERVER['SERVER_PORT'], array( '80', '443' ) ) ? '' : ':' . $_SERVER['SERVER_PORT'];
		$domain    = 'yes' === $incl_port ? $protocol . $_SERVER['HTTP_HOST'] . $port : $protocol . $_SERVER['HTTP_HOST'];

		return $domain;
	}

	/**
	 * Retrieves the shopper reference based on the WP user id.
	 *
	 * @since 1.0.6 - generate a unique guest id.
	 * @since 1.0.0
	 * @return string
	 */
	public static function get_shopper_reference() {
		$guest_id = md5( uniqid( time(), true ) );
		$user_id  = is_user_logged_in() ? get_current_user_id() : $guest_id;

		return md5( $user_id . '_' . self::get_origin_domain() );
	}

	/**
	 * Converts an object to an array
	 *
	 * @since 1.0.0
	 * @param object $obj
	 * @return array
	 */
	public static function wkwc_adyen_obj_to_arr( $input ) {
		return json_decode( json_encode( $input ), true );
	}

	/**
	 * Gets the client IP
	 *
	 * @since 1.0.0
	 * @return string
	 */
	public function wkwc_adyen_get_client_ip() {
		$ip = $_SERVER['REMOTE_ADDR'];

		if ( empty( $ip ) ) {
			$ip = $_SERVER['HTTP_CLIENT_IP'];
		}

		if ( empty( $ip ) ) {
			$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
		}

		return $ip;// '2.56.212.0'
	}

	/**
	 * Retrieves amount decimals for the shop currency code.
	 *
	 * @since 1.0.0
	 * @return integer
	 */
	public static function wkwc_adyen_currency_decimal() {
		$three = array( 'BHD', 'IQD', 'JOD', 'KWD', 'LYD', 'OMR', 'TND' );
		$zero  = array( 'CVE', 'DJF', 'GNF', 'IDR', 'JPY', 'KMF', 'KRW', 'PYG', 'RWF', 'UGX', 'VND', 'VUV', 'XAF', 'XOF', 'XPF' );

		if ( in_array( get_woocommerce_currency(), $three ) ) {
			return 3;
		}

		if ( in_array( get_woocommerce_currency(), $zero ) ) {
			return 0;
		}

		return 2;
	}

	/**
	 * Formats a given amount according to required currency decimals.
	 *
	 * @since 1.0.0
	 * @param string $amount
	 * @return integer
	 */
	public static function wkwc_adyen_format_amount( $amount ) {
		return (int) number_format( $amount, self::wkwc_adyen_currency_decimal(), '', '' );
	}

	/**
	 * Gets local language.
	 *
	 * @return string
	 */
	public function wkwc_adyen_get_locale() {
		$language = isset( $_SERVER['HTTP_ACCEPT_LANGUAGE'] ) ? $_SERVER['HTTP_ACCEPT_LANGUAGE'] : '';
		$locale   = array_filter( explode( ',', $language ) );

		if ( ! empty( $locale[0] ) ) {
			return $locale[0];
		}

		return str_replace( '_', '-', get_locale() );// get WP locale
	}

	/**
	 * Get store reference by ID
	 *
	 * @param $store_id
	 * @return string
	 */
	public function get_store_reference_by_id( $store_id ) {

		$store_url = 'https://management-test.adyen.com/v71/' . ltrim( '/stores', '/' );
		$params    = array(
			'pageSize'   => 100,
			'pageNumber' => 1,
		);
		$url       = add_query_arg( $params, $store_url );

		$stores = $this->wkwc_adyen_remote_request( $url, array(), 'GET' );

		if ( ! empty( $stores ) ) {

			foreach ( $stores as $store ) {

				$store_data = self::wkwc_adyen_obj_to_arr( $store );

				if ( $store_id === $store_data['id'] ) {
					return ( $store_data['reference'] ) ? $store_data['reference'] : $store_id;
				}
			}
		}

		return '';
	}

	/**
	 * Get the store for order
	 *
	 * @param \WC_Order $order
	 * @return string
	 */
	public function wkwc_adyen_get_store( $order ) {
		$store          = '';
		$user_country   = '';
		$country_source = get_option( 'country_source', 'billing_country' );

		switch ( $country_source ) {
			case 'billing_country':
				$user_country = $order->get_billing_country();
				break;
			case 'shipping_country':
				$user_country = $order->get_shipping_country();
				break;
		}

		if ( ! empty( $user_country ) ) {

			$stores_mapping = get_option( 'stores_mapping', array() );
			$user_country   = strtoupper( $user_country );

			if ( ! empty( $stores_mapping[ $user_country ] ) ) {
				$store = $this->get_store_reference_by_id( $stores_mapping[ $user_country ] );
			}
		}

		return $store;
	}
}
