<?php
/**
 * Plugin Name: Verifone eCommerce for WooCommerce
 * Plugin URI: https://www.verifonewebpay.fi/kayttoonotto/
 * Description: Verifone eCommerce offers secure, flexible, and easy-to-use payment methods for WooCommerce, supporting businesses in local and global markets.
 * Author: Verifone
 * Author URI: https://www.verifonewebpay.fi/
 * Requires Plugins: woocommerce
 * Version: 2.1.3
 * Requires at least: 4.7
 * Tested up to: 6.9
 * WC requires at least: 3.9
 * WC tested up to: 10.4
 * PHP requires at least: 7.0
 * PHP tested up to: 8.1
 * Text Domain: verifone-bluecommerce-for-woocommerce
 * License: GPLv2 or later
 */

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

/**
 * Check if the old gateway plugin is still active.
 * If it is, show a notice to deactivate it and do not load this plugin any further.
 * This is to avoid conflicts with the old plugin as this one is meant for drop-in replacement.
 */
if ( function_exists( 'get_option' ) ) {
	$_wcverifonecheck_plugins = get_option( 'active_plugins', [] );
	foreach ( $_wcverifonecheck_plugins as $_wcverifonecheck_plugin ) {
		// Check plugin file name instead of full path, in case someone has installed it in a different directory.
		if ( strpos( $_wcverifonecheck_plugin, 'woocommerce-gateway-verifone.php' ) === false ) {
			continue;
		}

		$_wcverifonecheck_plugin_path = WP_PLUGIN_DIR . '/' . $_wcverifonecheck_plugin;
		$_wcverifonecheck_plugin_data = get_file_data( $_wcverifonecheck_plugin_path, [
			'name'		 => 'Plugin Name',
			'textdomain' => 'Text Domain',
		] );

		// Check the textdomain as it has changed, to ensure we are not targeting ourselves.
		if ( $_wcverifonecheck_plugin_data['textdomain'] === 'verifone-bluecommerce-for-woocommerce' ) {
			continue;
		}

		add_action('admin_notices', function() use ( $_wcverifonecheck_plugin_data ) {
			/* translators: %1$s is the plugin name, %2$s is the closing b tag */
			$message = wp_sprintf( esc_html__( '%1$s -plugin is still active.%2$s Please deactivate this old version in order to take advantage of the features and fixes in the new plugin.', 'verifone-bluecommerce-for-woocommerce' ), '<b>' . $_wcverifonecheck_plugin_data['name'], '</b>' );
			$message .= '<br>' . esc_html__( 'New plugin is called "Verifone eCommerce for WooCommerce". It keeps all your old settings while bringing a number of improvements.', 'verifone-bluecommerce-for-woocommerce' );
			/* translators: %1$s is the link to plugins page, %2$s is the closing link tag */
			$message .= '<br>' . wp_sprintf( esc_html__( '%1$s Go to plugins page &rarr;%2$s', 'verifone-bluecommerce-for-woocommerce' ), '<a href="' . admin_url( 'plugins.php' ) . '?s=verifone">', '</a>' );
			echo '<div class="notice notice-error"><p>' . wp_kses_post( $message ) . '</p></div>';
		} );

		add_action( "after_plugin_row_{$_wcverifonecheck_plugin}", function() {
			$message = esc_html__( 'Deactivate this old version in order to take advantage of the features and fixes in new "Verifone eCommerce for WooCommerce" plugin.', 'verifone-bluecommerce-for-woocommerce' );
			echo '<tr class="plugin-update-tr active" style="position:relative;top:-1px"><td colspan="4" class="plugin-update colspanchange"><div class="notice inline notice-error notice-alt"><p>' . wp_kses_post( $message ) . '</p></div></td></tr>';
		} );

		// Declare blocks and HPOS support to avoid "not declared" warnings in admin
		add_action( 'before_woocommerce_init', function() {
			if ( class_exists( \Automattic\WooCommerce\Utilities\FeaturesUtil::class ) ) {
				\Automattic\WooCommerce\Utilities\FeaturesUtil::declare_compatibility( 'cart_checkout_blocks', __FILE__, true );
				\Automattic\WooCommerce\Utilities\FeaturesUtil::declare_compatibility( 'custom_order_tables', __FILE__, true );
			}
		} );

		// Prevent loading the plugin any further
		return;
	}
}

