<?php
namespace ActiriseAdmin\Includes;

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

use Actirise\Includes\AbstractCore;
use Actirise\Includes\Api;
use Actirise\Includes\Cron;
use Actirise\Includes\Helpers;
use Actirise\Includes\Logger;
use Actirise\Includes\Options;
use Actirise\Includes\I18n;
use ActiriseAdmin\Includes\View;
use ActiriseAdmin\Includes\Ajax;
use ActiriseAdmin\Includes\SiteHealth;
use ActirisePublic\Includes\AdsTxt;
use ActirisePublic\Includes\Debug;
use Actirise\Includes\AdFormat;
use Actirise\Includes\EventAnnotation;

/**
 * The admin-specific functionality of the plugin.
 *
 * Defines the plugin name, version, and two hooks to
 * enqueue the admin-facing stylesheet and JavaScript.
 * As you add hooks and methods, update this description.
 *
 * @link       https://actirise.com
 * @since      2.0.0
 * @package    actirise
 * @subpackage actirise/admin/includes
 * @author     actirise <wordpress@actirise.com>
 */
final class Core extends AbstractCore {
	/**
	 * The i18n class of the plugin.
	 *
	 * @since    2.0.0
	 * @access   protected
	 * @var      I18n    $i18n    The i18n class of the plugin.
	 */
	protected $i18n;

	/**
	 * The ajax of the plugin.
	 *
	 * @since    2.0.0
	 * @access   public
	 * @var      Ajax    $ajax    The ajax of the plugin.
	 */
	public $ajax;

	/**
	 * The views of the plugin.
	 *
	 * @since    2.0.0
	 * @access   private
	 * @var      View    $views    The views of the plugin.
	 */
	private $views;

	/**
	 * Api class
	 *
	 * @since    2.7
	 * @access   private
	 * @var      Api    $api    Api class.
	 */
	private $api;

	/**
	 * NoPub instance
	 *
	 * @since    3.2.0
	 * @access   private
	 * @var      \ActirisePublic\Includes\NoPub    $no_pub    NoPub instance
	 */
	private $no_pub;

	/**
	 * Initialize the class and set its properties.
	 *
	 * @since    2.0.0
	 * @param    string                         $plugin_name                            The name of this plugin.
	 * @param    string                         $plugin_prefix                          The unique prefix of this plugin.
	 * @param    string                         $version                                The version of this plugin.
	 * @param    \Actirise\Includes\Loader      $loader     The loader of this plugin.
	 * @param    \ActirisePublic\Includes\NoPub $no_pub NoPub instance.
	 */
	public function __construct( $plugin_name, $plugin_prefix, $version, $loader, $no_pub ) {
		$this->plugin_name   = $plugin_name;
		$this->plugin_prefix = $plugin_prefix;
		$this->version       = $version;
		$this->loader        = $loader;
		$this->no_pub        = $no_pub;
		$this->views         = new View();
		$this->ajax          = new Ajax( $plugin_name );
		$this->api           = new Api();

		$this->no_pub->register_meta_box();

		$this->register_ajax_event();

		if ( ! wp_doing_ajax() ) {
			$this->get_user_currency();
			$this->check_debug_token();
			$this->check_organization_fields();
		}

		if ( ACTIRISE_CRON !== 'true' ) {
			EventAnnotation::update_event_annotation();
		}
	}

	/**
	 * Register the JavaScript for the admin area.
	 *
	 * @since    2.0.0
	 * @param string $hook_suffix The current admin page.
	 * @return void
	 */
	public function enqueue_scripts( $hook_suffix ) {
		wp_register_script( $this->plugin_name, ACTIRISE_URL . 'admin/assets/js/main-' . $this->version . '.js', array(), $this->version, true );
		wp_register_style( $this->plugin_name, ACTIRISE_URL . 'admin/assets/css/main-' . $this->version . '.css', array(), $this->version );


		$this->localize_script( $hook_suffix );

		// Enqueue WordPress media library scripts for image picker
		wp_enqueue_media();

		wp_enqueue_script( $this->plugin_name );
		wp_enqueue_style( $this->plugin_name );

		add_filter( 'script_loader_tag', array( $this, 'transform_to_module' ), 10, 3 );
	}

