<?php
/**
 * Utility class for Pixelio Cart Abandon Recovery More plugin.
 *
 * Provides helper functions for plugin settings, API calls, encryption,
 * consent management, date/time handling, email sending, and other common tasks.
 *
 * Class Pixelio_Cart_Abandon_Recovery_More_Util
 *
 * @package PixelioCartAbandonRecoveryMore\Includes\Utils
 */

namespace PixelioCartAbandonRecoveryMore\Includes\Utils;

use DateTime;
use PixelioCartAbandonRecoveryMore\Admin\Wrapper\Pixelio_Cart_Abandon_Recovery_More_Wordpress_Wrapper;
use PixelioCartAbandonRecoveryMore\Frontend\Models\Pixelio_Cart_Abandon_Recovery_More_User_Consent_Model;
use WP_Error;

Pixelio_Cart_Abandon_Recovery_More_Util::pixelio_cart_abandon_recovery_more_check_path();

/**
 * Utility class for Pixelio Cart Abandon Recovery More plugin.
 *
 * Provides helper functions for plugin settings, API calls, encryption,
 * consent management, date/time handling, email sending, and other common tasks.
 *
 * @package PixelioCartAbandonRecoveryMore\Includes\Utils
 */
class Pixelio_Cart_Abandon_Recovery_More_Util
{
	const PIXELIO_CART_ABANDON_RECOVERY_MORE_VERSION = "0.5.3";

	/**
	 * Plugin text domain for translations.
	 *
	 * @var string
	 */
	public static $pixelio_plugin_domain = 'rivio-ai-cart-recovery-marketing-email-automation';

	/**
	 * Levels of settings for the plugin.
	 *
	 * @var array
	 */
	public static $level_of_settings = array('beginner', 'intermediate', 'advanced');
	public static $pack_page_url = 'https://rivio.be?rivio-pricing=1#how';
	public static $first_config_page_url = '/wp-admin/admin.php?page=rivio-first-config';

