<?php

use Optimole\Sdk\ValueObject\Position;

/**
 * Class Optml_Settings.
 */
class Optml_Settings {
	use Optml_Normalizer;

	const FILTER_EXT = 'extension';
	const FILTER_URL = 'page_url';
	const FILTER_URL_MATCH = 'page_url_match';
	const FILTER_FILENAME = 'filename';
	const FILTER_CLASS = 'class';
	const FILTER_TYPE_LAZYLOAD = 'lazyload';
	const FILTER_TYPE_OPTIMIZE = 'optimize';
	const OPTML_USER_EMAIL = 'optml_user_email';
	const INDIVIDUAL_CACHE_TOKENS_KEY = '_optml_cache_tokens_individual';
	/**
	 * Holds an array of possible settings to alter via wp cli or wp-config constants.
	 *
	 * @var array Whitelisted settings.
	 */
	public static $whitelisted_settings = [
		'image_replacer'       => 'bool',
		'quality'              => 'int',
		'lazyload'             => 'bool',
		'lazyload_placeholder' => 'bool',
		'network_optimization' => 'bool',
		'autoquality'          => 'bool',
		'img_to_video'         => 'bool',
		'resize_smart'         => 'bool',
		'retina_images'        => 'bool',
		'native_lazyload'      => 'bool',
		'video_lazyload'       => 'bool',
		'bg_replacer'          => 'bool',
		'scale'                => 'bool',
		'cdn'                  => 'bool',
	];
	/**
	 * Holds the status of the auto connect hook.
	 *
	 * @var boolean Whether or not the auto connect action is hooked.
	 */
	private static $auto_connect_hooked = false;

	/**
	 * Default settings schema.
	 *
	 * @var array Settings schema.
	 */
	private $default_schema = [
		'api_key'                    => '',
		'service_data'               => '',
		'cache_buster'               => '',
		'cache_buster_assets'        => '',
		'cache_buster_images'        => '',
		'cdn'                        => 'disabled',
		'admin_bar_item'             => 'enabled',
		'lazyload'                   => 'disabled',
		'scale'                      => 'disabled',
		'network_optimization'       => 'enabled',
		'lazyload_placeholder'       => 'enabled',
		'bg_replacer'                => 'enabled',
		'video_lazyload'             => 'enabled',
		'retina_images'              => 'disabled',
		'lazyload_type'              => 'fixed|viewport',
		'limit_dimensions'           => 'enabled',
		'limit_height'               => 4000,
		'limit_width'                => 1920,
		'resize_smart'               => 'disabled',
		'no_script'                  => 'disabled',
		'filters'                    => [],
		'compression_mode'           => 'custom',
		'cloud_sites'                => [ 'all' => 'true' ],
		'watchers'                   => '',
		'quality'                    => 80,
		'wm_id'                      => - 1,
		'wm_opacity'                 => 1,
		'wm_position'                => Position::SOUTH_EAST,
		'wm_x'                       => 0,
		'wm_y'                       => 0,
		'wm_scale'                   => 0,
		'image_replacer'             => 'enabled',
		'img_to_video'               => 'disabled',
		'css_minify'                 => 'enabled',
		'js_minify'                  => 'disabled',
		'avif'                       => 'enabled', // legacy setting, is no longer used in the UI
		'autoquality'                => 'enabled',
		'native_lazyload'            => 'disabled',
		'offload_media'              => 'disabled',
		'transfer_status'            => 'disabled',
		'cloud_images'               => 'enabled',
		'strip_metadata'             => 'enabled',
		'skip_lazyload_images'       => 2,
		'defined_image_sizes'        => [],
		'banner_frontend'            => 'disabled',
		'offloading_status'          => 'disabled',
		'rollback_status'            => 'disabled',
		'best_format'                => 'enabled',
		'offload_limit_reached'      => 'disabled',
		'offload_limit'              => 50000,
		'placeholder_color'          => '',
		'show_offload_finish_notice' => '',
		'show_badge_icon'            => 'disabled',
		'badge_position'             => 'left',
	];
	/**
	 * Option key.
	 *
	 * @var string Option name.
	 */
	private $namespace;
	/**
	 * Holds all options from db.
	 *
	 * @var array All options.
	 */
	private static $options;