	/**
	 * Transform script to module
	 *
	 * @param string $tag The script tag.
	 * @param string $handle The script handle.
	 * @param string $src The script src.
	 *
	 * @return string
	 */
	public function transform_to_module( $tag, $handle, $src ) {
		if ( 'actirise' === $handle ) {
			$tag = str_replace( '<script ', '<script type="module" ', $tag );
		}

		return $tag;
	}

	/**
	 * Register the page for the admin area.
	 *
	 * @since    2.0.0
	 * @param string $hook_suffix The current admin page.
	 * @return void
	 */
	public function add_plugin_admin_menu( $hook_suffix ) {
		$count_mod = count( $this->get_health_issues() );

		add_menu_page( 'Actirise', $count_mod > 0 ? 'Actirise <span class="awaiting-mod actirise-badge" style="padding: 0 6px;">' . $count_mod . '</span>' : 'Actirise', 'manage_options', 'actirise-settings', array( $this, 'view_settings' ), plugins_url( 'admin/assets/images/icon-actirise.png', ACTIRISE_FILE ), 99 );
	}

	/**
	 * Register the page for the admin area.
	 *
	 * @since    2.0.0
	 * @return void
	 */
	public function view_settings() {
		$this->views->render( 'page-settings', array() );
	}

	/**
	 * Register the settings link in the plugins list.
	 *
	 * @since    2.0.0
	 * @param array<string> $links The current links.
	 * @return array<string>
	 */
	public function add_action_links( $links ) {
		$settings_link = '<a href="' . Helpers::get_page_url() . '">' . __( 'Settings', 'actirise' ) . '</a>';

		array_unshift( $links, $settings_link );

		return $links;
	}

	/**
	 * Run the migrations of the plugin.
	 *
	 * @since    2.4.0
	 * @return void
	 */
	public function migrations() {
		$migrations = new Migrations( $this->plugin_name, $this->version );
		$migrations->migrate();
	}

	/**
	 * Define the locale for this plugin for internationalization.
	 *
	 * Uses the i18n class in order to set the domain and to register the hook
	 * with WordPress.
	 *
	 * @since    2.0.0
	 * @access   public
	 * @return   void
	 */
	public function set_locale() {
		$plugin_i18n = new I18n();

		$this->i18n = $plugin_i18n;
	}

	/**
	 * Register the site health page.
	 *
	 * @since    2.6.8
	 * @return void
	 */
	public function site_health() {
		$site_health = new SiteHealth( $this->plugin_name );

		$this->loader->add_filter( 'debug_information', $site_health, 'site_health_info' );
		$this->loader->add_filter( 'site_status_tests', $site_health, 'site_health_status' );
	}

	/**
	 * Add action to check if debug token exists.
	 *
	 * @since    2.5.5
	 * @access   private
	 * @return   void
	 */
	private function check_debug_token() {
		$debug = new Debug( $this->plugin_name );
		$this->loader->add_action( 'admin_init', $debug, 'check_token' );
	}