	public static $pixelio_cart_abandon_recovery_more_allowed_html = [
		'table' => [
			'class' => true,
			'id' => true,
			'style' => true,
		],
		'div' => [
			'class' => true,
			'id' => true,
			'style' => true,
			'data-value' => true,
			'data-mode' => true,
			'max_step' => true,
			'data-callback' => true,
			'data-step-state' => true,
			'contenteditable' => true,
			'data-index' => true,
			'data-clicked_on' => true,
			'data-onshow' => true
		],
		'thead' => [
			'class' => true,
			'id' => true,
			'name' => true,
			'style' => true,
			'data-value' => true,
			'max_step' => true
		],
		'meta' => [
			'name' => true,
			'content' => true,
		],
		'tbody' => [
			'class' => true,
			'id' => true,
			'style' => true,
			'data-value' => true,
			'max_step' => true
		],
		'img' => [
			'src' => true,
			'class' => true,
			'id' => true,
			'style' => true,
			'data-value' => true,
			'max_step' => true
		],
		'tr' => [
			'class' => true,
			'id' => true,
			'style' => true,
			'data-template-id' => true,
			'is_ia' => true,
			'document_status' => true,
			'align' => true,
		],
		'textarea' => [
			'class' => true,
			'id' => true,
			'style' => true,
			'value' => true,
			'name' => true,
		],
		'td' => [
			'class' => true,
			'id' => true,
			'style' => true,
			'align' => true,
			'valign' => true,
			'colspan' => true,
			'rowspan' => true,
		],
		'h3' => [
			'class' => true,
			'id' => true,
			'style' => true,
		],
		'h2' => [
			'class' => true,
			'id' => true,
			'style' => true,
		],

		'table' => [
			'class' => true,
			'id' => true,
			'style' => true,
		],
		'th' => [
			'class' => true,
			'id' => true,
			'style' => true,
		],

		'h1' => [
			'class' => true,
			'id' => true,
			'style' => true,
		],
		'span' => [
			'class' => true,
			'id' => true,
			'style' => true,
			'data-mode' => true
		],
		'br' => [
			'class' => true,
			'style' => true,
			'data-mode' => true
		],
		'strong' => [
			'class' => true,
			'style' => true,
			'data-mode' => true
		],
		'p' => [
			'class' => true,
			'style' => true,
		],
		'label' => [
			'for' => true,
			'class' => true,
			'style' => true,
		],
		'input' => [
			'type' => true,
			'name' => true,
			'value' => true,
			'checked' => true,
			'class' => true,
			'id' => true,
			'style' => true,
			'data-onshow' => true,
		],
		'button' => [
			'type' => true,
			'class' => true,
			'id' => true,
			'style' => true,
			'data-key' => true,
			'data-contact-id' => true,
			'data-clicked_on' => true,
			'data-onshow' => true,
			'data-value' => true,
			'data-template-id' => true,
		],
		'select' => [
			'type' => true,
			'class' => true,
			'name' => true,
			'id' => true,
			'style' => true,
		],
		'option' => [
			'type' => true,
			'class' => true,
			'id' => true,
			'style' => true,
			'value' => true,
		],
		'a' => [
			'href' => true,
			'class' => true,
			'data-force-update' => true,
			'id' => true,
			'style' => true,
		],
		'ul' => [
			'class' => true,
			'id' => true,
		],
		'li' => [
			'class' => true,
			'id' => true,
		],
		'form' => [
			'method' => true,
			'action' => true,
			'style' => true,
			'class' => true,
		],
	];
	public static $expiration_time_of_bought_popup = 60;
	/**
	 * Plugin URL.
	 *
	 * @var string
	 */
	public static $pixelio_plugin_url = '';
	/**
	 * Plugin directory path.
	 *
	 * @var string
	 */
	public static $pixelio_plugin_dir_path = '';
	/**
	 * Plugin changelog.
	 *
	 * @var string
	 */
	public static $changelog = '';
	/**
	 * Plugin slug.
	 *
	 * @var string
	 */
	public static $pixelio_plugin_slug = 'rivio-ai-cart-recovery-marketing-email-automation';
	/**
	 * Plugin class slug.
	 *
	 * @var string
	 */
	public static $pixelio_plugin_class_slug = 'class-pixelio-cart-abandon-recovery-more';
	/**
	 * Logo URL (blue).
	 *
	 * @var string
	 */
	public static $logo_blue = '/admin/assets/img/pixelio-cart-abandon-recovery-more-logo-blue-36px.svg';
	/**
	 * Plugin slogan.
	 *
	 * @var string
	 */
	public static $slogan = 'Sell more effortlessly';
	/**
	 * Database prefix.
	 *
	 * @var string
	 */
	public static $pixelio_plugin_db_prefix = 'pix_';
	/**
	 * Plugin base name.
	 *
	 * @var string
	 */
	public static $plugin_base_name = '';
	/**
	 * Force update flag.
	 *
	 * @var bool
	 */
	public static $force_update = false;
	/**
	 * Plugin version.
	 *
	 * @var string
	 */
	public static $plugin_version;
	/**
	 * Update available flag.
	 *
	 * @var bool
	 */
	public static $update_available = false;

	/**
	 * Finality for cart actions.
	 *
	 * @var string
	 */
	public static $finalite_cart = 'Cart';
	public static $finalite_review = 'Review';
	public static $finalite_wishlist = 'Wishlist';
	public static $gdpr_not_active = "GDPR_WAS_NOT_ACTIVE";
	private Pixelio_Cart_Abandon_Recovery_More_Wordpress_Wrapper $wordpress_wrapper;

	public function __construct($wordpress_wrapper)
	{
		$this->wordpress_wrapper = $wordpress_wrapper;
	}