	/**
	 * Optml_Settings constructor.
	 */
	public function __construct() {
		$this->default_schema['cloud_sites'] = $this->get_cloud_sites_whitelist_default();

		$this->namespace      = OPTML_NAMESPACE . '_settings';
		$this->default_schema = apply_filters( 'optml_default_settings', $this->default_schema );
		self::$options        = wp_parse_args( get_option( $this->namespace, $this->default_schema ), $this->default_schema );

		if ( defined( 'OPTIML_ENABLED_MU' ) && defined( 'OPTIML_MU_SITE_ID' ) && $this->to_boolean( constant( 'OPTIML_ENABLED_MU' ) ) && constant( 'OPTIML_MU_SITE_ID' ) ) {
			switch_to_blog( constant( 'OPTIML_MU_SITE_ID' ) );
			self::$options = wp_parse_args( get_option( $this->namespace, $this->default_schema ), $this->default_schema );
			restore_current_blog();
		}

		if ( defined( 'OPTIML_USE_ENV' ) && constant( 'OPTIML_USE_ENV' ) && $this->to_boolean( constant( 'OPTIML_USE_ENV' ) ) ) {

			if ( defined( 'OPTIML_API_KEY' )
				&& constant( 'OPTIML_API_KEY' ) !== ''
			) {
				if ( ! $this->is_connected() && ! self::$auto_connect_hooked ) {
					self::$auto_connect_hooked = true;
					add_action(
						'plugins_loaded',
						[ $this, 'auto_connect' ]
					);
				}
			}

			foreach ( self::$whitelisted_settings as $key => $type ) {
				$env_key = 'OPTIML_' . strtoupper( $key );
				if ( defined( $env_key ) && constant( $env_key ) ) {
					$value = constant( $env_key );
					if ( $type === 'bool' && ( (string) $value === '' || ! in_array(
						$value,
						[
							'on',
							'off',
						],
						true
					) ) ) {
						continue;
					}

					if ( $type === 'int' && ( (string) $value === '' || (int) $value > 100 || (int) $value < 0 ) ) {
						continue;
					}
					$sanitized_value       = ( $type === 'bool' ) ? ( $value === 'on' ? 'enabled' : 'disabled' ) : (int) $value;
					self::$options[ $key ] = $sanitized_value;
				}
			}
		}
	}

	/**
	 * Check if the user is connected to Optimole.
	 *
	 * @return bool Connection status.
	 */
	public function is_connected() {
		$service_data = $this->get( 'service_data' );
		if ( ! isset( $service_data['cdn_key'] ) ) {
			return false;
		}
		if ( empty( $service_data ['cdn_key'] ) || empty( $service_data['cdn_secret'] ) ) {
			return false;
		}

		return true;
	}

	/**
	 * Get setting value by key.
	 *
	 * @param string $key Key to search against.
	 *
	 * @return mixed|null Setting value.
	 */
	public function get( $key ) {
		if ( ! $this->is_allowed( $key ) ) {
			return null;
		}

		return isset( self::$options[ $key ] ) ? self::$options[ $key ] : '';
	}

	/**
	 * Check if key is allowed.
	 *
	 * @param string $key Is key allowed or not.
	 *
	 * @return bool Is key allowed or not.
	 */
	private function is_allowed( $key ) {
		return isset( $this->default_schema[ $key ] );
	}

	/**
	 * Auto connect action.
	 */
	public function auto_connect() {

		/**
		 * Connect rest request.
		 *
		 * @var WP_REST_Request<array{api_key: string, application?: string}>
		 */
		$request = new WP_REST_Request( 'POST' );
		$request->set_param( 'api_key', constant( 'OPTIML_API_KEY' ) );
		Optml_Main::instance()->rest->connect( $request );

		remove_action( 'plugins_loaded', [ $this, 'auto_connect' ] );
		self::$auto_connect_hooked = false;
	}

