<?php
/**
 * Class AP_Callback_Controller file.
 *
 * @package Addonpayments
 */

use ComerciaGlobalPayments\AddonPayments\SDK\Response\OperationInterface;
use WooCommerce\Plugin\AddonPayments\Entities\Transaction;

defined( 'ABSPATH' ) || exit;

/**
 * Callback Controller
 */
class AP_Callback_Controller {

	/**
	 * Addonpayments Gateway.
	 *
	 * @var \WC_Gateway_EasyPaymentGateway
	 */
	private $gateway;

	/**
	 * Consructor.
	 *
	 * @param \WC_Payment_Gateway $gateway Addonpayments Gateway.
	 */
	public function __construct( WC_Payment_Gateway $gateway ) {
		$this->gateway = $gateway;
	}

	/**
	 * Control callback response.
	 *
	 * @param string $merchant_trx_id Merchant transaction id.
	 * @param int    $status AddonPayments status code.
	 * @param int    $from payment form origin.
	 * @param int    $order_id Woocommerce Order id.
	 *
	 * @return void
	 */
	public function __invoke( $merchant_trx_id, $status, $from, $order_id ) {

		if ( WC_Gateway_EasyPaymentGateway::PAYMENT_STATUS_UNKNOWN === $status ||
			WC_Gateway_EasyPaymentGateway::PAYMENT_STATUS_FAILED === $status ||
			WC_Gateway_EasyPaymentGateway::PAYMENT_STATUS_CANCELLED === $status
		) {
			$status_name = $this->get_status_name( $status );
			$transaction = $this->get_transaction( $merchant_trx_id, $status_name );
		}

		if ( ! empty( $transaction ) && WC_Gateway_EasyPaymentGateway::PAYMENT_STATUS_UNKNOWN === $status ) {
			$status = $this->get_status_code( $transaction->status );
		}

		$message = __( 'The payment failed, please try again.', 'addonpayments' );

		if ( ! empty( $transaction ) && OperationInterface::STATUS_ERROR3DS !== $transaction->status ) {
			$message = $this->gateway->map_error_message( $transaction->message );
			$message = ! empty( $message ) ? $message : $transaction->message;

		} elseif ( WC_Gateway_EasyPaymentGateway::PAYMENT_STATUS_CANCELLED === $status ) {
			$message = __(
				'You have cancelled the payment. The order could not be completed.',
				'addonpayments'
			);
		}

		if ( WC_Gateway_EasyPaymentGateway::PAYMENT_STATUS_SUCCESS !== $status ) {
			wc_add_notice( $message, 'error' );
		}

		if ( WC_Gateway_EasyPaymentGateway::PAYMENT_STATUS_SUCCESS === $status ) {
			do_action( 'woocommerce_payment_complete', $order_id );
		}

		$callback = $this->get_callback( $from, $status, $order_id );

		wp_safe_redirect( $callback );

		exit;
	}

	/**
	 * Try to get last transaction status by merchant transaction ID.
	 *
	 * @param string        $merchant_trx_id Merchant transaction id.
	 * @param string | null $status EPG transaction status.
	 *
	 * @return false|mixed
	 */
	public function get_transaction( $merchant_trx_id, $status ) {
		$counter  = 0;
		$continue = true;

		do {
			$transactions = Transaction::getByMerchTransactionId( $merchant_trx_id, $status );
			$transaction  = reset( $transactions );

			$final_status = array(
				OperationInterface::STATUS_SUCCESS,
				OperationInterface::STATUS_ERROR,
				OperationInterface::STATUS_CANCELLED,
				OperationInterface::STATUS_FAIL,
				OperationInterface::STATUS_REJECTED,
				OperationInterface::STATUS_PENDING_CONFIRMATION,
			);

			if ( in_array( $transaction->status, $final_status, true ) || empty( $transaction ) ) {
				$continue = false;
			}

			$counter ++;
			if ( $continue ) {
				sleep( 1 );
			}
		} while ( $continue && $counter < 5 );

		return $transaction;
	}