	/**
	 * Ensure the script is called within WordPress context.
	 *
	 * Terminates execution if ABSPATH is not defined.
	 *
	 * @return void
	 */
	public static function pixelio_cart_abandon_recovery_more_check_path()
	{
		if (!defined('ABSPATH')) {
			die;
		}
	}
	public function pixelio_get_post_value(string $key): string
	{

		return isset($_POST[$key])
			? $this->wordpress_wrapper->pixelio_sanitize_text_field(
				$this->wordpress_wrapper->pixelio_wp_unslash($_POST[$key])
			)
			: '';
	}
	public function pixelio_cart_abandon_recovery_more_is_unreachable($body){
		if (is_wp_error($body)) {

			$error_code = $body->get_error_code();
			$error_message = strtolower($body->get_error_message());

			$is_api_unreachable =
				strpos($error_message, 'timed out') !== false
				|| strpos($error_message, 'timeout') !== false
				|| strpos($error_message, 'curl error 28') !== false
				|| strpos($error_message, 'couldn\'t connect to server') !== false
				|| strpos($error_message, 'failed to connect') !== false
				|| strpos($error_message, 'connection refused') !== false
				|| strpos($error_message, 'dns') !== false
				|| $error_code === 'connect_timeout'
				|| $error_code === 'http_request_failed';
			if ($is_api_unreachable) {

				return true;
			}
		}
		return false;
	}
	/**
	 * Check a nonce for a submitted form field and save its value.
	 *
	 * @param string $name Field name.
	 * @param string $label Field label.
	 * @return array [$name, $label, $value, $error]
	 */
	public function pixelio_cart_abandon_recovery_more_check_nonce($name, $label): array
	{
		$pixelio_cart_abandon_recovery_more_saved_value = '';
		$error = '';
		if (isset($_POST) && isset($_POST[$name]) && isset($_POST[$name . '_wpnonce']) &&
			wp_verify_nonce(sanitize_text_field(wp_unslash($_POST[$name . '_wpnonce'])), $name)) {
			$pixelio_cart_abandon_recovery_more_saved_value = sanitize_text_field(wp_unslash($_POST[$name]));
			$this->pixelio_cart_abandon_recovery_more_add_or_update_option($name, $pixelio_cart_abandon_recovery_more_saved_value);
		} elseif (isset($_POST) && isset($_POST[$name])) {
			$error = 'nonce';

		}

		return array($name, $label, $pixelio_cart_abandon_recovery_more_saved_value, $error);
	}

	/**
	 * Add or update an option in the WordPress database.
	 *
	 * @param string $option_name Name of the option.
	 * @param mixed $option_value Value to store.
	 * @return void
	 */
	public function pixelio_cart_abandon_recovery_more_add_or_update_option($option_name, $option_value)
	{
		if (is_string($option_value)) {
			$option_value = str_replace(' ', '', $option_value);
		}

		if (false === get_option($option_name)) {
			add_option($option_name, $option_value);
		} else {
			update_option($option_name, $option_value);
		}
	}

	/**
	 * Return a descriptive label for AI mode based on plugin state.
	 *
	 * @return string
	 */
	public function pixelio_cart_abandon_recovery_more_get_ia_label_checkbox()
	{

		if ($this->pixelio_cart_abandon_recovery_more_dependency_is_checked('ia-setup-mode')) {
			return 'You are in AI mode.';
		} else {
			return 'You are in manual mode.';
		}
	}

	/**
	 * Check if a specific plugin option is enabled.
	 *
	 * This function retrieves the value of a WordPress option and returns
	 * true if the option is set to 'on', otherwise it returns false.
	 *
	 * @param string $option_name The name of the plugin option to check.
	 *
	 * @return bool True if the option is enabled ('on'), false otherwise.
	 */
	public function pixelio_cart_abandon_recovery_more_dependency_is_checked($option_name): bool
	{
		$value = esc_html(get_option($option_name));
		$value = preg_replace('/\s+/', '', (string)$value);

		if ('on' === $value) {
			return true;
		}
		return false;
	}