	/**
	 * Register actirise js object
	 *
	 * @since    2.0.0
	 * @param string $hook_suffix The current admin page.
	 * @return void
	 */
	private function localize_script( $hook_suffix ) {
		$current_user = wp_get_current_user();

		/** @var int $activation_time */
		$activation_time = Options::get( 'activation-time', 0 );
		/** @var string $user_id */
		$user_id = Options::get( 'settings-analytics-userid', '' );
		/** @var string $api_token */
		$api_token = Options::get( 'settings-analytics-token', '' );

		wp_localize_script(
			$this->plugin_name,
			'actiriseJS',
			array(
				'api_url_data'           => ACTIRISE_URL_API_DATA,
				'api_url_v2'             => ACTIRISE_URL_API_V2,
				'api_token'              => $api_token,
				'api_userid'             => $user_id,
				'currency'               => Options::get( 'currency', 'USD' ),
				'plugin_url'             => ACTIRISE_URL,
				'current_theme'          => wp_get_theme()->get( 'Name' ),
				'nonce'                  => wp_create_nonce( $this->plugin_name . '-settings' ),
				'uuid'                   => Options::get( 'settings-uuid' ),
				'type'                   => Options::get( 'settings-uuid-type', 'boot' ),
				'website_exists'         => Options::get( 'website-exists' ),
				'onboarding_status'      => Options::get( 'onboarding-status' ),
				'contract_status'        => Options::get( 'contract-status' ),
				'contract_type'          => Options::get( 'contract-type' ),
				'contract_duration'      => Options::get( 'contract-duration' ),
				'trial_end_date'         => Options::get( 'trial-end-date' ),
				'ads_serving'            => Options::get( 'ads-serving' ),
				'organization_id'        => Options::get( 'organization-id' ),
				'organization_country'   => Options::get( 'organization-country', '' ),
				'activation_time'        => $activation_time,
				'user_role'              => Helpers::get_user_role( $user_id, $api_token ),
				'user_info'              => array(
					'first_name' => Options::get( 'user-first-name', '' ),
					'last_name'  => Options::get( 'user-last-name', '' ),
					'role'       => Options::get( 'user-role', '' ),
					'role_label' => Options::get( 'user-role-label', '' ),
				),
				'ajaxurl'                => admin_url( 'admin-ajax.php' ),
				'siteurl'                => site_url(),
				'domain'                 => wp_parse_url( site_url() ),
				'cron'                   => defined( 'ACTIRISE_CRON' ) && ACTIRISE_CRON === 'true',
				'tidy'                   => extension_loaded( 'tidy' ),
				'noPub'                  => Options::get( 'nopub', array() ),
				'debug'                  => Options::get( 'debug-enabled', true ) ? 'true' : 'false',
				'country_code'           => substr( get_bloginfo( 'language', 'raw' ), 3 ),
				'website_name'           => get_bloginfo( 'name' ),
				'website_url'            => get_bloginfo( 'url' ),
				'email'                  => $current_user->user_email,
				'auto_update'            => Helpers::has_auto_update() ? 'true' : 'false',
				'customVar'              => array(
					'form'     => $this->get_custom_v_form(),
					'selected' => array(
						'custom1' => Options::get( 'custom1', 'author_ID' ),
						'custom2' => Options::get( 'custom2', 'category_0_slug' ),
						'custom3' => Options::get( 'custom3', 'post_ID' ),
						'custom4' => Options::get( 'custom4', '' ),
						'custom5' => Options::get( 'custom5', '' ),
					),
				),
				'version'                => array(
					'current'   => ACTIRISE_VERSION,
					'available' => $this->get_available_version(),
					'wp'        => get_bloginfo( 'version' ),
				),
				'adstxt'                 => array(
					'actirise'       => AdsTxt::get_adstxt( false ),
					'file'           => Options::get( 'adstxt-file', false ),
					'custom'         => Options::get( 'adstxt-custom', array() ),
					'enabled'        => Options::get( 'adstxt-active', null ),
					'update'         => Options::get( 'adstxt-update', false ),
					'hosted'         => Options::get( 'hosted-adstxt-enabled', false ),
					'redirect_error' => Options::get( 'hosted-adstxt-redirect-error', false ),
				),
				'presizedDiv'            => array(
					'actirise' => Options::get( 'presizeddiv-actirise', array() ),
					'selected' => Options::get( 'presizeddiv-selected', array() ),
					'enabled'  => Options::get( 'presizeddiv-active', false ),
					'notif'    => Options::get( 'presizeddiv-notif', array() ),
				),
				'ad_format'              => array(
					'xpath_test'    => Options::get( 'adformat-slots-xpath', array() ),
					'enabled_slugs' => $this->get_ad_format_enabled_slugs(),
				),
				'fastcmp'                => Helpers::get_fastcmp_options( false ),
				'cmp_vendors'            => $this->get_cmp_vendors_for_frontend(),
				'toggle_features'        => array(
					'website_settings' => Options::get( 'website-settings', array() ),
				),
				'health_check'           => Options::get( 'health-check-cache', $this->get_health_issues() ),
				'gitbook_consent'        => Options::get( 'gitbook-consent', false ),
				'optimization_checklist' => Options::get( 'contract-type' ) === 'essential'
					? Options::get(
						'optimization-checklist-manual',
						array(
							'cache_exclusion'          => false,
							'editorial_best_practices' => false,
						)
					)
					: null,
			)
		);

		wp_localize_script(
			$this->plugin_name,
			'actiriseJSI18n',
			$this->i18n->get_admin_translations()
		);
	}