	/**
	 * Process settings.
	 *
	 * @param array $new_settings List of settings.
	 *
	 * @return array
	 */
	public function parse_settings( $new_settings ) {
		$sanitized       = [];
		$sanitized_value = '';

		foreach ( $new_settings as $key => $value ) {
			switch ( $key ) {
				case 'admin_bar_item':
				case 'lazyload':
				case 'scale':
				case 'image_replacer':
				case 'cdn':
				case 'network_optimization':
				case 'lazyload_placeholder':
				case 'retina_images':
				case 'limit_dimensions':
				case 'resize_smart':
				case 'bg_replacer':
				case 'video_lazyload':
				case 'avif':
				case 'offload_media':
				case 'cloud_images':
				case 'autoquality':
				case 'img_to_video':
				case 'css_minify':
				case 'js_minify':
				case 'native_lazyload':
				case 'strip_metadata':
				case 'no_script':
				case 'banner_frontend':
				case 'offloading_status':
				case 'rollback_status':
				case 'best_format':
				case 'offload_limit_reached':
				case 'show_badge_icon':
					$sanitized_value = $this->to_map_values( $value, [ 'enabled', 'disabled' ], 'enabled' );
					break;
				case 'offload_limit':
					$sanitized_value = absint( $value );
					break;
				case 'limit_height':
				case 'limit_width':
					$sanitized_value = $this->to_bound_integer( $value, 100, 5000 );
					break;
				case 'quality':
					if ( 'mauto' !== $value ) {
						$sanitized_value = $this->to_bound_integer( $value, 50, 100 );
					}
					break;
				case 'wm_id':
					$sanitized_value = intval( $value );
					break;
				case 'show_offload_finish_notice':
					$sanitized_value = $this->to_map_values( $value, [ 'offload', 'rollback' ], '' );
					break;
				case 'cache_buster_assets':
				case 'cache_buster_images':
				case 'cache_buster':
					$sanitized_value = is_string( $value ) ? sanitize_text_field( $value ) : '';
					break;
				case 'lazyload_type':
					$sanitized_value = $this->to_map_values( $value, [ 'fixed', 'viewport', 'all', 'fixed|viewport' ], 'fixed' );
					break;
				case 'compression_mode':
					$sanitized_value = $this->to_map_values( $value, [ 'speed_optimized', 'quality_optimized', 'custom' ], 'custom' );
					break;
				case 'cloud_sites':
					$current_sites   = $this->get( 'cloud_sites' );
					$sanitized_value = array_replace_recursive( $current_sites, $value );
					if ( isset( $value['all'] ) && $value['all'] === 'true' ) {
						$sanitized_value = [ 'all' => 'true' ];
					}
					break;
				case 'defined_image_sizes':
					$current_sizes = $this->get( 'defined_image_sizes' );
					foreach ( $value as $size_name => $size_value ) {
						if ( $size_value === 'remove' ) {
							unset( $current_sizes[ $size_name ] );
							unset( $value[ $size_name ] );
						}
					}
					$sanitized_value = array_replace_recursive( $current_sizes, $value );
					break;
				case 'filters':
					$current_filters = $this->get_filters();
					$sanitized_value = array_replace_recursive( $current_filters, $value );
					// Remove falsy vars.
					foreach ( $sanitized_value as $filter_type => $filter_values ) {
						foreach ( $filter_values as $filter_rule_type => $filter_rules_value ) {
							$sanitized_value[ $filter_type ][ $filter_rule_type ] = array_filter(
								$filter_rules_value,
								function ( $value ) {
									return ( $value !== 'false' && $value !== false );
								}
							);
						}
					}
					break;
				case 'watchers':
				case 'placeholder_color':
				case 'transfer_status':
					$sanitized_value = sanitize_text_field( $value );
					break;
				case 'skip_lazyload_images':
					$sanitized_value = $this->to_bound_integer( $value, 0, 100 );
					break;
				case 'wm_opacity':
				case 'wm_scale':
				case 'wm_x':
				case 'wm_y':
					$sanitized_value = floatval( $value );
					break;
				case 'wm_position':
					$sanitized_value = $this->to_map_values(
						$value,
						[
							Position::NORTH,
							Position::NORTH_EAST,
							Position::NORTH_WEST,
							Position::CENTER,
							Position::EAST,
							Position::WEST,
							Position::SOUTH_EAST,
							Position::SOUTH,
							Position::SOUTH_WEST,
						],
						Position::SOUTH_EAST
					);
					break;
				case 'badge_position':
					$sanitized_value = $this->to_map_values( $value, [ 'left', 'right' ], 'right' );
					break;
				default:
					$sanitized_value = '';
					break;

			}

			$sanitized[ $key ] = $sanitized_value;
			$this->update( $key, $sanitized_value );
		}

		return $sanitized;
	}