	/**
	 * Return configuration for GDPR consent checkbox.
	 *
	 * @return array
	 */
	public function pixelio_cart_abandon_recovery_more_get_rgpd_field_config($consent)
	{

		if ('on' === get_option('pixelio-cart-abandon-recovery-more-gdpr-consent-checkbox', 'off')) {
			if (!$consent) {
				return array(
					'id' => 'namespace/marketing-opt-in',
					'label' => esc_html__('I agree to data processing (GDPR)', 'rivio-ai-cart-recovery-marketing-email-automation'),
					'location' => 'contact',
					'type' => 'checkbox',
				);
			}
		}
		return array();
	}

	/**
	 * Return the API URL depending on environment.
	 *
	 * @return string
	 */
	public function pixelio_cart_abandon_recovery_more_get_url()
	{

		// Environnement de test / dev
		if (defined('WP_PIXELIO_TEST') && WP_PIXELIO_TEST === true) {
			return 'http://localhost:3000/';
		}

		// Production
		return 'https://api.pixelio.be/';
	}

	/**
	 * Return a precise timestamp string with milliseconds.
	 *
	 * @param int $hours Hours to subtract from current time.
	 * @return string
	 */
	public function pixelio_cart_abandon_recovery_more_get_timestamp_as_string($hours = 0): string
	{
		$timestamp = microtime(true) - floatval($hours * 3600);
		$milliseconds = sprintf('%03d', ($timestamp - floor($timestamp)) * 1000);
		$exact_timestamp = gmdate('Y-m-d H:i:s', $timestamp) . '.' . $milliseconds;
		return $exact_timestamp;
	}

	/**
	 * Output the HTML "checked" attribute if a given option is enabled.
	 *
	 * This is useful for generating checkbox inputs in admin forms.
	 * If the option value is 'on', it will echo: checked='checked'.
	 * Otherwise, it echoes an empty string.
	 *
	 * @param string $option_name The name of the option to check.
	 * @return void
	 */
	public function pixelio_cart_abandon_recovery_more_is_checked($option_name)
	{
		if ('on' === get_option($option_name)) {
			echo esc_attr("checked='checked'");
		} else {
			echo esc_attr('');
		}
	}

	/**
	 * Detect if the current visitor is a bot.
	 *
	 * @return bool
	 */
	public function pixelio_cart_abandon_recovery_more_is_bot(): bool
	{
		$cached = null;
		if (null !== $cached) {
			return $cached;
		}

		$ua = isset($_SERVER['HTTP_USER_AGENT']) ? sanitize_text_field(wp_unslash($_SERVER['HTTP_USER_AGENT'])) : '';
		if ('' === $ua) {
			$cached = true;
			return true;
		}

		$bot_regex = '/(bot|crawl|spider|slurp|facebookexternalhit|pingdom|monitoring|statuscake|uptimerobot|curl|wget|python-requests|postman)/i';
		if (preg_match($bot_regex, $ua)) {
			$cached = true;
			return true;
		}

		if (!empty($_SERVER['HTTP_X_UPTIME_CHECK']) || !empty($_SERVER['HTTP_X_MONITOR'])) {
			$cached = true;
			return true;
		}

		$ip = isset($_SERVER['REMOTE_ADDR']) ? sanitize_text_field(wp_unslash($_SERVER['REMOTE_ADDR'])) : '';
		if ($ip) {
			$transient_key = 'pixelio_botcheck_' . md5($ip);
			$res = get_transient($transient_key);
			if (false !== $res) {
				$cached = (bool)$res;
				return $cached;
			}

			$host = gethostbyaddr($ip);
			if ($host && preg_match('/googlebot|bingbot|crawl|amazonaws|facebookexternalhit/i', $host)) {
				set_transient($transient_key, 1, 3600);
				$cached = true;
				return true;
			} else {
				set_transient($transient_key, 0, 3600);
			}
		}

		$cached = false;
		return false;
	}