	/**
	 * Return status code.
	 *
	 * @param string $status EPG transaction status.
	 *
	 * @return int
	 */
	public function get_status_code( string $status ): int {
		$status_array = array(
			OperationInterface::STATUS_SUCCESS         => WC_Gateway_EasyPaymentGateway::PAYMENT_STATUS_SUCCESS,
			OperationInterface::STATUS_ERROR           => WC_Gateway_EasyPaymentGateway::PAYMENT_STATUS_FAILED,
			OperationInterface::STATUS_FAIL            => WC_Gateway_EasyPaymentGateway::PAYMENT_STATUS_FAILED,
			OperationInterface::STATUS_CANCELLED       => WC_Gateway_EasyPaymentGateway::PAYMENT_STATUS_CANCELLED,
			OperationInterface::STATUS_REDIRECTED      => WC_Gateway_EasyPaymentGateway::PAYMENT_STATUS_CANCELLED,
			OperationInterface::STATUS_AWAITING_PAYSOL => WC_Gateway_EasyPaymentGateway::PAYMENT_STATUS_SUCCESS,
			OperationInterface::STATUS_REJECTED        => WC_Gateway_EasyPaymentGateway::PAYMENT_STATUS_FAILED,
			OperationInterface::STATUS_PENDING_CONFIRMATION => WC_Gateway_EasyPaymentGateway::PAYMENT_STATUS_SUCCESS,
		);

		return $status_array[ $status ];
	}

	/**
	 * Return status name
	 *
	 * @param int $status_code Status from epg callback.
	 *
	 * @return string|array
	 */
	private function get_status_name( int $status_code ) {
		$status = null;

		$status_array = array(
			WC_Gateway_EasyPaymentGateway::PAYMENT_STATUS_SUCCESS   => OperationInterface::STATUS_SUCCESS,
			WC_Gateway_EasyPaymentGateway::PAYMENT_STATUS_FAILED    => array(
				OperationInterface::STATUS_ERROR,
				OperationInterface::STATUS_FAIL,
				OperationInterface::STATUS_ERROR3DS,
			),
			WC_Gateway_EasyPaymentGateway::PAYMENT_STATUS_CANCELLED => OperationInterface::STATUS_CANCELLED,
		);

		if ( isset( $status_array[ $status_code ] ) ) {
			$status = $status_array[ $status_code ];
		}

		return $status;
	}

	/**
	 * Return payment callback url
	 *
	 * @param int $from Payment form: 1-checkout, 2-order-pay.
	 * @param int $status Transaction status.
	 * @param int $order_id Order ID.
	 *
	 * @return string
	 */
	public function get_callback( int $from, int $status, int $order_id ): string {

		if ( WC_Gateway_EasyPaymentGateway::PAYMENT_STATUS_SUCCESS === $status ) {
			return $this->gateway->settings['success_url'] ? $this->gateway->settings['success_url'] : wc_get_endpoint_url( 'order-received', '', wc_get_checkout_url() );
		}

		if ( WC_Gateway_EasyPaymentGateway::PAYMENT_STATUS_CANCELLED === $status && ! empty( $this->gateway->settings['cancel_url'] ) ) {
			return $this->gateway->settings['cancel_url'];
		}

		if ( WC_Gateway_EasyPaymentGateway::PAYMENT_STATUS_FAILED === $status && ! empty( $this->gateway->settings['failure_url'] ) ) {
			return $this->gateway->settings['failure_url'];
		}

		if ( ( WC_Gateway_EasyPaymentGateway::PAYMENT_STATUS_FAILED === $status
			|| WC_Gateway_EasyPaymentGateway::PAYMENT_STATUS_CANCELLED === $status )
			&& 2 === $from ) {

			$order = new WC_Order( $order_id );
			return $order->get_checkout_payment_url();
		}

		return wc_get_checkout_url();
	}
}