	/**
	 * Register the ajax event for the admin area.
	 *
	 * @since    2.0.0
	 * @return void
	 */
	private function register_ajax_event() {
		$this->loader->add_action( 'wp_ajax_' . $this->get_plugin_prefix() . 'ajax_action', $this->ajax, 'dispatch' );
	}

	/**
	 * Get all custom v available
	 *
	 * @since 2.0.0
	 * @return array<mixed> All custom v available
	 */
	private function get_custom_v_form() {
		$base_array = array(
			array(
				'name'  => __( 'Not used', 'actirise' ),
				'value' => '',
			),
			array(
				'name'  => __( 'Author', 'actirise' ),
				'value' => 'author_ID',
			),
			array(
				'name'  => __( 'Post', 'actirise' ),
				'value' => array(
					array(
						'name'  => __( 'ID', 'actirise' ),
						'value' => 'post_ID',
					),
					array(
						'name'  => __( 'Slug', 'actirise' ),
						'value' => 'post_post_name',
					),
					array(
						'name'  => __( 'Type', 'actirise' ),
						'value' => 'post_post_type',
					),
				),
			),
			array(
				'name'  => __( 'Category Level 1', 'actirise' ),
				'value' => array(
					array(
						'name'  => __( 'ID', 'actirise' ),
						'value' => 'category_0_cat_ID',
					),
					array(
						'name'  => __( 'Slug', 'actirise' ),
						'value' => 'category_0_slug',
					),
					array(
						'name'  => __( 'Title', 'actirise' ),
						'value' => 'category_0_name',
					),
					array(
						'name'  => __( 'Parent', 'actirise' ),
						'value' => 'category_0_category_parent',
					),
				),
			),
			array(
				'name'  => __( 'Category Level 2', 'actirise' ),
				'value' => array(
					array(
						'name'  => __( 'ID', 'actirise' ),
						'value' => 'category_1_cat_ID',
					),
					array(
						'name'  => __( 'Slug', 'actirise' ),
						'value' => 'category_1_slug',
					),
					array(
						'name'  => __( 'Title', 'actirise' ),
						'value' => 'category_1_name',
					),
					array(
						'name'  => __( 'Parent', 'actirise' ),
						'value' => 'category_1_category_parent',
					),
				),
			),
			array(
				'name'  => __( 'Tag Level 1', 'actirise' ),
				'value' => array(
					array(
						'name'  => __( 'ID', 'actirise' ),
						'value' => 'tag_0_term_id',
					),
					array(
						'name'  => __( 'Slug', 'actirise' ),
						'value' => 'tag_0_slug',
					),
					array(
						'name'  => __( 'Title', 'actirise' ),
						'value' => 'tag_0_name',
					),
					array(
						'name'  => __( 'Parent', 'actirise' ),
						'value' => 'tag_0_parent',
					),
				),
			),
			array(
				'name'  => __( 'Tag Level 2', 'actirise' ),
				'value' => array(
					array(
						'name'  => __( 'ID', 'actirise' ),
						'value' => 'tag_1_term_id',
					),
					array(
						'name'  => __( 'Slug', 'actirise' ),
						'value' => 'tag_1_slug',
					),
					array(
						'name'  => __( 'Title', 'actirise' ),
						'value' => 'tag_1_name',
					),
					array(
						'name'  => __( 'Parent', 'actirise' ),
						'value' => 'tag_1_parent',
					),
				),
			),
		);

		$custom_fields = $this->get_custom_fields();

		if ( $custom_fields !== null && count( $custom_fields ) > 0 ) {
			$custom_fields = array_map(
				function ( $field ) {
					return array(
						'name'  => ucfirst( $field['meta_key'] ),
						'value' => 'customFields_' . $field['meta_key'],
					);
				},
				$custom_fields
			);

			$base_array[] = array(
				'name'  => __( 'Custom Field', 'actirise' ),
				'value' => $custom_fields,
			);
		}

		return $base_array;
	}

