<?php

namespace Wpo\Core;

use Wpo\Core\Extensions_Helpers;
use Wpo\Services\Log_Service;
use Wpo\Services\Options_Service;

// Prevent public access to this script
defined( 'ABSPATH' ) || die();

if ( ! class_exists( '\Wpo\Core\Plugin_Helpers' ) ) {

	class Plugin_Helpers {

		/**
		 * Helper to check if a premium WPO365 plugin edition is active.
		 */
		public static function is_premium_edition_active( $slug = null ) {
			Log_Service::write_log( 'WARN', sprintf( '%s -> Method is deprecated - Please update all your WPO365 plugins to version 27.0 or later', __METHOD__ ) );

			if ( empty( $slug ) ) {
				$extensions = Extensions_Helpers::get_active_extensions();
				return count( $extensions ) > 0;
			}

			if ( function_exists( 'is_plugin_active' ) === false ) {
				require_once ABSPATH . 'wp-admin/includes/plugin.php';
			}

			if ( is_multisite() ) {

				if ( is_plugin_active_for_network( $plugin_file ) ) {
					return true;
				}

				$sites = get_sites( array( 'fields' => 'ids' ) );

				foreach ( $sites as $site_id ) {
					switch_to_blog( $site_id );
					$active = is_plugin_active( $plugin_file );
					restore_current_blog();

					if ( $active ) {
						return true;
					}
				}

				return false;
			}

			return \is_plugin_active( $slug );
		}

		/**
		 * WPMU aware wp filter extension to show the action link on the plugins page. Will add
		 * the wpo365 configuration action link depending on the WPMU configuration
		 *
		 * @since 7.3
		 *
		 * @param array $links The current action link collection.
		 *
		 * @return array The new action link collection
		 */
		public static function get_configuration_action_link( $links ) {
			// Don't show the configuration link for subsite admin if subsite options shouldn't be used
			if ( is_multisite() && ! is_network_admin() && Options_Service::mu_use_subsite_options() === false ) {
				return $links;
			}

			$wizard_link = '<a href="admin.php?page=wpo365-wizard">' . __( 'Configuration', 'wpo365-login' ) . '</a>';
			array_push( $links, $wizard_link );

			return $links;
		}

		/**
		 * Iterates all installed WPO365 premium extensions and checks for updates.
		 *
		 * @since 32.0
		 *
		 * @param object|null $check_for_updates_data
		 * @return object
		 */
		public static function check_for_updates( $check_for_updates_data ) {

			if ( $check_for_updates_data === null || ! isset( $check_for_updates_data->response ) ) {
				return $check_for_updates_data;
			}

			$installed_plugins = Extensions_Helpers::get_extensions();

			if ( empty( $installed_plugins ) ) {
				return $check_for_updates_data;
			}

			$updates = self::get_plugin_update_info( $installed_plugins );

			foreach ( $updates as $filename => $plugin_update_info ) {
				$current_version = $installed_plugins[ $filename ]['version'];

				if (
					! empty( $plugin_update_info->new_version )
					&& version_compare( $plugin_update_info->new_version, $current_version, '>' )
				) {
					$check_for_updates_data->response[ $filename ] = $plugin_update_info;
				} else {
					$check_for_updates_data->no_update[ $filename ] = $plugin_update_info;
				}
			}

			return $check_for_updates_data;
		}

		public static function check_licenses( $reset = true ) {
			Wpmu_Helpers::mu_delete_transient( 'wpo365_lic_notices' );
			$extensions = Extensions_Helpers::get_active_extensions( $reset, 'network' );

			foreach ( $extensions as $slug => $extension ) {
				list($license_key, $url) = self::get_plugin_license_key( $extension );
				self::check_license( $extension, $license_key, $url );
			}
		}

		public static function show_license_notices() {
			// Get all license related admin notices
			$lic_notices = Wpmu_Helpers::mu_get_transient( 'wpo365_lic_notices' );

			if ( \is_array( $lic_notices ) ) {

				foreach ( $lic_notices as $lic_notice ) {
					add_action(
						'admin_notices',
						function () use ( $lic_notice ) {
							printf( '<div class="notice notice-error" style="margin-left: 2px;"><p>%s</p></div>', wp_kses( $lic_notice, WordPress_Helpers::get_allowed_html() ) );
						},
						10,
						0
					);
					add_action(
						'network_admin_notices',
						function () use ( $lic_notice ) {
							printf( '<div class="notice notice-error" style="margin-left: 2px;"><p>%s</p></div>', wp_kses( $lic_notice, WordPress_Helpers::get_allowed_html() ) );
						},
						10,
						0
					);
				}
			}
		}

		/**
		 * Hooks in to the plugins API to view details of available plugin updates.
		 *
		 * @since 32.0
		 *
		 * @param object|false $res
		 * @param string       $action
		 * @param object       $args
		 * @return object|false
		 */
		public static function plugin_info( $res, $action, $args ) {
			// Nothing to do
			if ( $action !== 'plugin_information' ) {
				return $res;
			}

			// Check the cache.
			$cache_key = 'wpo365_plugins_updated';
			$data      = get_site_transient( $cache_key );

			// No cached updates found
			if ( ! isset( $data['plugins'] ) || ! is_array( $data['plugins'] ) ) {
				return $res;
			}

			// Prepare the plugin info if found
			foreach ( $data['plugins'] as $filename => $plugin_info ) {
				$slug = sprintf( '%s/', $args->slug );

				if ( WordPress_Helpers::stripos( $filename, $slug ) !== false ) {
					return $plugin_info;
				}
			}

			return $res;
		}

		/**
		 * Shows a compatibility warning for older versions of premium plugins.
		 *
		 * @since 32.0
		 *
		 * @param array  $plugin_meta
		 * @param string $file_name
		 * @return array
		 */
		public static function show_old_version_warning( $plugin_meta, $file_name ) {
			if ( WordPress_Helpers::stripos( $file_name, 'wpo365' ) !== false ) {
				$non_premium_plugin_folders = array(
					'wpo365-login/',
					'wpo365-msgraphmailer/',
					'wpo365-samesite/',
					'wpo365-developer/',
				);

				$plugin_folder = explode( '/', $file_name );
				$plugin_folder = $plugin_folder[0] . '/';

				if ( ! in_array( $plugin_folder, $non_premium_plugin_folders, true ) ) {
					$update_plugins = get_site_transient( 'update_plugins' );

					if ( is_object( $update_plugins ) && property_exists( $update_plugins, 'response' ) && isset( $update_plugins->response[ $file_name ] ) ) {
						$plugin_row    = array( '<div style="display: block; color: red; padding: 10px; margin-top: 20px; border: 1px solid; background-color: #ffffff; font-weight: 600;">' );
						$plugin_row[]  = '<div style="display: block; padding-bottom: 5px;"><span class="dashicons dashicons-warning"></span>&nbsp;Compatibility alert</div>';
						$plugin_row[]  = sprintf( '<div style="display: block;"><span style="font-weight: 400; color: #000000;">The currently installed version of this plugin has not been tested with the latest version of %s. To avoid issues, make sure you update your plugins regularly.</span></div></div>', class_exists( '\Wpo\Login' ) ? 'WPO365 | LOGIN' : 'WPO365 | MICROSOFT GRAPH MAILER' );
						$plugin_meta[] = implode( '', $plugin_row );
					}
				}
			}

			return $plugin_meta;
		}

		private static function get_plugin_update_info( $installed_plugins ) {
			foreach ( $installed_plugins as $slug => $plugin_data ) {
				list($license_key)                         = self::get_plugin_license_key( $plugin_data );
				$installed_plugins[ $slug ]['license_key'] = $license_key;
			}

			$hash = md5( wp_json_encode( $installed_plugins ) );

			// Check the cache.
			$cache_key = 'wpo365_plugins_updated';
			$data      = get_site_transient( $cache_key );

			if ( isset( $data['hash'], $data['plugins'] ) && $hash === $data['hash'] ) {
				return $data['plugins'];
			}

			$data = array(
				'hash'    => $hash,
				'plugins' => array(),
			);

			self::check_licenses();

			$plugin_version_infos = self::get_version_from_remote( $installed_plugins );

			if ( is_array( $plugin_version_infos ) ) {

				foreach ( $plugin_version_infos as $filename => $plugin_version_info ) {
					$data['plugins'][ $filename ] = (object) $plugin_version_info;
				}
			}

			set_site_transient( $cache_key, $data, 4 * HOUR_IN_SECONDS );

			return $data['plugins'];
		}

		/**
		 * Prompt WordPress to clean its plugin-updates cache and refresh the cached data for premium WPO365 plugins.
		 *
		 * @since 32.0
		 *
		 * @return void
		 */
		public static function force_check_for_plugin_updates() {
			if (
				! is_user_logged_in()
				|| ! current_user_can( 'delete_users' )
				|| empty( $_POST )
				|| ! check_admin_referer( 'wpo365_force_check_for_plugin_updates', 'wpo365_force_check_for_plugin_updates_nonce' )
			) {
				wp_die( 'Forbidden', '403 Forbidden', array( 'response' => 403 ) );
			}

			// Force a fresh iteration of all WPO365 extensions.

			if ( isset( $_REQUEST['is_network_admin'] ) && $_REQUEST['is_network_admin'] === '1' ) {
				delete_site_option( 'wpo365_active_extensions' );
			} else {
				delete_option( 'wpo365_active_extensions' );
			}

			// Force getting fresh data from the WPO365.com server.
			delete_site_transient( 'wpo365_plugins_updated' );
			wp_clean_plugins_cache( true );

			$goto_after = isset( $_REQUEST['request_url'] ) ? $_REQUEST['request_url'] : ( is_network_admin() ? network_admin_url( 'plugins.php' ) : admin_url( 'plugins.php' ) ); // phpcs:ignore
			wp_safe_redirect( $goto_after );
			die();
		}

		/**
		 * Returns true if license-check is required, otherwise false.
		 *
		 * @since 38.0
		 *
		 * @param string $url
		 * @return bool
		 */
		public static function is_license_required( $url = '' ) {

			if ( empty( $url ) ) {
				$url = is_multisite() ? network_home_url() : home_url();
			}

			$parsed_url = wp_parse_url( $url );

			if ( ! $parsed_url || ! isset( $parsed_url['host'] ) ) {
				return false; // Invalid or incomplete URL.
			}

			$host = strtolower( $parsed_url['host'] );
			$path = isset( $parsed_url['path'] ) ? strtolower( $parsed_url['path'] ) : '';

			// Keywords and TLDs that indicate non-productive environments.
			$non_prod_keywords = array( 'dev', 'test', 'staging', 'stage', 'preprod', 'pre-prod,', 'uat', 'quality', 'qa-' );
			$non_prod_tlds     = array( 'lan' );

			// Check for localhost or loopback.
			if ( $host === 'localhost' || $host === '127.0.0.1' ) {
				return false;
			}

			// Check if host contains any non-productive keywords.
			foreach ( $non_prod_keywords as $keyword ) {

				if ( strpos( $host, $keyword ) !== false ) {
					return false;
				}
			}

			// Check for non-productive TLDs.
			$host_parts = explode( '.', $host );
			$tld        = end( $host_parts );

			if ( in_array( $tld, $non_prod_tlds, true ) ) {
				return false;
			}

			// Check if path contains non-productive indicators.
			foreach ( $non_prod_keywords as $keyword ) {

				if ( strpos( $path, $keyword ) !== false ) {
					return false;
				}
			}

			return true;
		}

		/**
		 * Connects to the EDD SL service endpoint at wpo365.com to get the
		 * plugin update info for the plugin in question.
		 *
		 * @param   array $installed_plugins
		 * @return  false|object    The (EDD) plugin update info from the wpo365.com server; Otherwise false.
		 */
		private static function get_version_from_remote( $installed_plugins ) {

			if ( self::request_recently_failed() ) {
				return false;
			}

			$api_params = array(
				'edd_action' => 'get_version',
				'products'   => array(),
			);

			foreach ( $installed_plugins as $slug => $installed_plugin ) {
				$api_params['products'][ $slug ] = array(
					'license' => isset( $installed_plugin['license_key'] ) ? $installed_plugin['license_key'] : '',
					'item_id' => isset( $installed_plugin['store_item_id'] ) ? $installed_plugin['store_item_id'] : false,
					'url'     => home_url(),
				);
			}

			$request = wp_remote_post(
				$GLOBALS['WPO_CONFIG']['store'],
				array(
					'sslverify' => true,
					'body'      => $api_params,
					'headers'   => array( 'Expect' => '' ),
				)
			);

			if ( is_wp_error( $request ) || ( wp_remote_retrieve_response_code( $request ) !== 200 ) ) {
				$slugs = array_keys( $installed_plugins );
				Log_Service::write_log( 'WARN', sprintf( '%s -> Could not retrieve version info from wpo365.com for the following plugins: %s', __METHOD__, implode( ', ', $slugs ) ) );
				self::log_failed_request();
				return false;
			}

			$plugin_version_infos = json_decode( wp_remote_retrieve_body( $request ) );
			$result               = array();

			foreach ( $plugin_version_infos as $filename => $plugin_version_info ) {

				if ( isset( $plugin_version_info->sections ) ) {
					$plugin_version_info->sections = maybe_unserialize( $plugin_version_info->sections );
				} else {
					return false;
				}

				if ( isset( $plugin_version_info->banners ) ) {
					$plugin_version_info->banners = maybe_unserialize( $plugin_version_info->banners );
				}

				if ( isset( $plugin_version_info->icons ) ) {
					$plugin_version_info->icons = maybe_unserialize( $plugin_version_info->icons );
				}

				if ( ! empty( $plugin_version_info->sections ) ) {

					foreach ( $plugin_version_info->sections as $key => $section ) {
						$plugin_version_info->$key = (array) $section;
					}
				}

				// Correct the wrong slug that EDD is making up out of get_next_post_where
				$plugin_version_info->slug = substr( $filename, 0, WordPress_Helpers::stripos( $filename, '/' ) );

				// This is required for your plugin to support auto-updates in WordPress 5.5.
				$plugin_version_info->plugin = $filename;
				$plugin_version_info->id     = $filename;
				$plugin_version_info->tested = self::get_tested_version( $plugin_version_info );

				$result[ $filename ] = $plugin_version_info;
			}

			return $result;
		}

		/**
		 * Reads the license key for the plugin in question from the site's (network)
		 * options.
		 *
		 * @param   array $plugin_data
		 * @return  array   The license key entered by the admin and the URL
		 */
		private static function get_plugin_license_key( $plugin_data ) {
			$store_item_id    = $plugin_data['store_item_id'];
			$license_key_name = \sprintf( 'license_%d', $store_item_id );
			$license_key      = '';
			$url              = '';
			$network_options  = get_site_option( 'wpo365_options' );

			if ( ! empty( $network_options[ $license_key_name ] ) ) {
				$license_key = $network_options[ $license_key_name ];

				if ( WordPress_Helpers::stripos( $license_key, '|' ) > -1 ) {
					list($license_key, $url) = explode( '|', $license_key );
				}
			}

			return array(
				$license_key,
				$url,
			);
		}

		private static function check_license( $extension, $license_key, $url = '' ) {

			if ( self::request_recently_failed() ) {
				return;
			}

			$lic_url = is_multisite()
				? network_admin_url( 'admin.php?page=wpo365-manage-licenses' )
				: admin_url( 'admin.php?page=wpo365-manage-licenses' );

			$empty_url_arg = empty( $url );

			if ( $empty_url_arg ) {
				$url = is_multisite() ? network_home_url() : home_url();
			} else {
				$_url = is_multisite() ? network_home_url() : home_url();

				// Check if the URL that was previously valid has changed
				if ( strcasecmp( trailingslashit( $url ), trailingslashit( $_url ) ) !== 0 ) {
					$host = wp_parse_url( $_url, PHP_URL_HOST );

					// Ignore the case where the hostname is an IP address
					if ( filter_var( $host, FILTER_VALIDATE_IP ) !== false ) {
						return;
					}
				}
			}

			if ( ! self::is_license_required( $url ) ) {
				Log_Service::write_log(
					'DEBUG',
					sprintf(
						'%s -> Skipping license check for %s using URL %s',
						__METHOD__,
						$extension['store_item'],
						$url
					)
				);
				return;
			}

			Log_Service::write_log(
				'DEBUG',
				sprintf(
					'%s -> Checking license for %s using %s',
					__METHOD__,
					$extension['store_item'],
					$url
				)
			);

			// Generate warning if license was not found
			if ( empty( $license_key ) ) {
				$lic_notices = Wpmu_Helpers::mu_get_transient( 'wpo365_lic_notices' );

				if ( empty( $lic_notices ) ) {
					$lic_notices = array();
				}

				$lic_notices[] = \sprintf(
					'Could not find a license for <strong>%s</strong>. Please go to <a href="%s">WP Admin > WPO365 > Licenses</a> and activate your license or purchase a <a href="%s" target="_blank">new license online</a>. See the <a href="%s" target="_blank">End User License Agreement</a> for details',
					$extension['store_item'],
					$lic_url,
					$extension['store_url'],
					'https://www.wpo365.com/end-user-license-agreement/'
				);

				Wpmu_Helpers::mu_set_transient( 'wpo365_lic_notices', $lic_notices );
				return;
			}

			self::check_license_remotely(
				$extension,
				$license_key,
				$url,
				$empty_url_arg,
				$lic_url
			);
		}

		/**
		 * Will check the license remotely.
		 *
		 * @param mixed $extension The plugin data.
		 * @param mixed $license_key  The license key entered by the user.
		 * @param mixed $url The URL for which the license should be activated.
		 * @param mixed $empty_url_arg No URL was previously paired with the license key and persisted.
		 * @param mixed $lic_url The URL for the WPO365 "Licenses" sub page, where to send the user to activate the license.
		 * @return void
		 */
		private static function check_license_remotely( $extension, $license_key, $url, $empty_url_arg, $lic_url ) {
			// Call the custom API.
			$response = wp_remote_get(
				\sprintf( 'https://www.wpo365.com/?edd_action=check_license&license=%s&item_id=%s&url=%s', $license_key, $extension['store_item_id'], $url ),
				array(
					'timeout'   => 15,
					'sslverify' => false,
				)
			);

			$message = '';

			// make sure the response came back okay
			if ( is_wp_error( $response ) || wp_remote_retrieve_response_code( $response ) !== 200 ) {

				if ( is_wp_error( $response ) ) {
					$message = $response->get_error_message();
				} else {
					$message = sprintf(
						'An unknown error occurred whilst checking your license key for %s. Please check WP Admin > WPO365 > ... > Debug to view the raw request (and optionally send it to support@wpo365.com).',
						$extension['store_item']
					);
				}

				Log_Service::write_log(
					'WARN',
					sprintf(
						'%s -> License key %s for %s is not valid for site with URL %s [raw request: %s]',
						__METHOD__,
						$license_key,
						$extension['store_item_id'],
						$url,
							htmlentities( serialize( $response ) ) // phpcs:ignore
					)
				);

				self::log_failed_request();
			} else {
				$license_data = json_decode( wp_remote_retrieve_body( $response ) );

				switch ( $license_data->license ) {

					case 'valid':
						Log_Service::write_log(
							'DEBUG',
							sprintf(
								'%s -> License key for %s is valid',
								__METHOD__,
								$extension['store_item']
							)
						);

						/**
						 * @since   23.0    Lets cache the URL for which the license check was successful
						 */

						if ( $empty_url_arg ) {
							$license_key_name = \sprintf( 'license_%d', $extension['store_item_id'] );
							$network_options  = get_site_option( 'wpo365_options' );

							if ( ! empty( $network_options[ $license_key_name ] ) ) {
								$network_options[ $license_key_name ] = sprintf( '%s|%s', $license_key, $url );
								update_site_option( 'wpo365_options', $network_options );
								$GLOBALS['WPO_CONFIG']['options'] = array();
							}
						}

						return;

					case 'expired':
						$message = sprintf(
							'Your license key for <strong>%s</strong> expired on %s. Please go to <a href="%s" target="_blank">WP Admin > WPO365 > Licenses</a> and update your license or purchase a <a href="%s" target="_blank">new license online</a>. See the <a href="%s" target="_blank">End User License Agreement</a> for details',
							$extension['store_item'],
							WordPress_Helpers::time_zone_corrected_formatted_date( $license_data->expires ),
							$lic_url,
							$extension['store_url'],
							'https://www.wpo365.com/end-user-license-agreement/'
						);
						break;

					case 'disabled':
						$message = sprintf(
							'Your license key for <strong>%s</strong> has been disabled. Please go to <a href="%s" target="_blank">WP Admin > WPO365 > Licenses</a> and update your license or purchase a <a href="%s" target="_blank">new license online</a>. See the <a href="%s" target="_blank">End User License Agreement</a> for details',
							$extension['store_item'],
							$lic_url,
							$extension['store_url'],
							'https://www.wpo365.com/end-user-license-agreement/'
						);
						break;

					case 'key_mismatch':
					case 'item_name_mismatch':
						$message = sprintf(
							'Your license key for <strong>%s</strong> is not valid for this product. Please go to <a href="%s" target="_blank">WP Admin > WPO365 > Licenses</a> and update your license key or purchase additional <a href="%s" target="_blank">licenses online</a>. See the <a href="%s" target="_blank">End User License Agreement</a> for details',
							$extension['store_item'],
							$lic_url,
							$extension['store_url'],
							'https://www.wpo365.com/end-user-license-agreement/'
						);
						break;

					case 'site_inactive':
						$message = sprintf(
							'Your license key for <strong>%s</strong> is not active for this site. Please go to <a href="%s" target="_blank">WP Admin > WPO365 > Licenses</a> and activate your license or purchase additional <a href="%s" target="_blank">licenses online</a>. See the <a href="%s" target="_blank">End User License Agreement</a> for details',
							$extension['store_item'],
							$lic_url,
							$extension['store_url'],
							'https://www.wpo365.com/end-user-license-agreement/'
						);

						break;

					case 'invalid_item_id':
						$message = sprintf(
							'The item ID <strong>%s</strong> for <strong>%s</strong> is not valid. Please go to <a href="%s" target="_blank">WP Admin > WPO365 > Licenses</a> and update your license key or purchase additional <a href="%s" target="_blank">licenses online</a>. See the <a href="%s" target="_blank">End User License Agreement</a> for details',
							$extension['store_item_id'],
							$extension['store_item'],
							$lic_url,
							$extension['store_url'],
							'https://www.wpo365.com/end-user-license-agreement/'
						);
						break;

					case 'invalid':
						$message = sprintf(
							'Your license key for <strong>%s</strong> is invalid. Please go to <a href="%s" target="_blank">WP Admin > WPO365 > Licenses</a> and update your license or purchase a <a href="%s" target="_blank">new license online</a>. See the <a href="%s" target="_blank">End User License Agreement</a> for details',
							$extension['store_item'],
							$lic_url,
							$extension['store_url'],
							'https://www.wpo365.com/end-user-license-agreement/'
						);
						break;

					default:
						$message = sprintf(
							'An unknown error occurred whilst checking your license key for %s. Please check WP Admin > WPO365 > ... > Debug to view the raw request (and optionally send it to support@wpo365.com).',
							$extension['store_item']
						);
						Log_Service::write_log(
							'WARN',
							sprintf(
								'%s -> License key %s for %s is not valid for site with URL %s [raw request: %s]',
								__METHOD__,
								$license_key,
								$extension['store_item'],
								$url,
							htmlentities( serialize( $response ) ) // phpcs:ignore
							)
						);
						break;
				}
			}

			if ( ! empty( $message ) ) {
				$lic_notices = Wpmu_Helpers::mu_get_transient( 'wpo365_lic_notices' );

				if ( empty( $lic_notices ) ) {
					$lic_notices = array();
				}

				$lic_notices[] = $message;
				Wpmu_Helpers::mu_set_transient( 'wpo365_lic_notices', $lic_notices );

				Compatibility_Helpers::compat_warning(
					sprintf(
						'%s -> License key %s for %s is not valid for site with URL %s [error: %s]',
						__METHOD__,
						$license_key,
						$extension['store_item_id'],
						$url,
						$message
					)
				);
			}
		}

		/**
		 * Logs a failed HTTP request for this API URL.
		 * We set a timestamp for 1 hour from now. This prevents future API requests from being
		 * made to this domain for 1 hour. Once the timestamp is in the past, API requests
		 * will be allowed again. This way if the site is down for some reason we don't bombard
		 * it with failed API requests.
		 *
		 * @since
		 */
		private static function log_failed_request() {
			$failed_request_cache_key = 'wpo365_failed_http_' . md5( $GLOBALS['WPO_CONFIG']['store'] );
			update_option( $failed_request_cache_key, strtotime( '+1 hour' ) );
		}

		/**
		 * Determines if a request has recently failed.
		 *
		 * @since 1.9.1
		 *
		 * @return bool
		 */
		private static function request_recently_failed() {
			$failed_request_cache_key = 'wpo365_failed_http_' . md5( $GLOBALS['WPO_CONFIG']['store'] );
			$failed_request_details   = get_option( $failed_request_cache_key );

			// Request has never failed.
			if ( empty( $failed_request_details ) || ! is_numeric( $failed_request_details ) ) {
				return false;
			}

			/*
			* Request previously failed, but the timeout has expired.
			* This means we're allowed to try again.
			*/
			if ( time() > $failed_request_details ) {
				delete_option( $failed_request_cache_key );
				return false;
			}

			return true;
		}

		/**
		 * Gets the plugin's tested version.
		 *
		 * @param object $version_info
		 * @return null|string
		 */
		private static function get_tested_version( $version_info ) {
			// There is no tested version.
			if ( empty( $version_info->tested ) ) {
				return null;
			}

			// Strip off extra version data so the result is x.y or x.y.z.
			list($current_wp_version) = explode( '-', get_bloginfo( 'version' ) );

			// The tested version is greater than or equal to the current WP version, no need to do anything.
			if ( version_compare( $version_info->tested, $current_wp_version, '>=' ) ) {
				return $version_info->tested;
			}
			$current_version_parts = explode( '.', $current_wp_version );
			$tested_parts          = explode( '.', $version_info->tested );

			// The current WordPress version is x.y.z, so update the tested version to match it.
			if ( isset( $current_version_parts[2] ) && $current_version_parts[0] === $tested_parts[0] && $current_version_parts[1] === $tested_parts[1] ) {
				$tested_parts[2] = $current_version_parts[2];
			}

			return implode( '.', $tested_parts );
		}
	}
}