	/**
	 * Make an HTTP request to an external API with an optional JSON payload.
	 *
	 * This function uses WordPress's `wp_remote_request` to perform the request.
	 * It automatically sets the `Content-Type` header to `application/json` and
	 * includes the decrypted API key from the plugin options in the `x-api-key` header.
	 *
	 * @param string $url The API endpoint URL.
	 * @param string $method The HTTP method to use (GET, POST, PUT, DELETE, etc.). Default 'GET'.
	 * @param array $body Optional data to send as JSON in the request body. Default empty array.
	 *
	 * @return mixed Returns the decoded JSON response as an associative array on success.
	 *               Returns a string with the error message if the request fails.
	 */
	public function pixelio_cart_abandon_recovery_more_call_api($url, $method = 'GET', $body = array())
	{
		$args = array(
			'method' => $method,
			'headers' => array(
				'Content-Type' => 'application/json',
				'x-api-key' => $this->pixelio_cart_abandon_recovery_more_decrypt_api_key('pixelio_api_key'),
			),
			'timeout' => 15,
		);

		if (!empty($body) && $method !== 'GET') {
			$args['body'] = wp_json_encode($body);
		}

		$response = wp_remote_request($url, $args);

		if ($this->wordpress_wrapper->pixelio_is_wp_error($response)) {
			return $response;
		}

		$code = wp_remote_retrieve_response_code($response);
		$body = json_decode(wp_remote_retrieve_body($response), true);

		if ($code < 200 || $code >= 300) {
			$message = is_array($body) && isset($body['message'])
				? $body['message']
				: 'API request failed with status ' . $code;

			return new WP_Error('pixelio_api_error', $message, array(
				'status' => $code,
				'body' => $body,
			));
		}

		return $body;
	}

	/**
	 * Decrypt a previously encrypted API key using AES-256-CBC.
	 *
	 * The encrypted API key must have been created using
	 * pixelio_cart_abandon_recovery_more_encrypt_api_key().
	 * This method decodes the base64 string, extracts the initialization vector (IV),
	 * and decrypts the content using the AUTH_KEY constant as encryption key.
	 *
	 * @param string $encrypted_api_key The encrypted API key (base64 encoded).
	 * @return string|false The decrypted API key, or false if AUTH_KEY is not defined or decryption fails.
	 */
	public function pixelio_cart_abandon_recovery_more_decrypt_api_key($encrypted_api_key)
	{
		$encrypted_api_key = esc_html(get_option($encrypted_api_key, ""));
		if (!defined('AUTH_KEY')) {
			return false;
		}

		$encryption_key = AUTH_KEY;
		// phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode
		$data = base64_decode($encrypted_api_key);
		$iv_length = openssl_cipher_iv_length('aes-256-cbc');
		$iv = substr($data, 0, $iv_length);
		$encrypted_data = substr($data, $iv_length);
		$decrypted_data = openssl_decrypt($encrypted_data, 'aes-256-cbc', $encryption_key, 0, $iv);

		return $decrypted_data;
	}

	/**
	 * Sanitize and clean a URL by removing query parameters and ensuring it is valid.
	 *
	 * This function validates the URL, removes GET parameters, and ensures
	 * the scheme, host, port, path, and fragment are properly sanitized.
	 *
	 * @param string $url The URL to sanitize and clean.
	 *
	 * @return string|null Returns the cleaned URL if valid, or null if the URL is invalid.
	 */
	public function pixelio_cart_abandon_recovery_more_clean_url($url)
	{
		$url = filter_var($url, FILTER_SANITIZE_URL);

		if (!filter_var($url, FILTER_VALIDATE_URL)) {
			return null;
		}

		$parts = wp_parse_url($url);
		$clean = $parts['scheme'] . '://' . $parts['host'];

		if (isset($parts['port'])) {
			$clean .= ':' . $parts['port'];
		}
		if (isset($parts['path'])) {
			$clean .= filter_var($parts['path'], FILTER_SANITIZE_URL);
		}
		if (isset($parts['fragment'])) {
			$clean .= '#' . filter_var($parts['fragment'], FILTER_SANITIZE_URL);
		}

		return $clean;
	}