	/**
	 * Return filter definitions.
	 *
	 * @return mixed|null Filter values.
	 */
	public function get_filters() {

		$filters = $this->get( 'filters' );
		if ( ! isset( $filters[ self::FILTER_TYPE_LAZYLOAD ] ) ) {
			$filters[ self::FILTER_TYPE_LAZYLOAD ] = [];
		}
		if ( ! isset( $filters[ self::FILTER_TYPE_OPTIMIZE ] ) ) {
			$filters[ self::FILTER_TYPE_OPTIMIZE ] = [];
		}
		foreach ( $filters as $filter_key => $filter_rules ) {
			if ( ! isset( $filter_rules[ self::FILTER_EXT ] ) ) {
				$filters[ $filter_key ][ self::FILTER_EXT ] = [];
			}
			if ( ! isset( $filter_rules[ self::FILTER_FILENAME ] ) ) {
				$filters[ $filter_key ][ self::FILTER_FILENAME ] = [];
			}
			if ( ! isset( $filter_rules[ self::FILTER_URL ] ) ) {
				$filters[ $filter_key ][ self::FILTER_URL ] = [];
			}
			if ( ! isset( $filter_rules[ self::FILTER_URL_MATCH ] ) ) {
				$filters[ $filter_key ][ self::FILTER_URL_MATCH ] = [];
			}
			if ( ! isset( $filter_rules[ self::FILTER_CLASS ] ) ) {
				$filters[ $filter_key ][ self::FILTER_CLASS ] = [];
			}
		}

		return $filters;
	}

	/**
	 * Update frontend banner setting from remote.
	 *
	 * @param bool $value Value.
	 *
	 * @return bool
	 */
	public function update_frontend_banner_from_remote( $value ) {
		if ( ! $this->is_main_mu_site() ) {
			return false;
		}

		$opts                    = self::$options;
		$opts['banner_frontend'] = $value ? 'enabled' : 'disabled';

		$update = update_option( $this->namespace, $opts, false );

		if ( $update ) {
			self::$options = $opts;
		}

		return $update;
	}

	/**
	 * Update settings.
	 *
	 * @param string $key Settings key.
	 * @param mixed  $value Settings value.
	 *
	 * @return bool Update result.
	 */
	public function update( $key, $value ) {
		if ( ! $this->is_allowed( $key ) ) {
			return false;
		}

		if ( ! $this->is_main_mu_site() ) {
			return false;
		}
		$opt = self::$options;

		if ( $key === 'banner_frontend' ) {
			$api          = new Optml_Api();
			$service_data = $this->get( 'service_data' );
			$application  = isset( $service_data['cdn_key'] ) ? $service_data['cdn_key'] : '';
			$response     = $api->update_extra_visits( $opt['api_key'], $value, $application );
		}

		$opt[ $key ] = $value;

		$update      = update_option( $this->namespace, $opt, false );

		if ( $update ) {
			self::$options = $opt;
		}
		if ( apply_filters( 'optml_dont_trigger_settings_updated', false ) === false ) {
			/**
			 * Fires when Optimole settings are updated.
			 *
			 * This action is triggered after settings have been successfully updated
			 * and provides an opportunity for other plugins or themes to react to
			 * Optimole configuration changes.
			 */
			do_action( 'optml_settings_updated' );
			static $cleared = false;
			if ( $cleared ) {
				return $update;
			}
			$cleared = true;
			/**
			 * Fires when Optimole cache needs to be cleared after settings update.
			 *
			 * This action is triggered after settings are updated to ensure that
			 * any cached data is refreshed with the new configuration.
			 *
			 * @param bool|string $location Whether to clear the cache globally or just for a particular request.
			 *                              You can pass a string with the URL to clear the cache for a particular URL only.
			 */
			do_action( 'optml_clear_cache', true );
		}
		return $update;
	}