	/**
	 * Get all custom fields.
	 *
	 * @since 2.0.0
	 * @return array<array<string>>
	 */
	private function get_custom_fields() {
		/** @var \wpdb $wpdb */
		global $wpdb;

		$cache_key = 'actirise_cache_custom_fields';
		$_posts    = wp_cache_get( $cache_key );

		if ( false === $_posts ) {
			$_posts = $wpdb->get_results( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
				"SELECT DISTINCT meta_key FROM $wpdb->postmeta WHERE meta_key NOT LIKE '\_%'",
				ARRAY_A
			);

			wp_cache_set( $cache_key, $_posts, '', 3600 );
		}

		/** @var array<array<string>> $_posts */
		return $_posts;
	}

	/**
	 * Get user currency, name and role
	 *
	 * @since 2.3.15
	 * @return void
	 */
	private function get_user_currency() {
		if (
			Options::get( 'settings-analytics-userid', '' ) === '' ||
			Options::get( 'settings-analytics-token', '' ) === ''
		) {
			return;
		}

		/** @var string $token */
		$token = Options::get( 'settings-analytics-token', '' );

		if ( $token === '' ) {
			return;
		}

		$response = $this->api->get( 'api', 'users/' . Options::get( 'settings-analytics-userid', '' ), array(), $token );

		if ( is_wp_error( $response ) || ! is_array( $response ) ) {
			return;
		}

		// Store currency
		if ( isset( $response['currency'] ) ) {
			Options::update( 'currency', $response['currency'] );
		}

		// Store first name
		if ( isset( $response['firstName'] ) && is_string( $response['firstName'] ) ) {
			Options::update( 'user-first-name', $response['firstName'] );
		}

		// Store last name
		if ( isset( $response['lastName'] ) && is_string( $response['lastName'] ) ) {
			Options::update( 'user-last-name', $response['lastName'] );
		}

		// Store user role from userGroups
		if ( isset( $response['userGroups'] ) && is_array( $response['userGroups'] ) && ! empty( $response['userGroups'] ) ) {
			$first_group = $response['userGroups'][0];
			if ( isset( $first_group['role']['name'] ) && is_string( $first_group['role']['name'] ) ) {
				Options::update( 'user-role', $first_group['role']['name'] );
			}
			if ( isset( $first_group['role']['label'] ) && is_string( $first_group['role']['label'] ) ) {
				Options::update( 'user-role-label', $first_group['role']['label'] );
			}
		}
	}

	/**
	 * Check website onboarding and contract status
	 *
	 * @since 3.0.0
	 * @param array<string, mixed> $website
	 * @return void
	 */
	public static function check_website_status( $website = array() ) {
		if ( empty( $website ) ) {
			$website = Helpers::get_website_info();
		}

		if ( ! is_array( $website ) || empty( $website ) ) {
			self::clear_website_options();
			return;
		}

		Options::update( 'website-exists', true );

		/** @var string $local_status */
		$local_status = Options::get( 'onboarding-status', 'unknown' );
		/** @var string $api_status */
		$api_status      = $website['onboardingStatus'];
		$is_premium      = isset( $website['contractType'] ) && $website['contractType'] === 'premium';
		$contract_signed = $website['contractStatus'] === 'signed';
		$ads_serving     = $website['adsServing'];
		$next_status     = $local_status;
		$status_map      = array(
			'pending'   => 'approval',
			'suspended' => 'suspended',
			'refused'   => 'refused',
			'disabled'  => 'disabled',
		);

		if ( $ads_serving ) {
			$next_status = 'congrats';

			if ( $local_status === 'activation' ) {
				Options::update( 'activation-time', time() );
			}
		} elseif ( isset( $status_map[$api_status] ) ) {
				/** @var string $mapped_status */
				$mapped_status = $status_map[$api_status];
				$next_status   = $mapped_status;
		} elseif ( $api_status === 'approved' ) {
			if ( $is_premium && in_array( $local_status, array( 'approval', 'refused', 'premium_io', 'unknown' ), true ) ) {
				$next_status = $contract_signed ? 'ads' : 'premium_io';
			} elseif ( ! $is_premium && in_array( $local_status, array( 'approval', 'refused', 'unknown' ), true ) ) {
				$next_status = 'ads';
			} elseif ( $local_status === 'suspended' ) {
				$next_status = 'congrats';
			}
		}

		if ( $next_status === 'ads' ) {
			$cron = new Cron();
			$cron->update_adstxt();
		}

		/** @var array<string, mixed> $website */
		self::update_website_options( $website, $next_status );
	}

