<?php

if (!defined('ABSPATH')) {
    exit;
}

class WC_Verifone_Site_Health_Status {
	private static $instance;

	/**
	 * Protected constructor to prevent creating a new instance of the
	 * *Singleton* via the `new` operator from outside of this class.
	 */
	protected function __construct() {
		add_filter( 'site_status_tests', array( $this, 'add_site_status_tests' ) );
	}

	/**
	 * Returns the *Singleton* instance of this class.
	 *
	 * @return WC_Verifone_Site_Health Singleton The *Singleton* instance.
	 */
	public static function getInstance() {
		if (null === self::$instance) {
			self::$instance = new self();
		}

		return self::$instance;
    }

	/**
	 * Add our site status/health tests.
	 *
	 * @param array $tests Array of tests.
	 * @return array
	 */
	public function add_site_status_tests( $tests ) {
		$tests['direct']['wc_verifone_is_live_mode'] = [
			'label'	=> esc_html__( 'Verifone eCommerce environment', 'verifone-bluecommerce-for-woocommerce' ),
			'test'	=> [ $this, 'test_is_live_mode' ],
		];

		$tests['direct']['wc_verifone_live_mode_merchant_code'] = [
			'label'	=> esc_html__( 'Verifone eCommerce merchant code', 'verifone-bluecommerce-for-woocommerce' ),
			'test'	=> [ $this, 'test_live_mode_merchant_code' ],
		];

		$tests['direct']['wc_verifone_server_communications'] = [
			'label'	=> esc_html__( 'Verifone eCommerce server communications', 'verifone-bluecommerce-for-woocommerce' ),
			'test'	=> [ $this, 'test_server_communications' ],
		];

		return $tests;
	}

	/**
	 * Test if plugin is configured to be in live mode.
	 *
	 * @return array Test results.
	 */
	public static function test_is_live_mode() {
		$status = [
			'label'       => esc_html__( 'Verifone eCommerce is using test environment', 'verifone-bluecommerce-for-woocommerce' ),
			'status'      => 'recommended',
			'badge'       => [
				'label' => esc_html__( 'Verifone eCommerce', 'verifone-bluecommerce-for-woocommerce' ),
				'color' => 'blue',
			],
			'description' => esc_html__( 'Verifone eCommerce is using test environment. Make sure to switch to production for accepting payments.', 'verifone-bluecommerce-for-woocommerce' ),
			'actions'     => sprintf(
				'<p><a href="%s">%s</a></p>',
				esc_url( WC_Verifone_Urls::getSettingsUrl() ),
				esc_html__( 'Go to settings', 'verifone-bluecommerce-for-woocommerce' )
			),
			'test'        => 'wc_verifone_test_is_live_mode',
		];

		$config = WC_Verifone_Config::getInstance();
		$liveMode = $config->isLiveMode();
		if ( $liveMode ) {
			$status['status'] = 'good';
			$status['label'] = esc_html__( 'Verifone eCommerce is using production environment', 'verifone-bluecommerce-for-woocommerce' );
			$status['description'] = esc_html__( 'Verifone eCommerce is using production environment. You are ready to accept payments.', 'verifone-bluecommerce-for-woocommerce' );
			$status['actions'] = [];
		}

		return $status;
	}

	/**
	 * If in live mode, test that the merchant code is set.
	 *
	 * @return array Test results.
	 */
	public function test_live_mode_merchant_code() {
		$config = WC_Verifone_Config::getInstance();
		$liveMode = $config->isLiveMode();

		if ( ! $liveMode ) {
			return [];
		}

		$status = [
			'label'       => esc_html__( 'Verifone EC ID (merchant code) is not set', 'verifone-bluecommerce-for-woocommerce' ),
			'status'      => 'critical',
			'badge'       => [
				'label' => esc_html__( 'Verifone eCommerce', 'verifone-bluecommerce-for-woocommerce' ),
				'color' => 'blue',
			],
			'description' => esc_html__( 'Verifone eCommerce is using production environment, but the merchant code is not set. Payments will not work.', 'verifone-bluecommerce-for-woocommerce' ),
			'actions'     => sprintf(
				'<p><a href="%s">%s</a></p>',
				esc_url( WC_Verifone_Urls::getSettingsUrl() ),
				esc_html__( 'Go to ssettings', 'verifone-bluecommerce-for-woocommerce' )
			),
			'test'        => 'wc_verifone_test_live_mode_merchant_code',
		];

		$config = WC_Verifone_Config::getInstance();
		$merchantCode = $config->getMerchantAgreement();
		$defaultMerchantCode = $config->getMerchantAgreementDefault();

		if ( $merchantCode && $merchantCode !== $defaultMerchantCode ) {
			$status['status'] = 'good';
			$status['label'] = esc_html__( 'Verifone EC ID (merchant code) is set', 'verifone-bluecommerce-for-woocommerce' );
			$status['description'] = esc_html__( 'Verifone eCommerce using production environment and the merchant code is set. You are ready to accept payments.', 'verifone-bluecommerce-for-woocommerce' );
			$status['actions'] = [];
		}

		return $status;
	}