	/**
	 * Check that we're on the main OPTML blog.
	 *
	 * @return bool
	 */
	private function is_main_mu_site() {
		// If we try to update from a website which is not the main OPTML blog, bail.
		if ( defined( 'OPTIML_ENABLED_MU' ) && constant( 'OPTIML_ENABLED_MU' ) && defined( 'OPTIML_MU_SITE_ID' ) && constant( 'OPTIML_MU_SITE_ID' ) &&
			intval( constant( 'OPTIML_MU_SITE_ID' ) ) !== get_current_blog_id()
		) {
			return false;
		}

		return true;
	}

	/**
	 * Return site settings.
	 *
	 * @return array Site settings.
	 */
	public function get_site_settings() {
		$service_data = $this->get( 'service_data' );
		$whitelist    = [];
		if ( isset( $service_data['whitelist'] ) ) {
			$whitelist = $service_data['whitelist'];
		}

		return [
			'quality'                    => $this->get_quality(),
			'admin_bar_item'             => $this->get( 'admin_bar_item' ),
			'lazyload'                   => $this->get( 'lazyload' ),
			'network_optimization'       => $this->get( 'network_optimization' ),
			'retina_images'              => $this->get( 'retina_images' ),
			'limit_dimensions'           => $this->get( 'limit_dimensions' ),
			'limit_height'               => $this->get( 'limit_height' ),
			'limit_width'                => $this->get( 'limit_width' ),
			'lazyload_placeholder'       => $this->get( 'lazyload_placeholder' ),
			'skip_lazyload_images'       => $this->get( 'skip_lazyload_images' ),
			'bg_replacer'                => $this->get( 'bg_replacer' ),
			'video_lazyload'             => $this->get( 'video_lazyload' ),
			'resize_smart'               => $this->get( 'resize_smart' ),
			'no_script'                  => $this->get( 'no_script' ),
			'lazyload_type'              => $this->get( 'lazyload_type' ),
			'compression_mode'           => $this->get( 'compression_mode' ),
			'image_replacer'             => $this->get( 'image_replacer' ),
			'cdn'                        => $this->get( 'cdn' ),
			'filters'                    => $this->get_filters(),
			'cloud_sites'                => $this->get( 'cloud_sites' ),
			'defined_image_sizes'        => $this->get( 'defined_image_sizes' ),
			'watchers'                   => $this->get_watchers(),
			'watermark'                  => $this->get_watermark(),
			'img_to_video'               => $this->get( 'img_to_video' ), // @deprecated
			'scale'                      => $this->get( 'scale' ),
			'css_minify'                 => $this->get( 'css_minify' ),
			'js_minify'                  => $this->get( 'js_minify' ),
			'native_lazyload'            => $this->get( 'native_lazyload' ),
			'avif'                       => $this->get( 'avif' ),
			'autoquality'                => $this->get( 'autoquality' ),
			'offload_media'              => $this->get( 'offload_media' ),
			'cloud_images'               => $this->get( 'cloud_images' ),
			'strip_metadata'             => $this->get( 'strip_metadata' ),
			'whitelist_domains'          => $whitelist,
			'banner_frontend'            => $this->get( 'banner_frontend' ),
			'offloading_status'          => $this->get( 'offloading_status' ),
			'rollback_status'            => $this->get( 'rollback_status' ),
			'best_format'                => $this->get( 'best_format' ),
			'offload_limit_reached'      => $this->get( 'offload_limit_reached' ),
			'placeholder_color'          => $this->get( 'placeholder_color' ),
			'show_offload_finish_notice' => $this->get( 'show_offload_finish_notice' ),
			'show_badge_icon'            => $this->get( 'show_badge_icon' ),
			'badge_position'             => $this->get( 'badge_position' ),
		];
	}