	/**
	 * Get the value of an option, optionally decrypting it if it's an API key.
	 *
	 * @param string $option_name The name of the option in the database.
	 * @param bool $api_key Whether to decrypt the option as an API key.
	 *
	 * @return mixed The option value, decrypted if requested, or false on failure.
	 */
	public function pixelio_cart_abandon_recovery_more_dependency_get_input_content($option_name, $api_key)
	{
		if ($api_key) {
			return $this->pixelio_cart_abandon_recovery_more_decrypt_api_key($option_name);
		}
		return esc_html(get_option($option_name));
	}

	/**
	 * Echo 'on' or 'off' depending on whether a plugin option is enabled.
	 *
	 * @param string $option_name The option name to check.
	 * @return void
	 */
	public function pixelio_cart_abandon_recovery_more_is_checked_val($option_name)
	{
		if ('on' === get_option($option_name)) {
			echo esc_attr('on');
		} else {
			echo esc_attr('off');
		}
	}

	/**
	 * Encrypt an API key using AES-256-CBC and encode it in base64 for safe storage.
	 *
	 * This method uses the AUTH_KEY constant as the encryption key and generates a random
	 * initialization vector (IV) for each encryption. The resulting string is base64-encoded
	 * to ensure it can be safely stored in the database or options.
	 *
	 * @param string $api_key The API key to encrypt.
	 * @return string|false The encrypted API key encoded in base64, or false if AUTH_KEY is not defined.
	 */
	public function pixelio_cart_abandon_recovery_more_encrypt_api_key($api_key)
	{
		if (!defined('AUTH_KEY')) {
			return false;
		}
		$encryption_key = AUTH_KEY;
		$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length('aes-256-cbc'));
		$encrypted_data = openssl_encrypt($api_key, 'aes-256-cbc', $encryption_key, 0, $iv);
		// phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode used to encode api key
		return base64_encode($iv . $encrypted_data);
	}


	/**
	 * Convert a datetime string into a human-readable "time ago" format.
	 *
	 * Examples of returned values: "2 days ago", "just now", "3 months ago".
	 * Supports years, months, days, hours, and minutes.
	 *
	 * @param string $datetime The datetime string to convert. Should be parseable by DateTime.
	 * @return string Human-readable time difference from now.
	 */
	public function pixelio_cart_abandon_recovery_more_time_ago($datetime)
	{
		$now = new DateTime();
		$then = new DateTime($datetime);
		$diff = $now->diff($then);

		if ($diff->y > 0) {
			return $diff->y . ' ' . esc_html('  year') . ($diff->y > 1 ? 's' : '') . esc_html('  ago');
		} elseif ($diff->m > 0) {
			return $diff->m . esc_html('  month') . ($diff->m > 1 ? 's' : '') . esc_html('  ago');
		} elseif ($diff->d > 0) {
			return $diff->d . __('  day', 'rivio-ai-cart-recovery-marketing-email-automation') . ($diff->m > 1 ? 's' : '') . ($diff->d > 1 ? 's' : '') . __('  ago', 'rivio-ai-cart-recovery-marketing-email-automation');
		} elseif ($diff->h > 0) {
			return $diff->h . __('  hour', 'rivio-ai-cart-recovery-marketing-email-automation') . ($diff->m > 1 ? 's' : '') . ($diff->h > 1 ? 's' : '') . __('  ago', 'rivio-ai-cart-recovery-marketing-email-automation');
		} elseif ($diff->i > 0) {
			return $diff->i . __('  min', 'rivio-ai-cart-recovery-marketing-email-automation') . ($diff->i > 1 ? 's' : '') . __('  ago', 'rivio-ai-cart-recovery-marketing-email-automation');
		} else {
			return __('  just now', 'rivio-ai-cart-recovery-marketing-email-automation');
		}
	}

	/**
	 * Send a formatted HTML email to a recipient using a template.
	 *
	 * This function loads an email template, injects the provided content,
	 * coupon code, and link, and sends the email via WordPress's wp_mail().
	 *
	 * @param string|null $recipient The email address of the recipient. Can be null.
	 * @param mixed $subject The subject of the email.
	 * @param string $pixelio_cart_abandon_recovery_more_email The main content/body of the email.
	 * @param string $pixelio_cart_abandon_recovery_more_coupon_code Optional coupon code to include in the email.
	 * @param string $pixelio_cart_abandon_recovery_more_link Optional link to include in the email.
	 *
	 * @phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals
	 *
	 * @return bool True if the email was sent successfully, false otherwise.
	 */
	public function pixelio_cart_abandon_recovery_more_send_email_to(?string $recipient, mixed $subject, $pixelio_cart_abandon_recovery_more_email, $pixelio_cart_abandon_recovery_more_coupon_code, $pixelio_cart_abandon_recovery_more_link, $pixelio_cart_abandon_recovery_unsubscribed_link, $pixelio_cart_abandon_recovery_tracking_url, $pixelio_cart_abandon_recovery_more_email_template_id): mixed
	{
		// phpcs:ignore WordPress.NamingConventions.ValidVariableName
		$pixelio_cart_abandon_recovery_more_email;
		// phpcs:ignore WordPress.NamingConventions.ValidVariableName
		$pixelio_cart_abandon_recovery_more_coupon_code;
		// phpcs:ignore WordPress.NamingConventions.ValidVariableName
		$pixelio_cart_abandon_recovery_more_link;
		ob_start();
		require $this->wordpress_wrapper->pixelio_plugin_dir_path(__FILE__) . '../templates/email-templates/pixelio-cart-abandon-recovery-more-email-reminder.php';
		$html = ob_get_clean();

		$sent = $this->wordpress_wrapper->pixelio_wp_mail($recipient, $subject, $html, array('Content-Type: text/html; charset=UTF-8'));


		return $sent;
	}

	/**
	 * Checks whether an email address belongs to a temporary (disposable) email provider.
	 *
	 * This method extracts the domain part of the given email address and compares it
	 * against a predefined list of known disposable email domains
	 * (e.g. Mailinator, 10MinuteMail, Yopmail, etc.).
	 *
	 * It is primarily used in Pixelio cart abandonment recovery workflows to
	 * prevent collecting low-quality or short-lived email addresses and to
	 * improve email deliverability and conversion rates.
	 *
	 * Note:
	 * - This method does not perform DNS or MX record validation.
	 * - The list of temporary domains is  and should be updated periodically.
	 *
	 * @param string $email The email address to check.
	 * @return bool True if the email is considered temporary/disposable, false otherwise.
	 * @since 1.0.0
	 *
	 */
	public function pixelio_cart_abandon_recovery_more_is_temporary_email($email)
	{
		$domain = strtolower(substr(strrchr($email, "@"), 1));

		$temporary_domains = [
			'mailinator.com',
			'10minutemail.com',
			'guerrillamail.com',
			'yopmail.com',
			'tempmail.com',
			'dispostable.com',
			'trashmail.com',
			'getnada.com',
		];

		return in_array($domain, $temporary_domains, true);
	}

	public function pixelio_cart_abandon_recovery_more_get_locale()
	{
		if (defined('ICL_SITEPRESS_VERSION') && function_exists('icl_object_id')) {
			// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound use of wpml filter
			$lang = apply_filters('wpml_current_language', null);
			if ($lang) {
				return $lang;
			}
		}

		if (function_exists('pll_current_language')) {
			$lang = pll_current_language();
			if ($lang) {
				return $lang;
			}
		}

		return get_locale();
	}

	public function pixelio_cart_abandon_recovery_more_disconnect()
	{
		delete_option('pixelio_api_key');
		delete_option('pixelio_first_config_done');
		$this->pixelio_cart_abandon_recovery_more_add_or_update_option(
			"ia-setup-mode",
			false
		);
	}


}