	/**
	 * Test Verifone server communications.
	 *
	 * @return array Test results.
	 */
	public function test_server_communications() {
		$status = [
			'label'       => esc_html__( 'Can\'t communicate with Verifone servers', 'verifone-bluecommerce-for-woocommerce' ),
			'status'      => 'critical',
			'badge'       => [
				'label' => esc_html__( 'Verifone eCommerce', 'verifone-bluecommerce-for-woocommerce' ),
				'color' => 'blue',
			],
			'description' => esc_html__( 'Your site is unable to communicate with Verifone servers.', 'verifone-bluecommerce-for-woocommerce' ) . ' ' . esc_html__( 'Payments will not work. This might be due to a network issue or missing EC ID (merchant code).', 'verifone-bluecommerce-for-woocommerce' ),
			'actions'     => sprintf(
				'<p><a href="%s">%s</a></p>',
				esc_url( WC_Verifone_Urls::getSettingsUrl() ),
				esc_html__( 'Go to settings', 'verifone-bluecommerce-for-woocommerce' )
			),
			'test'        => 'wc_verifone_test_server_communications',
		];

		// Check if we can communicate with Verifone
		$test_result = $this->server_communications_test();
		$connected = $test_result['connected'] ?? false;
		$extra_debug = $test_result['extra_debug'] ?? '';

		// Change test status if we can communicate
		if ( $connected ) {
			$status['status'] = 'good';
			$status['label'] = esc_html__( 'Can communicate with Verifone', 'verifone-bluecommerce-for-woocommerce' );
			$status['description'] = esc_html__( 'Your site can communicate with Verifone to process payments.', 'verifone-bluecommerce-for-woocommerce' );
			$status['actions'] = [];
		}

		// If can't communicate and is using test environment, change message
		$config = WC_Verifone_Config::getInstance();
		$liveMode = $config->isLiveMode();
		if ( ! $connected && ! $liveMode ) {
			$server_ip = isset( $_SERVER['SERVER_ADDR'] ) ? sanitize_text_field( wp_unslash( $_SERVER['SERVER_ADDR'] ) ) : '';
			if ( file_exists('/.dockerenv') ) {
				$server_ip = ''; // Docker container IP is not the same as host IP so we can't use it.
			}

			$status['description'] .= '<br><br>' . esc_html__( 'You are using test envarionment.', 'verifone-bluecommerce-for-woocommerce' );
			$status['description'] .= ' ' . esc_html__( 'Communication problems might also be due to your site IP address not being allowlisted by Verifone.', 'verifone-bluecommerce-for-woocommerce' );
			$status['description'] .= ' ' . wp_sprintf( esc_html__( 'To use test environment, site IP %s address must be allowlisted by Verifone.', 'verifone-bluecommerce-for-woocommerce' ), $server_ip );
			/** translators: 1: Link to ipinfo.io, 2: closing link tag */
			$status['description'] .= '<br><br>' . wp_sprintf( esc_html__( 'To test and complete payment process, the IP address of the network you are using needs to be allowlisted. Find your IP address with %1$sipinfo.io%2$s.', 'verifone-bluecommerce-for-woocommerce' ), '<a href="https://ipinfo.io/ip">', '</a>' );
			$status['description'] .= '<br><br>' . esc_html__( 'Please contact Verifone support to get your IP addresses allowlisted.', 'verifone-bluecommerce-for-woocommerce' );
		}

		// If can't communicate, add the exception message to the description
		if ( ! $connected && $extra_debug ) {
			/** translators: %s is the exception message from connector */
			$status['description'] .= '<br><br>' . wp_sprintf( esc_html__( 'Debug information: %s', 'verifone-bluecommerce-for-woocommerce' ), esc_html( $extra_debug ) );
		}

		return $status;
	}

	private function server_communications_test() {
		$connected = false;
		$extra_debug = '';
		$transient_key = 'wc_verifone_server_comms_status';

		$config = WC_Verifone_Config::getInstance();
		$options = $config->getAll();
		$transient_key .= '|' . md5( serialize( $options ) );

		// Cache to limit requests made
		$transient = get_transient( $transient_key );
		if ( false !== $transient ) {
			return $transient;
		}

		try {
			$response = WC_Verifone_Core_PaymentMethods::refreshAvailablePaymentMethods();
			if ( is_array( $response ) ) {
				$connected = true;
			}
		} catch ( Exception $e ) {
			$extra_debug = $e->getMessage();
		}

		$return = [
			'connected' => $connected,
			'extra_debug' => $extra_debug,
		];

		// If connection failed, do recheck more often
		$cache_lifetime = $connected ? DAY_IN_SECONDS : HOUR_IN_SECONDS;
		set_transient( $transient_key, $return, $cache_lifetime );

		return $return;
	}
}

WC_Verifone_Site_Health_Status::getInstance();