	/**
	 * Return quality factor.
	 *
	 * @return string Quality factor.
	 */
	public function get_quality() {
		$quality = $this->get( 'quality' );
		if ( $this->get( 'autoquality' ) === 'enabled' ) {
			return 'mauto';
		}
		// Legacy compat.
		if ( $quality === 'low' ) {
			return 'high_c';
		}
		if ( $quality === 'medium' ) {
			return 'medium_c';
		}

		if ( $quality === 'high' ) {
			return 'low_c';
		}

		return $quality;
	}

	/**
	 * Return filter definitions.
	 *
	 * @return mixed|null Filter values.
	 */
	public function get_watchers() {

		return $this->get( 'watchers' );
	}

	/**
	 * Return an watermark array.
	 *
	 * @return array
	 */
	public function get_watermark() {
		return [
			'id'       => $this->get( 'wm_id' ),
			'opacity'  => $this->get( 'wm_opacity' ),
			'position' => $this->get( 'wm_position' ),
			'x_offset' => $this->get( 'wm_x' ),
			'y_offset' => $this->get( 'wm_y' ),
			'scale'    => $this->get( 'wm_scale' ),
		];
	}

	/**
	 * Check if smart cropping is enabled.
	 *
	 * @return bool Is smart cropping enabled.
	 */
	public function is_smart_cropping() {
		return $this->get( 'resize_smart' ) === 'enabled';
	}

	/**
	 * Check if best format is enabled.
	 *
	 * @return bool
	 */
	public function is_best_format() {
		return $this->get( 'best_format' ) === 'enabled';
	}

	/**
	 * Check if offload limit was reached.
	 *
	 * @return bool
	 */
	public function is_offload_limit_reached() {
		return $this->get( 'offload_limit_reached' ) === 'enabled';
	}

	/**
	 * Get numeric quality used by the service.
	 *
	 * @return int Numeric quality.
	 */
	public function get_numeric_quality() {
		$value = $this->get_quality();

		return (int) $this->to_accepted_quality( $value );
	}

	/**
	 * Check if replacer is enabled.
	 *
	 * @return bool Replacer enabled
	 */
	public function is_enabled() {
		$status       = $this->get( 'image_replacer' );
		$service_data = $this->get( 'service_data' );
		if ( empty( $service_data ) ) {
			return false;
		}
		if ( isset( $service_data['status'] ) && $service_data['status'] === 'inactive' ) {
			return false;
		}

		return $this->to_boolean( $status );
	}

	/**
	 * Check if lazyload is enabled.
	 *
	 * @return bool Lazyload enabled
	 */
	public function use_lazyload() {
		$status = $this->get( 'lazyload' );

		return $this->to_boolean( $status );
	}

	/**
	 * Check if replacer is enabled.
	 *
	 * @return bool Replacer enabled
	 */
	public function use_cdn() {
		$status = $this->get( 'cdn' );

		return $this->to_boolean( $status );
	}

	/**
	 * Return cdn url.
	 *
	 * @return string CDN url.
	 */
	public function get_cdn_url() {
		$service_data = $this->get( 'service_data' );
		if ( ! isset( $service_data['cdn_key'] ) ) {
			return '';
		}

		if ( defined( 'OPTML_CUSTOM_DOMAIN' ) && constant( 'OPTML_CUSTOM_DOMAIN' ) ) {
			return parse_url( strtolower( OPTML_CUSTOM_DOMAIN ), PHP_URL_HOST );
		}

		if ( isset( $service_data['is_cname_assigned'] ) && $service_data['is_cname_assigned'] === 'yes' && ! empty( $service_data['domain'] ) ) {
			return strtolower( $service_data['domain'] );
		}

		return sprintf(
			'%s.%s',
			strtolower( $service_data['cdn_key'] ),
			Optml_Config::$base_domain
		);
	}