	/**
	 * Clear all website-related options
	 *
	 * @since 3.0.3
	 * @return void
	 */
	private static function clear_website_options() {
		$options_to_clear = array(
			'settings-analytics-token',
			'website-exists',
			'website-created-at',
			'onboarding-status',
			'contract-type',
			'contract-status',
			'contract-duration',
			'trial-end-date',
			'ads-serving',
			'website-id',
			'organization-id',
			'billing-status',
		);

		foreach ( $options_to_clear as $option ) {
			Options::delete( $option );
		}
	}

	/**
	 * Update website options with data from API
	 *
	 * @since 3.0.3
	 * @param array<string, mixed> $website
	 * @param string               $status
	 * @return void
	 */
	private static function update_website_options( $website, $status ) {
		Options::update( 'onboarding-status', $status );
		Options::update( 'contract-status', $website['contractStatus'] );
		Options::update( 'ads-serving', $website['adsServing'] );
		Options::update( 'website-created-at', $website['createdAt'] );

		if ( isset( $website['@id'] ) && is_string( $website['@id'] ) ) {
			$website_id = basename( $website['@id'] );
			Options::update( 'website-id', $website_id );
		}

		if ( isset( $website['uuid'] ) ) {
			Options::update( 'website-uuid', $website['uuid'] );
		}

		if ( isset( $website['organization'] ) && is_string( $website['organization'] ) ) {
			$organization_id = basename( $website['organization'] );
			Options::update( 'organization-id', $organization_id );
		}

		$optional_fields = array(
			'contractType'     => 'contract-type',
			'contractDuration' => 'contract-duration',
			'trialEndDate'     => 'trial-end-date',
		);

		foreach ( $optional_fields as $api_field => $option_key ) {
			if ( isset( $website[ $api_field ] ) ) {
				Options::update( $option_key, $website[ $api_field ] );
			}
		}

		if ( isset( $website['websiteSettings'] ) && is_array( $website['websiteSettings'] ) ) {
			$settings = array();
			foreach ( $website['websiteSettings'] as $setting ) {
				if ( isset( $setting['name'] ) && isset( $setting['active'] ) && ( is_string( $setting['name'] ) || is_int( $setting['name'] ) ) ) {
					$settings[ $setting['name'] ] = $setting['active'];
				}
			}
			Options::update( 'website-settings', $settings );
		} else {
			Options::update( 'website-settings', array() );
		}
	}

	/**
	 * Check billing status and head office country in organization
	 *
	 * @since 3.0.0
	 * @return void
	 */
	public static function check_organization_fields() {
		$billing_status  = false;
		$organization_id = Options::get( 'organization-id', '' );
		/** @var string $token */
		$token = Options::get( 'settings-analytics-token', '' );

		if ( $token !== '' && $organization_id !== '' ) {
			$api          = new Api();
			$organization = $api->get(
				'api',
				'organizations/' . $organization_id,
				array(),
				$token
			);

			if ( ! is_wp_error( $organization ) && is_array( $organization ) && ! empty( $organization ) ) {
				if ( isset( $organization['hasBilling'] ) && is_bool( $organization['hasBilling'] ) ) {
					$billing_status = $organization['hasBilling'];
				}
				if ( isset( $organization['country'] ) && is_array( $organization['country'] ) ) {
					if ( isset( $organization['country']['code'] ) && is_string( $organization['country']['code'] ) ) {
						Options::update( 'organization-country', $organization['country']['code'] );
					}
				}
			}
		}

		Options::update( 'billing-status', $billing_status );
	}