/**
 * Required minimums and constants
 */
define('WC_VERIFONE_VERSION', '2.1.3');
define('WC_VERIFONE_MIN_PHP_VER', '5.6.0');
define('WC_VERIFONE_MIN_WC_VER', '3.0.0');
define('WC_VERIFONE_MAIN_FILE', __FILE__);
define('WC_VERIFONE_PLUGIN_URL', untrailingslashit(plugin_dir_url(__FILE__)));
define('WC_VERIFONE_PLUGIN_PATH', untrailingslashit(plugin_dir_path(__FILE__)));
define('WC_VERIFONE_GATEWAY_ID', 'verifone');

if (!class_exists('WC_Verifone')) :
    class WC_Verifone {
        /**
         * @var WC_Verifone $instance Singleton The reference the *Singleton* instance of this class
         */
        private static $instance;

		private static $environmentCheckPassed = false;

        /**
         * @var WC_Logger $log Reference to logging class.
         */
        private static $log;

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

        /**
         * Protected constructor to prevent creating a new instance of the
         * *Singleton* via the `new` operator from outside of this class.
         */
        protected function __construct() {
			require_once(plugin_basename('includes/wc-verifone-notice.php'));
			require_once(plugin_basename('includes/wc-verifone-site-health-status.php'));
			require_once(plugin_basename('includes/wc-verifone-site-health-info.php'));

			// Init the plugin and gateway
			add_action('plugins_loaded', array($this, 'init'));
            add_action('plugins_loaded', array($this, 'upgrade'), 15);

			// Check the environment and configuration, show notices if needed
            add_action('admin_init', array($this, 'checkEnvironment'));
			add_action('admin_init', array($this, 'checkSetupStatus'));

			/**
			 * Render plugin notices.
			 * Clear all notices on login and logout in case there were any left behind by a previous session.
			 * That should not happen, as we are clearing all notices after displaying them. But just in case.
			 */
			add_action('admin_notices', array('WC_Verifone_Notice', 'render'), 15);
			add_action('wp_login', array('WC_Verifone_Notice', 'clearAllNotices') );
			add_action('wp_logout', array('WC_Verifone_Notice', 'clearAllNotices') );
        }

        /**
         * Init the plugin after plugins_loaded so environment variables are set.
         */
        public function init() {
            // Don't hook anything else in the plugin if we're in an incompatible environment
            if (self::getEnvironmentWarning()) {
                return;
            }

            // Init the gateway itself
            $this->initGateways();

			// Generate keys if needed
			$this->maybeGenerateKeys();

            add_filter('plugin_action_links_' . plugin_basename(__FILE__), array($this, 'pluginActionLinks'));

            add_action('admin_enqueue_scripts', array($this, 'adminScripts'));
            add_action('wp_enqueue_scripts', array($this, 'frontendScripts'));

			add_action('wp_ajax_verifone_refresh_payment_methods', array($this, 'refreshPaymentMethodsAjax'));

            add_action('woocommerce_order_actions', [WC_Verifone_Observer::class, 'addCheckOrderPaymentAction']);
            add_action('woocommerce_order_action_verifone_check_order_payment', [WC_Verifone_Observer::class, 'executeCheckOrderPaymentAction']);

            add_filter('woocommerce_get_customer_payment_tokens', array($this, 'woocommerceGetCustomerPaymentTokens'), 10, 3);
            add_action('woocommerce_payment_token_deleted', array($this, 'woocommercePaymentTokenDeleted'), 10, 2);

            add_filter('cron_schedules', array($this, 'manageCustomSchedules'));
            add_action('verifoneCheckPaymentStatusCronAction', array($this, 'checkPaymentStatusCron'));
			add_action('verifoneUpdatePaymentMethodsCronAction', array($this, 'refreshPaymentMethodsCron'));

            if (!wp_get_schedule('verifoneCheckPaymentStatusCronAction')) {
                wp_schedule_event(time(), '15min', 'verifoneCheckPaymentStatusCronAction');
            }

			if (!wp_get_schedule('verifoneUpdatePaymentMethodsCronAction')) {
				wp_schedule_event(time(), 'daily', 'verifoneUpdatePaymentMethodsCronAction');
			}

			add_action('before_woocommerce_init', array($this, 'declareFeatureCompatibility'));
			add_action('woocommerce_blocks_loaded', array($this, 'blocksSupport'));

			add_action('admin_init', [ $this, 'maybe_reset_settings' ]);
        }

        /**
         * Checks the environment for compatibility problems.  Returns a string with the first incompatibility
         * found or false if the environment has no problems.
         */
        public static function getEnvironmentWarning() {
            if (version_compare(phpversion(), WC_VERIFONE_MIN_PHP_VER, '<')) {
                $message =esc_html__('WooCommerce Verifone - The minimum PHP version required for this plugin is %1$s. You are running %2$s.', 'verifone-bluecommerce-for-woocommerce');

                return sprintf($message, WC_VERIFONE_MIN_PHP_VER, phpversion());
            }

            if (!defined('WC_VERSION')) {
                return esc_html__('WooCommerce Verifone requires WooCommerce to be activated to work.', 'verifone-bluecommerce-for-woocommerce');
            }

            if (version_compare(WC_VERSION, WC_VERIFONE_MIN_WC_VER, '<')) {
                $message = esc_html__('WooCommerce Verifone - The minimum WooCommerce version required for this plugin is %1$s. You are running %2$s.', 'verifone-bluecommerce-for-woocommerce');

                return sprintf($message, WC_VERIFONE_MIN_WC_VER, WC_VERSION);
            }

            if (!function_exists('curl_init')) {
                return esc_html__('WooCommerce Verifone - cURL is not installed.', 'verifone-bluecommerce-for-woocommerce');
            }

            return false;
        }

        /**
         * Adds plugin action links
         *
         * @since 1.0.0
         */
        public function pluginActionLinks($links) {
            $pluginLinks = array(
                '<a href="' . WC_Verifone_Urls::getSettingsUrl() . '">' .esc_html__('Settings', 'verifone-bluecommerce-for-woocommerce') . '</a>'
			);

            return array_merge($pluginLinks, $links);
        }

        /**
         * The backup sanity check, in case the plugin is activated in a weird way,
         * or the environment changes after activation. Also handles upgrade routines.
         *
         * @return bool
         */
        public function checkEnvironment() {
            $environmentWarning = self::getEnvironmentWarning();

            if ($environmentWarning && is_plugin_active(plugin_basename(__FILE__))) {
                WC_Verifone_Notice::addError($environmentWarning, false, true);
                return false;
            }

			self::$environmentCheckPassed = true;

            return true;
        }

        /**
         * @return bool
         */
        public function checkSetupStatus() {
			if ( ! self::$environmentCheckPassed ) {
				return false;
			}

			$tests = WC_Verifone_Site_Health_Status::getInstance();
			$test_live_mode_result = $tests->test_is_live_mode();

			$message = '';
			$severity = 'warning';

			if ( 'good' !== $test_live_mode_result['status'] ) {
				$message = $test_live_mode_result['description'];
			} else {
				$test_live_mode_merchant_code_result = $tests->test_live_mode_merchant_code();
				if ( 'good' !== $test_live_mode_merchant_code_result['status'] ) {
					$message = $test_live_mode_merchant_code_result['description'];
				}
			}

			// Add the notice if there's message
			if ( $message ) {
				WC_Verifone_Notice::add( $message, $severity );
			}
        }

        /**
         * Initialize the gateway. Called very early - in the context of the plugins_loaded action
         *
         * @since 1.0.0
         */
        public function initGateways() {
            if (!class_exists('WC_Payment_Gateway')) {
                return;
            }

            require_once(plugin_basename('includes/wc-verifone-settings.php'));

            foreach (glob(WC_VERIFONE_PLUGIN_PATH . '/includes/helpers/*.php') as $file) {
                require_once $file;
            }

            foreach (glob(WC_VERIFONE_PLUGIN_PATH . '/includes/helpers/core/*.php') as $file) {
                require_once $file;
            }

            require_once(plugin_basename('includes/class-wc-gateway-verifone.php'));

            add_filter('woocommerce_payment_gateways', array($this, 'addGateway'));
        }

		public function refreshPaymentMethodsCron() {
			try {
				WC_Verifone_Core_PaymentMethods::refreshAvailablePaymentMethods();
			} catch (Exception $e) {
				self::log('Problem with retrieve payment methods from Verifone. (' . $e->getMessage() . ')');
			}
		}

		public function maybeGenerateKeys() {
			$keys = new WC_Verifone_Keys();

			// Generate keys if they are missing
			$keys_exist_live = $keys->getLivePrivateKey() && $keys->getLivePublicKey();
			if(!$keys_exist_live) {
				$key_generation_live = WC_Verifone_Core_Generator::generateKeys('live');
			}

			// Generate keys if they are missing
			$keys_exist_test = $keys->getTestPrivateKey() && $keys->getTestPublicKey();
			if(!$keys_exist_test) {
				$key_generation_test = WC_Verifone_Core_Generator::generateKeys('test');
			}

			// If generation was not successful, add error notice
			if(isset($key_generation_live) && !$key_generation_live['success']) {
				WC_Verifone_Notice::addError(__('Failed to generate keys that are needed to communicate with Verifone, please refresh the page to try again.', 'verifone-bluecommerce-for-woocommerce'));
			}
		}

        /**
         * Add the gateways to WooCommerce
         *
         * @since 1.0.0
         */
        public function addGateway($methods) {
            $methods[] = 'WC_Gateway_Verifone';
            return $methods;
        }

        public function refreshPaymentMethodsAjax() {
            $success = false;
            $response = null;
            $exceptionMessage = '';

			if ( ! current_user_can( 'manage_woocommerce' ) ) {
				wp_send_json_error( esc_html__( 'You do not have permission to do this.', 'verifone-bluecommerce-for-woocommerce' ) );
				exit;
			}

			$nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '';
			if ( ! wp_verify_nonce( $nonce, 'verifone_admin_nonce' ) ) {
				wp_send_json_error( esc_html__( 'You do not have permission to do this.', 'verifone-bluecommerce-for-woocommerce' ) );
				exit;
			}

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

            if ($success) {
				$payment_methods = WC_Verifone_System::getPaymentMethodsOptions();
				unset($payment_methods['all']); // Remove all in one method from the list as it has it's own setting
				$payment_method_names = array_values($payment_methods);
				$payment_methods_last_update = get_option(WC_Verifone_PaymentMethods::PAYMENT_METHODS_UPDATED_OPTION_KEY, null);
				$payment_methods_last_update_human = $payment_methods_last_update ? wp_date( get_option('date_format') . ' ' . get_option('time_format'), strtotime($payment_methods_last_update) ) : null;

                $return = [
                    'code' => 200,
					'response' => $response ? $response : '',
                    'methods' => $payment_method_names ? implode( ', ', $payment_method_names ) : '',
					'last_updated' => $payment_methods_last_update_human,
                    'message' => esc_html__('Payment methods have been refreshed.', 'verifone-bluecommerce-for-woocommerce')
                ];
            } else {
                $return = [
                    'code' => 400,
                    'response' => $response ? $response : '',
                    'message' => esc_html__('Problem with retrieve payment methods. ', 'verifone-bluecommerce-for-woocommerce')
                ];
            }

            wp_send_json($return);
			exit;
        }

        /**
         * Load admin scripts.
         *
         * @since 1.0.0
         */
        public function adminScripts() {
            if ('woocommerce_page_wc-settings' !== get_current_screen()->id) {
                return;
            }

            wp_enqueue_script('woocommerce_verifone_admin', plugins_url('assets/js/verifone-admin.js', WC_VERIFONE_MAIN_FILE), array(), WC_VERIFONE_VERSION, true);
            wp_enqueue_style('verifonepayment-styles', plugins_url('assets/css/verifonepayment-styles.css', WC_VERIFONE_MAIN_FILE), array(), WC_VERIFONE_VERSION);

			wp_localize_script('woocommerce_verifone_admin', 'woocommerceVerifone', [
				'nonce' => wp_create_nonce('verifone_admin_nonce'),
			]);
        }

        public function frontendScripts() {
			$config = WC_Verifone_Config::getInstance();

            wp_enqueue_style('verifonepayment-styles_f', plugins_url('assets/css/verifonepayment-styles_f.css', WC_VERIFONE_MAIN_FILE), array(), WC_VERIFONE_VERSION);
            wp_enqueue_script('woocommerce_verifone_admin', plugins_url('assets/js/verifone.js', WC_VERIFONE_MAIN_FILE), array(), WC_VERIFONE_VERSION, true);
			wp_localize_script('woocommerce_verifone_admin', 'woocommerceVerifone', array(
				'usePaymentMethodLogos' => $config->displayMethodLogos(),
			));
        }

        public function woocommerceGetCustomerPaymentTokens($tokens, $customer_id, $gateway_id) {
            $config = WC_Verifone_Config::getInstance();

            /**
             * @var int $key
             * @var WC_Payment_Token_CC $token
             */
            foreach ($tokens as $key => $token) {
                if ((!$config->isAllowToSaveCC() && $token->get_gateway_id() == WC_VERIFONE_GATEWAY_ID) || get_current_user_id() != $customer_id) {
                    unset($tokens[$key]);
                }
            }
            return $tokens;
        }

        /**
         * Delete token in Verifone Service
         * @param $token_id
         * @param WC_Payment_Token_CC $token
         * @return bool
         * @throws Exception
         */
        public function woocommercePaymentTokenDeleted($token_id, $token) {
            if (WC_VERIFONE_GATEWAY_ID === $token->get_gateway_id()) {
                try {
                    if (WC_Verifone_Core_SavedPaymentMethods::deleteCard($token->get_token())) {
                        return true;
                    } else {
                        return false;
                    }
                } catch (Exception $e) {
                    throw $e;
                }

            }

            return true;
        }

        /**
         * Set as default in Verifone Service
         * @param $token_id
         * @return bool
         */
        public function woocommercePaymentTokenSetDefault($token_id) {
            $token = WC_Payment_Tokens::get($token_id);

            if (WC_VERIFONE_GATEWAY_ID === $token->get_gateway_id()) {
                return true;
            }

            return true;

        }

        public function manageCustomSchedules($schedules) {
            if (!isset($schedules["15min"])) {
                $schedules["15min"] = array(
                    'interval' => 15 * 60,
                    'display' => esc_html__('Once every 15 minutes', 'verifone-bluecommerce-for-woocommerce')
				);
            }

            return $schedules;
        }

        public function checkPaymentStatusCron() {
			$now     = time();
			$from_ts = $now - 2 * HOUR_IN_SECONDS;      // 2 hours ago (oldest allowed)
			$to_ts   = $now - 10 * MINUTE_IN_SECONDS;   // 10 minutes ago (youngest allowed)

			$args = array(
				'payment_method' => WC_VERIFONE_GATEWAY_ID,
				'date_created'   => $from_ts . '...' . $to_ts, // Filter orders between 5 mins and 2 hours old
				'status'         => 'pending',
				'limit'          => 5555,
			);

			$orders = wc_get_orders( $args );

			foreach ( $orders as $order ) {
				WC_Verifone_Observer::executeCheckOrderPaymentAction( $order, true );
			}

			return true;
		}

        public function upgrade() {
			require_once(plugin_basename('includes/wc-verifone-upgrade.php'));
            WC_Verifone_Upgrade::upgrade();
        }

		 /**
		 * Declares compatibility with Woocommerce features.
		 *
		 * List of features:
		 * - cart_checkout_blocks
		 * - custom_order_tables
		 *
		 * @since 1.3.16
		 * @return void
		 */
		function declareFeatureCompatibility() {
			if (!class_exists(\Automattic\WooCommerce\Utilities\FeaturesUtil::class)) {
				return;
			}

			\Automattic\WooCommerce\Utilities\FeaturesUtil::declare_compatibility(
				'cart_checkout_blocks',
				__FILE__,
				true
			);

			\Automattic\WooCommerce\Utilities\FeaturesUtil::declare_compatibility(
				'custom_order_tables',
				__FILE__,
				true
			);
		}

		/**
		 * Add the gateway to WooCommerce Blocks.
		 *
		 * @since 1.3.16
		 * @return void
		 */
		function blocksSupport() {
			if (!class_exists('Automattic\WooCommerce\Blocks\Payments\Integrations\AbstractPaymentMethodType')) {
				return;
			}

			require_once WC_VERIFONE_PLUGIN_PATH . '/includes/wc-verifone-blocks.php';

			add_action(
				'woocommerce_blocks_payment_method_type_registration',
				function (Automattic\WooCommerce\Blocks\Payments\PaymentMethodRegistry $payment_method_registry) {
					$payment_method_registry->register(new Wc_Verifone_Blocks);
				}
			);
		}

		public function maybe_reset_settings() {
			// Check if is a reset
			if ( isset( $_GET['woocommerce_verifone_reset_settings'] ) && ! empty( $_GET['woocommerce_verifone_reset_settings'] ) ) {
				// Verify nonce field
				if ( ! isset( $_GET['woocommerce_verifone_reset_settings'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['woocommerce_verifone_reset_settings'] ) ), 'verifone_wc_reset_settings' ) ) {
					wp_die( esc_html__( 'Cheating, huh?', 'verifone-bluecommerce-for-woocommerce') );
				}

				// Verify that user is logged in
				if ( ! is_user_logged_in() ) {
					wp_die( esc_html__( 'Cheating, huh?', 'verifone-bluecommerce-for-woocommerce') );
				}

				// Verify permissions
				if ( ! current_user_can( 'manage_woocommerce' ) ) {
					wp_die( esc_html__( 'You do not have sufficient permissions to access this page.', 'verifone-bluecommerce-for-woocommerce' ) );
				}

				$config = WC_Verifone_Config::getInstance();

				// Redirect if already empty and no need to reset
				if ( empty( $config->getAll() ) ) {
					wp_safe_redirect( WC_Verifone_Urls::getSettingsUrl() );
					return;
				}

				// Reset settings
				$resetted = true;
				$resetted = $resetted && $config->resetSettings();
				WC_Verifone_Keys::resetAllKeys();
				WC_Verifone_PaymentMethods::resetPaymentMethods();

				// Add notice
				if ( $resetted ) {
					WC_Verifone_Notice::addSuccess( esc_html__( 'Settings reset successfully.', 'verifone-bluecommerce-for-woocommerce' ), false, true );
				} else {
					WC_Verifone_Notice::addError( esc_html__( 'Settings reset failed.', 'verifone-bluecommerce-for-woocommerce' ), false, true );
				}

				// Redirect
				wp_safe_redirect( WC_Verifone_Urls::getSettingsUrl() );
			}
		}

		public static function log($message) {
            if (empty(self::$log)) {
                self::$log = new WC_Logger();
            }

            self::$log->info($message);
        }
    }

	// Init the plugin
    $GLOBALS['wc_verifone'] = WC_Verifone::getInstance();
endif;