	/**
	 * Reset options to defaults.
	 *
	 * @return bool Reset action status.
	 */
	public function reset() {
		$reset_schema            = $this->default_schema;
		$reset_schema['filters'] = self::$options['filters'];

		$update = update_option( $this->namespace, $reset_schema );
		if ( $update ) {
			self::$options = $reset_schema;
		}
		wp_unschedule_hook( Optml_Admin::SYNC_CRON );
		wp_unschedule_hook( Optml_Admin::ENRICH_CRON );

		return $update;
	}

	/**
	 * Get raw settings value.
	 *
	 * @return  array
	 */
	public function get_raw_settings() {
		return get_option( $this->namespace, false );
	}


	/**
	 * Clear cache.
	 *
	 * @param string $type Cache type.
	 *
	 * @return string|WP_Error
	 */
	public function clear_cache( $type = '' ) {
		$token        = $this->get( 'cache_buster' );
		$token_images = $this->get( 'cache_buster_images' );

		// here is an individual cache tokens
		$individual = get_transient( self::INDIVIDUAL_CACHE_TOKENS_KEY ) ?: [];
		if ( ( empty( $type ) || $type === 'images' ) ) {
			if ( ! empty( $token_images ) ) {
				$token = $token_images;
			}
		} elseif ( $type === 'assets' ) {
			$token = $this->get( 'cache_buster_assets' );
		} else {
			$token = $individual[ crc32( $type ) ] ?? $token_images ?: $token;
		}

		$request = new Optml_Api();
		$data    = $request->get_cache_token( $token, $type );

		if ( $data === false || is_wp_error( $data ) || empty( $data ) || ! isset( $data['token'] ) ) {
			$extra = '';

			if ( is_wp_error( $data ) ) {
				/**
				 * Error from api.
				 *
				 * @var WP_Error $data Error object.
				 */
				$extra = sprintf( /* translators: Error details */ __( '. ERROR details: %s', 'optimole-wp' ), $data->get_error_message() );
			}

			return new WP_Error( 'optimole_cache_buster_error', __( 'Can not get new token from Optimole service', 'optimole-wp' ) . $extra );
		}

		if ( empty( $type ) || $type === 'images' ) {
			set_transient( 'optml_cache_lock', 'yes', 5 * MINUTE_IN_SECONDS );
			$this->update( 'cache_buster_images', $data['token'] );
			// we delete individual cache tokens since this is a global cache clear.
			delete_transient( self::INDIVIDUAL_CACHE_TOKENS_KEY );
		} elseif ( $type === 'assets' ) {
			set_transient( 'optml_cache_lock_assets', 'yes', 5 * MINUTE_IN_SECONDS );
			$this->update( 'cache_buster_assets', $data['token'] );
		} else {
			$individual[ crc32( $type ) ] = $data['token'];
			set_transient( self::INDIVIDUAL_CACHE_TOKENS_KEY, $individual, 6 * HOUR_IN_SECONDS );
		}

		return $data['token'];
	}

	/**
	 * Check if lazyload type is viewport.
	 *
	 * @return bool
	 */
	public function is_lazyload_type_viewport() {
		return false !== strpos( $this->get( 'lazyload_type' ), 'viewport' );
	}

	/**
	 * Check if lazyload type is all.
	 *
	 * @return bool
	 */
	public function is_lazyload_type_all() {
		return $this->get( 'lazyload_type' ) === 'all';
	}

	/**
	 * Check if lazyload type is fixed.
	 *
	 * @return bool
	 */
	public function is_lazyload_type_fixed() {
		return false !== strpos( $this->get( 'lazyload_type' ), 'fixed' );
	}
	/**
	 * Utility to check if offload is enabled.
	 *
	 * @return bool
	 */
	public function is_offload_enabled() {
		return $this->get( 'offload_media' ) === 'enabled' || $this->get( 'rollback_status' ) !== 'disabled';
	}

	/**
	 * Get cloud sites whitelist for current domain only.
	 *
	 * @return array
	 */
	public function get_cloud_sites_whitelist_default() {
		$site_url = get_site_url();

		$site_url = preg_replace( '/^https?:\/\//', '', $site_url );
		$site_url = trim( $site_url, '/' );

		return [
			'all'     => 'false',
			$site_url => 'true',
		];
	}
}