	/**
	 * Add admin notice if billing informations are not filled
	 *
	 * @since 3.0.0
	 * @return void
	 */
	public function add_billing_notice() {
		$organization_id = Options::get( 'organization-id', '' );

		if ( Options::get( 'contract-type' ) === 'essential' && Options::get( 'ads-serving' ) && Options::get( 'billing-status', false ) === false && $organization_id !== '' ) {
			$link = esc_url( 'https://platform.actirise.com/organizations/edit/' . $organization_id . '/billing-information' );

			$link_i18n = __( 'Actirise Platform', 'actirise' );

			$message = sprintf(
			// translators: %s: Link to Actirise Platform billing information page.
				__( 'To receive your initial payments, please securely submit your billing information directly on the %s.', 'actirise' ),
				'<a target="_blank" href="' . $link . '">' . $link_i18n . '</a>'
			);
			printf( '<div class="notice notice-error inline" style="margin-left: 2px;"><p>%1$s</p></div>', wp_kses_post( $message ) );
		}
	}

	/**
	 * Get enabled ad format slugs, fetching from API if cache is empty.
	 *
	 * @since 4.1.0
	 * @return array<string>
	 */
	private function get_ad_format_enabled_slugs() {
		/** @var array<string> $slugs */
		$slugs = Options::get( 'ad-format-enabled-slugs', array() );
		if ( ! empty( $slugs ) ) {
			return $slugs;
		}

		$ad_format = new AdFormat();
		$response  = $ad_format->get_slots();
		if ( ! is_wp_error( $response ) ) {
			AdFormat::cache_enabled_slugs( $response );
			/** @var array<string> $cached */
			$cached = Options::get( 'ad-format-enabled-slugs', array() );
			return $cached;
		}

		return array();
	}

	/**
	 * Get health check issues
	 *
	 * @since 4.0.0
	 * @return array<array<string, mixed>>
	 */
	private function get_health_issues() {
		$health_check = new HealthCheck();
		return $health_check->get_issues();
	}

	/**
	 * Get health check data (public wrapper for AJAX access)
	 *
	 * @since 4.0.0
	 * @return array<array<string, mixed>>
	 */
	public function get_health_check_data() {
		return $this->get_health_issues();
	}

	/**
	 * Get CMP vendors from API (for frontend data)
	 *
	 * @since 3.3.0
	 * @return array<mixed>
	 */
	private function get_cmp_vendors_for_frontend() {
		if ( ! Helpers::is_user_authenticated() ) {
			return array();
		}

		/** @var string $token */
		$token    = Options::get( 'settings-analytics-token', '' );
		$response = $this->api->get( 'api', 'cmp_vendors', array(), $token );

		if ( is_wp_error( $response ) ) {
			Logger::add_log( 'get_cmp_vendors_for_frontend: API error - ' . $response->get_error_message(), 'admin/core', 'error' );
			return array();
		}

		if ( ! is_array( $response ) || empty( $response ) ) {
			return array();
		}

		return $response;
	}

	/**
	 * Get available plugin version from update transient
	 *
	 * @since 4.0.0
	 * @return string
	 */
	private function get_available_version() {
		$plugin_file = 'actirise/actirise.php';

		// Get update information
		$update_plugins = get_site_transient( 'update_plugins' );

		// Check if an update is available
		if ( is_object( $update_plugins ) && isset( $update_plugins->response[ $plugin_file ] ) ) {
			$plugin_update = $update_plugins->response[ $plugin_file ];
			if ( is_object( $plugin_update ) && isset( $plugin_update->new_version ) && is_string( $plugin_update->new_version ) ) {
				return $plugin_update->new_version;
			}
		}

		// No update available, return current version
		return ACTIRISE_VERSION;
	}
}
