<?php
defined( 'ABSPATH' ) or die();

/**
 * Enqueue Gutenberg block assets for backend editor.
 *
 * @since 1.0.0
 */
require_once CMPLZ_PATH . 'settings/config/menu.php';
require_once CMPLZ_PATH . 'settings/config/blocks.php';
require_once CMPLZ_PATH . 'settings/wizard.php';
require_once CMPLZ_PATH . 'settings/config/fields-notices.php';
require_once CMPLZ_PATH . 'settings/media/wp_enqueue_media_override.php';
/**
 * Fix for WPML issue where WPML breaks the rest api by adding a language locale in the url
 *
 * @param $url
 * @param $path
 * @param $blog_id
 * @param $scheme
 *
 * @return string
 */
function cmplz_fix_rest_url_for_wpml( $url, $path, $blog_id, $scheme ) {
	if ( strpos( $url, 'complianz/v' ) === false ) {
		return $url;
	}

	$current_language = false;
	if ( function_exists( 'icl_register_string' ) ) {
		$current_language = apply_filters( 'wpml_current_language', null );
	}

	if ( function_exists( 'qtranxf_getLanguage' ) ) {
		$current_language = qtranxf_getLanguage();
	}

	if ( $current_language ) {
		if ( strpos( $url, '/' . $current_language . '/wp-json/' ) ) {
			$url = str_replace( '/' . $current_language . '/wp-json/', '/wp-json/', $url );
		}
	}
	return $url;
}
add_filter( 'rest_url', 'cmplz_fix_rest_url_for_wpml', 10, 4 );

/**
 * @return void
 * as we can't append #dashboard to the first menu item, we leave it at 'complianz', and replace the text. This is a bit hacky, but it works.
 */
function cmplz_fix_duplicate_menu_item() {
	?>
	<script>
		window.addEventListener("load", () => {
			let cmplzMain = document.querySelector('li.wp-has-submenu.toplevel_page_complianz a.wp-first-item');
			if (cmplzMain) {
				cmplzMain.innerHTML = cmplzMain.innerHTML.replace('Complianz', '<?php esc_html_e( 'Dashboard', 'complianz-gdpr' ); ?>');
			}
		});
	</script>

	<?php
	/**
	 * Ensure the items are selected in sync with the complianz react menu.
	 */
	if ( isset( $_GET['page'] ) && $_GET['page'] === 'complianz' ) {
		?>
			<script>
				const cmplzSetActive = (obj) => {
					obj.classList.add('current');
					obj.parentNode.classList.add('current');
				}

				window.addEventListener("load", () => {
					let cmplzMain = document.querySelector('li.wp-has-submenu.toplevel_page_complianz a.wp-first-item');
					if (cmplzMain) {
						cmplzMain.href = '#';
					}
				});
				//get the hash from the current url
				let cmplzHash = window.location.hash;
				//strip off anything after a /
				if ( cmplzHash.indexOf('/') !== -1 ) {
					cmplzHash = cmplzHash.substring(0, cmplzHash.indexOf('/'));
				}
				if ( !cmplzHash ) {
					let cmplzMain = document.querySelector('li.wp-has-submenu.toplevel_page_complianz a.wp-first-item');
					cmplzSetActive(cmplzMain);
				} else {
					let cmplzMenuItems = document.querySelector('li.wp-has-submenu.toplevel_page_complianz').querySelectorAll('a');
					for (const link of cmplzMenuItems) {
						if (cmplzHash && link.href.indexOf(cmplzHash) !== -1) {
							cmplzSetActive(link);
						} else {
							link.classList.remove('current');
							link.parentNode.classList.remove('current');
						}
					}
				}

				window.addEventListener('click', (e) => {
					const cmplzTargetHref = e.target && e.target.href;
					let cmplzIsMainMenu = false;
					let cmplzIsWpMenu = false;
					if (cmplzTargetHref && e.target.classList.contains('cmplz-main')) {
						cmplzIsMainMenu = true;
					} else if (cmplzTargetHref && cmplzTargetHref.indexOf('admin.php')!==-1) {
						cmplzIsWpMenu = true;
					}
					if (!cmplzIsWpMenu && !cmplzIsMainMenu) {
						return;
					}
					if (cmplzIsWpMenu) {
						if (cmplzTargetHref && cmplzTargetHref.indexOf('page=complianz') !== -1) {
							const parentElement = e.target.parentNode.parentNode;
							const childLinks = parentElement.querySelectorAll('li, a');
							// Loop through each 'a' element and add the class
							for (const link of childLinks) {
								link.classList.remove('current');
							}
							e.target.classList.add('current');
							e.target.parentNode.classList.add('current');
						}
					} else {
						//find cmplzTargetHref in WordPress menu
						let cmplzMenuItems = document.querySelector('li.wp-has-submenu.toplevel_page_complianz').querySelectorAll('a');
						for (const link of cmplzMenuItems) {
							//check if last character of link.href is '#'
							if (cmplzTargetHref.indexOf('dashboard')!==-1 && link.href.charAt(link.href.length - 1) === '#'){
								cmplzSetActive(link);
							} else if (cmplzTargetHref && link.href.indexOf(cmplzTargetHref) !== -1) {
								cmplzSetActive(link);
							} else {
								link.classList.remove('current');
								link.parentNode.classList.remove('current');
							}
						}
					}
				});
			</script>
		<?php
	}
}
add_action( 'admin_footer', 'cmplz_fix_duplicate_menu_item' );
/**
 * WordPress doesn't allow for translation of chunks resulting of code splitting.
 * Several workarounds have popped up in JetPack and Woocommerce: https://developer.wordpress.com/2022/01/06/wordpress-plugin-i18n-webpack-and-composer/
 * Below is mainly based on the Woocommerce solution, which seems to be the most simple approach. Simplicity is king here.
 *
 * @return array
 */
function cmplz_get_chunk_translations() {
	// get all files from the settings/build folder
	$files             = scandir( CMPLZ_PATH . 'settings/build' );
	$json_translations = array();
	foreach ( $files as $file ) {
		if ( strpos( $file, '.js' ) === false ) {
			continue;
		}

		$chunk_handle = str_replace( '.js', '', $file );
		// temporarily register the script, so we can get a translations object.
		wp_register_script( $chunk_handle, plugins_url( 'build/' . $file, __FILE__ ), array(), true );
		$path       = defined( 'cmplz_premium' ) ? CMPLZ_PATH . 'languages' : false;
		$localeData = load_script_textdomain( $chunk_handle, 'complianz-gdpr', $path );
		if ( ! empty( $localeData ) ) {
			$json_translations[] = $localeData;
		}
		wp_deregister_script( $chunk_handle );
	}
	return $json_translations;
}

function cmplz_plugin_admin_scripts() {

	// replace with the actual path to your build directory
	$buildDirPath = plugin_dir_path( __FILE__ ) . '/build';

	// get the filenames in the build directory
	$filenames = scandir( $buildDirPath );

	// filter the filenames to get the JavaScript and asset filenames
	$jsFilename    = '';
	$assetFilename = '';
	foreach ( $filenames as $filename ) {
		if ( strpos( $filename, 'index.' ) === 0 ) {
			if ( substr( $filename, - 3 ) === '.js' ) {
				$jsFilename = $filename;
			} elseif ( substr( $filename, - 10 ) === '.asset.php' ) {
				$assetFilename = $filename;
			}
		}
	}

	/**
	 * Register polyfill for React JSX runtime for version lower than 6.6.
	 *
	 * @TODO: Remove this once the minimum required version of WordPress is 6.6.
	 */
	global $wp_version;

	if ( version_compare( $wp_version, '6.6', '<' ) && ! wp_script_is( 'react-jsx-runtime', 'registered' ) ) {
		wp_enqueue_script(
			'react-jsx-runtime',
			plugins_url( 'assets/js/react-jsx-runtime.js', __FILE__ ),
			array( 'react' ), // it is a polyfill for react JSX runtime, it depends on react
			CMPLZ_VERSION,
		);
	}

	// check if the necessary files are found
	if ( $jsFilename !== '' && $assetFilename !== '' ) {
		$assetFilePath = $buildDirPath . '/' . $assetFilename;
		$assetFile     = require $assetFilePath;
		$handle        = 'cmplz-settings';
		cmplz_wp_enqueue_media();
		wp_enqueue_script( $handle );
		wp_enqueue_script(
			$handle,
			plugins_url( 'build/' . $jsFilename, __FILE__ ),
			$assetFile['dependencies'],
			$assetFile['version'],
			true
		);
		wp_set_script_translations( $handle, 'complianz-gdpr' );

		wp_localize_script(
			'cmplz-settings',
			'cmplz_settings',
			apply_filters(
				'cmplz_localize_script',
				array(
					'json_translations'    => cmplz_get_chunk_translations(),
					'site_url'             => get_rest_url(),
					'admin_url'            => admin_url(),
					'admin_ajax_url'       => add_query_arg(
						array(
							'type'   => 'errors',
							'action' => 'cmplz_rest_api_fallback',
						),
						admin_url( 'admin-ajax.php' )
					),
					'dashboard_url'        => cmplz_admin_url(),
					'upgrade_link'         => cmplz_get_referral_url( 'menu', 'header' ),
					'plugin_url'           => CMPLZ_URL,
					'license_url'          => is_multisite() ? cmplz_main_site_url( '#settings/license' ) : '#settings/license',
					'blocks'               => cmplz_blocks(),
					'is_premium'           => defined( 'cmplz_premium' ),
					'nonce'                => wp_create_nonce( 'wp_rest' ), // to authenticate the logged in user
					'cmplz_nonce'          => wp_create_nonce( 'cmplz_react' ),
					'menu'                 => cmplz_menu(),
					'regions'              => COMPLIANZ::$config->regions,
					'user_id'              => get_current_user_id(),
					'is_multisite'         => is_multisite(),
					'is_multisite_plugin'  => defined( 'cmplz_premium_multisite' ),
					'onboarding_complete'  => cmplz_wsc_auth::wsc_is_authenticated() || COMPLIANZ::$wsc_onboarding->wsc_is_dismissed(),
					'wsc_is_authenticated' => cmplz_wsc_auth::wsc_is_authenticated(),
					'scan_upsell'          => COMPLIANZ::$scan->get_scan_upsell_data(),
					'referral'             => array(
						'source'      => cmplz_get_source(),
						'ref_id'      => cmplz_get_ref(),
						'has_partner' => cmplz_get_ref() !== false,
					),
				)
			)
		);
	}
}

/**
 * Get admin url, adjusted for multisite
 *
 * @return string|null
 */
function cmplz_admin_url( $path = '' ) {
	if ( is_network_admin() ) {
		switch_to_blog( get_main_site_id() );
	}
	$url = add_query_arg( array( 'page' => 'complianz' ), admin_url( 'admin.php' ) );
	if ( is_network_admin() ) {
		restore_current_blog();
	}
	return $url . $path;
}

/**
 * Get admin url, adjusted for multisite
 *
 * @return string|null
 */
function cmplz_main_site_url( $path = '' ) {
	$switch_back = false;
	if ( ! is_main_site() ) {
		$switch_back = true;
		switch_to_blog( get_main_site_id() );
	}
	$url = add_query_arg( array( 'page' => 'complianz' ), admin_url( 'admin.php' ) );
	if ( $switch_back ) {
		restore_current_blog();
	}
	return $url . $path;
}

/**
 * Add SSL menu
 *
 * @return void
 */
function cmplz_add_option_menu() {
	if ( ! cmplz_user_can_manage() ) {
		return;
	}

	$warnings         = COMPLIANZ::$admin->get_warnings(
		array(
			'plus_ones' => true,
		)
	);
	$warning_count    = count( $warnings );
	$warning_title    = esc_attr( cmplz_sprintf( '%s plugin warnings', $warning_count ) );
	$plus_one         = " <span class='update-plugins count-$warning_count' title='$warning_title'><span class='update-count'>" . number_format_i18n( $warning_count ) . '</span></span>';
	$page_hook_suffix = add_menu_page(
		'Complianz',
		'Complianz' . $plus_one,
		apply_filters( 'cmplz_capability', 'manage_privacy' ),
		'complianz',
		'cmplz_settings_page',
		CMPLZ_URL . 'assets/images/menu-icon.svg',
		CMPLZ_MAIN_MENU_POSITION
	);

	add_submenu_page(
		'complianz#dashboard',
		__( 'Dashboard', 'complianz-gdpr' ) . $plus_one,
		__( 'Dashboard', 'complianz-gdpr' ),
		apply_filters( 'cmplz_capability', 'manage_privacy' ),
		'complianz',
		'cmplz_settings_page'
	);

	add_submenu_page(
		'complianz',
		__( 'Wizard', 'complianz-gdpr' ),
		__( 'Wizard', 'complianz-gdpr' ),
		apply_filters( 'cmplz_capability', 'manage_privacy' ),
		'complianz#wizard',
		'cmplz_settings_page'
	);
	do_action( 'cmplz_cookiebanner_menu' );
	add_submenu_page(
		'complianz',
		__( 'Integrations', 'complianz-gdpr' ),
		__( 'Integrations', 'complianz-gdpr' ),
		apply_filters( 'cmplz_capability', 'manage_privacy' ),
		'complianz#integrations',
		'cmplz_settings_page'
	);
	add_submenu_page(
		'complianz',
		__( 'Settings', 'complianz-gdpr' ),
		__( 'Settings', 'complianz-gdpr' ),
		apply_filters( 'cmplz_capability', 'manage_privacy' ),
		'complianz#settings',
		'cmplz_settings_page'
	);
	add_submenu_page(
		'complianz',
		__( 'Tools', 'complianz-gdpr' ),
		__( 'Tools', 'complianz-gdpr' ),
		apply_filters( 'cmplz_capability', 'manage_privacy' ),
		'complianz#tools',
		'cmplz_settings_page'
	);

	do_action( 'cmplz_admin_menu' );
	if ( defined( 'cmplz_free' ) && cmplz_free ) {
		global $submenu;
		if ( isset( $submenu['complianz'] ) ) {
			$class                  = 'cmplz-submenu';
			$highest_index          = count( $submenu['complianz'] );
			$submenu['complianz'][] = array(
				__( 'Upgrade to premium', 'complianz-gdpr' ),
				apply_filters( 'cmplz_capability', 'manage_privacy' ),
				cmplz_get_referral_url( 'menu', 'admin-submenu', 'https://complianz.io/pricing/' ),
			);
			if ( isset( $submenu['complianz'][ $highest_index ] ) ) {
				if ( ! isset( $submenu['complianz'][ $highest_index ][4] ) ) {
					$submenu['complianz'][ $highest_index ][4] = '';
				}
				$submenu['complianz'][ $highest_index ][4] .= ' ' . $class;
			}
		}
	}

	add_action( "admin_print_scripts-{$page_hook_suffix}", 'cmplz_plugin_admin_scripts' );
}
add_action( 'admin_menu', 'cmplz_add_option_menu' );


/**
 * Render the settings page
 */
function cmplz_settings_page() {
	if ( ! cmplz_user_can_manage() ) {
		return;
	}
	?>
	<div id="complianz" class="cmplz"></div>
	<div id="complianz-modal"></div>
	<?php
}

/**
 * If the rest api is blocked, the code will try an admin ajax call as fall back.
 *
 * @return void
 */
function cmplz_rest_api_fallback() {
	$response = $data = array();
	$error    = $action = $do_action = false;
	if ( ! cmplz_user_can_manage() ) {
		$error = true;
	}

	// if the site is using this fallback, we want to show a notice
	update_option( 'cmplz_ajax_fallback_active', time(), false );
	$requestData = json_decode( file_get_contents( 'php://input' ), true );
	if ( empty( $requestData ) ) {
		$requestData = $_GET;
	}

	if ( $requestData ) {
		$action = $requestData['rest_action'] ?? false;
		$action = sanitize_text_field( $action );
		$data   = $requestData['data'] ?? false;
		if ( strpos( $action, 'complianz/v1/do_action/' ) !== false ) {
			$do_action = strtolower( str_replace( 'complianz/v1/do_action/', '', $action ) );
		}
	}
	if ( ! $error ) {
		if ( strpos( $action, 'fields/get' ) !== false ) {
			$response = cmplz_rest_api_fields_get();
		} elseif ( strpos( $action, 'fields/set' ) !== false ) {
			$request  = new WP_REST_Request();
			$response = cmplz_rest_api_fields_set( $request );
		} elseif ( $do_action ) {
			$request = new WP_REST_Request();
			$request->set_param( 'action', $do_action );
			$request->set_param( 'data', $data );
			$response = cmplz_do_action( $request );
		}
	}
	if ( ob_get_length() ) {
		ob_clean();
	}
	header( 'Content-Type: application/json' );
	echo json_encode( $response );
	exit;
}
add_action( 'wp_ajax_cmplz_rest_api_fallback', 'cmplz_rest_api_fallback' );

add_action( 'rest_api_init', 'cmplz_settings_rest_route', 10 );
function cmplz_settings_rest_route() {
	if ( ! cmplz_user_can_manage() ) {
		return;
	}

	register_rest_route(
		'complianz/v1',
		'fields/get',
		array(
			'methods'             => 'GET',
			'callback'            => 'cmplz_rest_api_fields_get',
			'permission_callback' => function () {
				return cmplz_user_can_manage();
			},
		)
	);

	register_rest_route(
		'complianz/v1',
		'fields/set',
		array(
			'methods'             => 'POST',
			'callback'            => 'cmplz_rest_api_fields_set',
			'permission_callback' => function () {
				return cmplz_user_can_manage();
			},
		)
	);

	register_rest_route(
		'complianz/v1',
		'do_action/(?P<action>[a-z\_\-]+)',
		array(
			'methods'             => 'POST',
			'callback'            => 'cmplz_do_action',
			'permission_callback' => function () {
				return cmplz_user_can_manage();
			},
		)
	);
}


/**
 * @param WP_REST_Request $request
 *
 * @return array
 */
function cmplz_do_action( $request ) {
	if ( ! cmplz_user_can_manage() ) {
		return array();
	}

	$data  = $request->get_param( 'data' );
	$nonce = $request->get_param( 'nonce' );
	if ( empty( $nonce ) && isset( $data['nonce'] ) ) {
		$nonce = $data['nonce'];
	}

	if ( ! wp_verify_nonce( $nonce, 'cmplz_react' ) ) {
		return array();
	}
	$action = sanitize_title( $request->get_param( 'action' ) );
	switch ( $action ) {
		case 'get_pages_list':
			$data = COMPLIANZ::$document->get_pages_list( $request );
			break;
		case 'update_custom_legal_document_id':
			$data = COMPLIANZ::$documents_admin->update_custom_legal_document_id( $request );
			break;
		case 'plugin_actions':
			$data = cmplz_plugin_actions( $request );
			break;
		case 'otherpluginsdata':
			$data = cmplz_other_plugins_data();
			break;
		case 'get_cookiebanner_required':
			$is_required = COMPLIANZ::$banner_loader->site_needs_cookie_warning();
			$data        = array( 'required' => $is_required );
			break;
		case 'reset_settings':
			$data = cmplz_reset_settings();
			break;
		default:
			$data = apply_filters( 'cmplz_do_action', array(), $action, $request );
	}

	// Only add request_success if it's not already set by the handler
	if ( ! isset( $data['request_success'] ) ) {
		$data['request_success'] = true;
	}

	if ( ob_get_length() ) {
		ob_clean();
	}
	return $data;
}

/**
 * Reset all settings to default
 */
function cmplz_reset_settings() {
	if ( ! cmplz_user_can_manage() ) {
		return array();
	}

	COMPLIANZ::$scan->reset_pages_list( false, true );
	$options = array(
		'cmplz_first_sync_started',
		'cmplz_post_scribe_required',
		'cmplz_activation_time',
		'cmplz_review_notice_shown',
		'cmplz_wizard_completed_once',
		'cmplz_options',
		'complianz_active_policy_id',
		'complianz_scan_token',
		'cmplz_license_notice_dismissed',
		'cmplz_license_status',
		'cmplz_changed_cookies',
		'cmplz_plugins_changed',
		'cmplz_detected_stats',
		'cmplz_deleted_cookies',
		'cmplz_reported_cookies',
		'cmplz_sync_cookies_complete',
		'cmplz_sync_cookies_after_services_complete',
		'cmplz_sync_services_complete',
		'cmplz_detected_social_media',
		'cmplz_detected_thirdparty_services',
			// 'cmplz_vendorlist_downloaded_once',
	);

	foreach ( $options as $option_name ) {
		delete_option( $option_name );
		delete_site_option( $option_name );
	}

	global $wpdb;
	$table_names = array(
		$wpdb->prefix . 'cmplz_statistics',
		$wpdb->prefix . 'cmplz_cookies',
		$wpdb->prefix . 'cmplz_services',
	);

	foreach ( $table_names as $table_name ) {
		if ( $wpdb->get_var( "SHOW TABLES LIKE '$table_name'" ) === $table_name ) {
			$wpdb->query( "TRUNCATE TABLE $table_name" );
		}
	}

	$banners = cmplz_get_cookiebanners( array( 'status' => 'all' ) );
	foreach ( $banners as $banner ) {
		$banner = cmplz_get_cookiebanner( $banner->ID );
		$banner->delete( true );
	}
	// ensure the activation will run again
	update_option( 'cmplz_run_activation', true, false );

	return array(
		'success' => true,
		'id'      => 'reset_settings',
		'message' => __( 'Data successfully cleared', 'complianz-gdpr' ),
	);
}

/**
 * Process plugin installation or activation actions
 *
 * @param WP_REST_Request $request
 *
 * @return array
 */
function cmplz_plugin_actions( $request ) {
	if ( ! cmplz_user_can_manage() ) {
		return array();
	}
	$slug   = $request->get_param( 'slug' );
	$action = $request->get_param( 'pluginAction' );
	if ( $action === 'download' || $action === 'activate' ) {
		require_once CMPLZ_PATH . 'class-installer.php';
		$installer = new cmplz_installer( $slug );
	}

	if ( $action === 'download' ) {
		$installer->download_plugin();
	} elseif ( $action === 'activate' ) {
		$installer->activate_plugin();
	}
	return cmplz_other_plugins_data( $slug );
}

/**
 * Get plugin data for other plugin section
 *
 * @param string $slug
 * @return array
 */
function cmplz_other_plugins_data( $slug = false ) {
	if ( ! cmplz_user_can_manage() ) {
		return array();
	}
	$plugins = array(
		array(
			'slug'          => 'complianz-terms-conditions',
			'constant_free' => 'cmplz_tc_version',
			'create'        => admin_url( 'admin.php?page=terms-conditions' ),
			'wordpress_url' => 'https://wordpress.org/plugins/complianz-terms-conditions/',
			'title'         => 'Complianz - ' . __( 'Terms & Conditions', 'complianz-gdpr' ),
			'summary'       => __( 'Configure your own Terms and Conditions.', 'complianz-gdpr' ),
			'description'   => __( 'A simple, but in-depth wizard will configure a Terms and Conditions page for your website or for those of your clients.', 'complianz-gdpr' ),
			'image'         => 'complianz-gdpr.png',
		),
		array(
			'slug'             => 'really-simple-ssl',
			'constant_free'    => 'rsssl_version',
			'constant_premium' => 'rsssl_pro',
			'wordpress_url'    => 'https://wordpress.org/plugins/really-simple-ssl/',
			'upgrade_url'      => 'https://really-simple-ssl.com/pro?src=cmplz-plugin',
			'title'            => 'Really Simple Security',
			'summary'          => __( 'Lightweight plugin. Heavyweight security features.', 'complianz-gdpr' ),
			'description'      => __( 'Leverage your SSL certificate to the fullest, with health checks, security headers, hardening, vulnerability detection and more.', 'complianz-gdpr' ),
			'image'            => 'really-simple-ssl.png',
		),
	);

	foreach ( $plugins as $index => $plugin ) {
		$star_rating = false;
		require_once CMPLZ_PATH . 'class-installer.php';
		$installer = new cmplz_installer( $plugin['slug'] );
		// if slug defined, get star rating as well
		if ( $slug ) {
			$plugin_info = $installer->get_plugin_info();
			$star_rating = array(
				'rating'       => $plugin_info->rating,
				'rating_count' => $plugin_info->num_ratings,
			);
		}

		if ( isset( $plugin['constant_premium'] ) && defined( $plugin['constant_premium'] ) ) {
			$plugins[ $index ]['pluginAction'] = 'installed';
		} elseif ( ! $installer->plugin_is_downloaded() && ! $installer->plugin_is_activated() ) {
			$plugins[ $index ]['pluginAction'] = 'download';
		} elseif ( $installer->plugin_is_downloaded() && ! $installer->plugin_is_activated() ) {
			$plugins[ $index ]['pluginAction'] = 'activate';
		} elseif ( isset( $plugin['constant_premium'] ) ) {
				$plugins[ $index ]['pluginAction'] = 'upgrade-to-premium';
		} else {
			$plugins[ $index ]['pluginAction'] = 'installed';
		}
	}

	if ( $slug ) {
		foreach ( $plugins as $key => $plugin ) {
			if ( $plugin['slug'] === $slug ) {
				if ( $star_rating ) {
					$plugin['star_rating'] = $star_rating;
				}

				return $plugin;
			}
		}
	}

	// If first plugin Complianz T&C is not installed, return only that one
	if ( $plugins[0]['pluginAction'] !== 'installed' ) {
		return array( 'plugins' => array( $plugins[0] ) );
	}

	// If first plugin is installed, return only the second one
	return array( 'plugins' => array( $plugins[1] ) );
}


/**
 * List of allowed field types
 *
 * @param $type
 *
 * @return mixed|string
 */
function cmplz_sanitize_field_type( $type ) {
	$types = array(
		'hidden',
		'license',
		'database',
		'checkbox',
		'multicheckbox',
		'password',
		'radio',
		'text',
		'text_checkbox',
		'borderradius',
		'borderwidth',
		'colorpicker',
		'css',
		'editor',
		'textarea',
		'document',
		'number',
		'email',
		'select',
		'phone',
		'url',
		'processors',
		'thirdparties',
	);
	if ( in_array( $type, $types, true ) ) {
		return $type;
	}
	return 'checkbox';
}

/**
 * @param WP_REST_Request $request
 *
 * @return array
 */
function cmplz_rest_api_fields_set( WP_REST_Request $request ): array {
	if ( ! cmplz_user_can_manage() ) {
		return array();
	}

	if ( COMPLIANZ::$wizard->get_lock_user() !== get_current_user_id() ) {
		return array();
	}
	$data  = $request->get_param( 'data' );
	$nonce = $request->get_param( 'nonce' );
	if ( empty( $nonce ) && isset( $data['nonce'] ) ) {
		$nonce = $data['nonce'];
	}
	if ( ! wp_verify_nonce( $nonce, 'cmplz_react' ) ) {
		return array();
	}

	$fields        = $request->get_param( 'fields' );
	$finish        = (bool) $request->get_param( 'finish' );
	$config_fields = COMPLIANZ::$config->fields;
	$config_ids    = array_column( $config_fields, 'id' );
	foreach ( $fields as $index => $field ) {
		$config_field_index = in_array( $field['id'], $config_ids, true );
		if ( $config_field_index === false ) {
			unset( $fields[ $index ] );
		}
	}

	$options = get_option( 'cmplz_options', array() );
	// build a new options array
	foreach ( $fields as $index => $field ) {
		$prev_value = $options[ $field['id'] ] ?? false;

		$value                          = cmplz_sanitize_field( $field['value'], $field['type'], $field['id'] );
		$fields[ $index ]['value']      = $value;
		$fields[ $index ]['prev_value'] = $prev_value;
		$fields[ $index ]['type']       = cmplz_sanitize_field_type( $field['type'] );
		$fields[ $index ]['id']         = cmplz_sanitize_title_preserve_uppercase( $field['id'] );

		do_action( 'cmplz_before_save_option', $fields[ $index ]['id'], $value, $prev_value, $fields[ $index ]['type'] );
		$options[ $field['id'] ] = $value;
		$options                 = cmplz_maybe_add_source_option( $options, $value, $field );
	}

	foreach ( $fields as $field ) {
		$options = apply_filters( 'cmplz_before_save_options', $options, $field['id'], $field['value'], $field['prev_value'], $field['type'] );
	}

	if ( ! empty( $options ) ) {
		update_option( 'cmplz_options', $options );
	}

	foreach ( $fields as $field ) {
		$prev_value = $options[ $field['id'] ] ?? false;
		if ( isset( $field['translatable'] ) && $field['translatable'] ) {

			$value = $field['value'];
			$type  = $field['type'];
			$id    = $field['id'];
			if ( is_array( $value ) && ( $type === 'thirdparties' || $type === 'processors' ) ) {
				foreach ( $value as $item_key => $item ) {
					// contains the values of an item
					foreach ( $item as $key => $key_value ) {
						cmplz_register_translation( $key_value, $item_key . '_' . $id . '_' . $key );
					}
				}
			} else {
				cmplz_register_translation( $value, $id );
			}
		}
		do_action( 'cmplz_after_save_field', $field['id'], $field['value'], $prev_value, $field['type'] );
	}
	do_action( 'cmplz_after_saved_fields', $fields );
	cmplz_delete_transient( 'cmplz_blocked_scripts' );
	if ( $finish ) {
		do_action( 'cmplz_finish_wizard' );
	}
	if ( ob_get_length() ) {
		ob_clean();
	}
	$fields = cmplz_fields( true, $options );
	$fields = apply_filters( 'cmplz_after_saved_fields', $fields );

	return array(
		'request_success'   => true,
		'fields'            => $fields,
		// fields to update the progress bar and notices
		'notices'           => COMPLIANZ::$progress->notices(),
		'show_cookiebanner' => cmplz_cookiebanner_should_load( true ),
		'field_notices'     => cmplz_field_notices(),
	);
}

/**
 * Update a complianz option
 *
 * @param string $name
 * @param mixed  $value
 *
 * @return void
 */
if ( ! function_exists( 'cmplz_update_option' ) ) {
	function cmplz_update_option( string $name, $value ) {
		if ( ! cmplz_admin_logged_in() ) {
			return;
		}
		$config_fields = COMPLIANZ::$config->fields;
		$config_ids    = array_column( $config_fields, 'id' );

		$config_field_index = array_search( $name, $config_ids );
		$config_field       = $config_fields[ $config_field_index ] ?? false;
		if ( $config_field_index === false ) {
			return;
		}

		$type = isset( $config_field['type'] ) ? $config_field['type'] : false;
		if ( ! $type ) {
			return;
		}

		$options = get_option( 'cmplz_options', array() );

		if ( ! is_array( $options ) ) {
			$options = array();
		}

		/*
		 * Some fields are duplicate, but opposite, like safe_mode vs 'enable_cookie_blocker'.
		 * This function will get the value as its mapped value in the related field.
		 * Then the value is saved in that related field
		 */

		$prev_value       = $options[ $name ] ?? false;
		$name             = cmplz_sanitize_title_preserve_uppercase( $name );
		$type             = cmplz_sanitize_field_type( $type );
		$value            = cmplz_sanitize_field( $value, $type, $name );
		$value            = apply_filters( 'cmplz_field_value', $value, cmplz_sanitize_title_preserve_uppercase( $name ), $type );
		$options[ $name ] = $value;
		$options          = cmplz_maybe_add_source_option( $options, $value, $config_field );
		$options          = apply_filters( 'cmplz_before_save_options', $options, $name, $value, $prev_value, $type );

		update_option( 'cmplz_options', $options );

		do_action( 'cmplz_after_save_field', $name, $value, $prev_value, $type );
	}
}

/**
 * Update a complianz option without running the hooks
 * This is needed to prevent infinite loops, when used in the hook callback itself.
 *
 * @param string $name
 * @param mixed  $value
 *
 * @return void
 */
if ( ! function_exists( 'cmplz_update_option_no_hooks' ) ) {
	function cmplz_update_option_no_hooks( string $name, $value ) {
		if ( ! cmplz_admin_logged_in() ) {
			return;
		}
		$config_fields      = COMPLIANZ::$config->fields;
		$config_ids         = array_column( $config_fields, 'id' );
		$config_field_index = array_search( $name, $config_ids );
		$config_field       = $config_fields[ $config_field_index ];
		if ( $config_field_index === false ) {
			return;
		}

		$type = isset( $config_field['type'] ) ? $config_field['type'] : false;
		if ( ! $type ) {
			return;
		}

		$options = get_option( 'cmplz_options', array() );

		if ( ! is_array( $options ) ) {
			$options = array();
		}

		$name             = cmplz_sanitize_title_preserve_uppercase( $name );
		$type             = cmplz_sanitize_field_type( $type );
		$value            = cmplz_sanitize_field( $value, $type, $name );
		$value            = apply_filters( 'cmplz_field_value', $value, $name, $type );
		$options[ $name ] = $value;
		update_option( 'cmplz_options', $options );
	}
}
/**
 * Some fields are duplicate, but opposite, like safe_mode vs 'enable_cookie_blocker'.
 * This function will convert the value to equivalent value in the related field.
 *
 * @param $options
 * @param $value
 * @param $field
 *
 * @return int|mixed|string
 */
function cmplz_maybe_add_source_option( $options, $value, $field ) {
	if ( ! isset( $field['source_id'] ) ) {
		return $options;
	}
	// convert value to mapped source value
	$source_mapping = array_flip( $field['source_mapping'] );
	if ( ! isset( $source_mapping[ $value ] ) ) {
		return $options;
	}

	$mapped_value = $source_mapping[ $value ];

	// get the source field, and update the value in that field.
	$config_fields = COMPLIANZ::$config->fields;

	$config_ids                     = array_column( $config_fields, 'id' );
	$source_field_index             = array_search( $field['source_id'], $config_ids, true );
	$source_field                   = $config_fields[ $source_field_index ];
	$options[ $source_field['id'] ] = $mapped_value;
	return $options;
}

/**
 * Get the rest api fields
 *
 * @return array
 */
function cmplz_rest_api_fields_get(): array {
	if ( ! cmplz_user_can_manage() ) {
		return array();
	}
	$nonce = $_GET['nonce'] ?? false;
	if ( ! wp_verify_nonce( $nonce, 'cmplz_react' ) ) {
		return array();
	}

	if ( ! COMPLIANZ::$wizard->wizard_is_locked() || COMPLIANZ::$wizard->get_lock_user() === get_current_user_id() ) {
		COMPLIANZ::$wizard->lock_wizard();
	}

	delete_option( 'cmplz_ajax_fallback_active' );

	$output                    = array();
	$fields                    = cmplz_fields();
	$output['fields']          = $fields;
	$output['field_notices']   = cmplz_field_notices();
	$output['request_success'] = true;
	$output['locked_by']       = COMPLIANZ::$wizard->get_lock_user() ? COMPLIANZ::$wizard->get_lock_user() : get_current_user_id();
	if ( ob_get_length() ) {
		ob_clean();
	}
	return apply_filters( 'cmplz_rest_api_fields_get', $output );
}

/**
 * Sanitize a field
 *
 * @param mixed  $value
 * @param string $type
 * @param string $id
 *
 * @return array|bool|int|string|void
 */
function cmplz_sanitize_field( $value, string $type, string $id ) {
	switch ( $type ) {
		case 'checkbox':
		case 'number':
			return (int) $value;
		case 'hidden':
			return sanitize_title( $value );
		case 'document':
			return in_array( $value, array( 'generated', 'custom', 'url', 'none' ) ) ? $value : false;
		case 'url':
			return esc_url_raw( $value );
		case 'license':
			return $value;
		case 'multicheckbox':
			if ( ! is_array( $value ) ) {
				$value = empty( $value ) ? array() : array( $value => 1 );
			}
			return array_map( 'sanitize_text_field', $value );
		case 'email':
			return strtolower( sanitize_email( $value ) );
		case 'processors':
			return cmplz_sanitize_processors( $value );
		case 'thirdparties':
			return cmplz_sanitize_thirdparties( $value );
		case 'editor':
			return wp_kses_post( $value );
		case 'colorpicker':
			return cmplz_sanitize_color_picker( $value );
		case 'textarea':
			return wp_kses_post( $value );
		case 'select':
		case 'password':
		case 'text':
		default:
			return sanitize_text_field( $value );
	}
}

function cmplz_sanitize_color_picker( $value ) {

	if ( ! is_array( $value ) ) {
		return false;
	}

	foreach ( $value as $key => $color ) {
		$value[ sanitize_text_field( $key ) ] = sanitize_hex_color( $color );
	}

	return $value;
}
/**
 * Sanizite a processors field
 *
 * @param array $processors
 *
 * @return array
 */
function cmplz_sanitize_processors( $processors ) {
	if ( ! is_array( $processors ) ) {
		$processors = array();
	}
	$defaults = array(
		'name'                 => '',
		'processing_agreement' => false,
		'country'              => false,
		'purpose'              => '',
		'data'                 => '',
		'saved_by_user'        => false,
	);

	foreach ( $processors as $index => $processor ) {
		$processor                         = wp_parse_args( $processor, $defaults );
		$processor['name']                 = sanitize_text_field( $processor['name'] );
		$processor['processing_agreement'] = (int) $processor['processing_agreement'];
		$processor['country']              = sanitize_text_field( $processor['country'] );
		$processor['purpose']              = sanitize_text_field( $processor['purpose'] );
		$processor['data']                 = sanitize_text_field( $processor['data'] );
		$processor['saved_by_user']        = (bool) $processor['saved_by_user'];
		$processors[ $index ]              = $processor;
	}
	return $processors;
}

/**
 * Sanizite a processors field
 *
 * @param array $thirdparties
 *
 * @return array
 */
function cmplz_sanitize_thirdparties( $thirdparties ): array {
	if ( ! is_array( $thirdparties ) ) {
		$thirdparties = array();
	}
	$defaults = array(
		'name'          => '',
		'country'       => false,
		'purpose'       => '',
		'data'          => '',
		'saved_by_user' => false,
	);

	foreach ( $thirdparties as $index => $thirdparty ) {
		$thirdparty                  = wp_parse_args( $thirdparty, $defaults );
		$thirdparty['name']          = sanitize_text_field( $thirdparty['name'] );
		$thirdparty['country']       = sanitize_text_field( $thirdparty['country'] );
		$thirdparty['purpose']       = sanitize_text_field( $thirdparty['purpose'] );
		$thirdparty['data']          = sanitize_text_field( $thirdparty['data'] );
		$thirdparty['saved_by_user'] = (bool) $thirdparty['saved_by_user'];
		$thirdparty[ $index ]        = $thirdparty;
	}
	return $thirdparties;
}

/**
 * Sanitize and encode a password
 *
 * @param $password
 *
 * @return mixed|string
 */
function cmplz_encode_password( $password ) {
	if ( ! cmplz_user_can_manage() ) {
		return $password;
	}
	if ( strlen( trim( $password ) ) === 0 ) {
		return $password;
	}

	$password = sanitize_text_field( $password );
	if ( strpos( $password, 'cmplz_' ) !== false ) {
		return $password;
	}

	$key = get_site_option( 'cmplz_key' );
	if ( ! $key ) {
		update_site_option( 'cmplz_key', time() );
		$key = get_site_option( 'cmplz_key' );
	}

	$ivlength       = openssl_cipher_iv_length( 'aes-256-cbc' );
	$iv             = openssl_random_pseudo_bytes( $ivlength );
	$ciphertext_raw = openssl_encrypt( $password, 'aes-256-cbc', $key, 0, $iv );
	$key            = base64_encode( $iv . $ciphertext_raw );

	return 'cmplz_' . $key;
}

/**
 * Check if the server side conditions apply
 *
 * @param array $conditions
 *
 * @return bool
 */
function cmplz_conditions_apply( array $conditions ) {
	if ( ! cmplz_user_can_manage() ) {
		return false;
	}
	$defaults   = array( 'relation' => 'AND' );
	$conditions = wp_parse_args( $conditions, $defaults );
	$relation   = $conditions['relation'] === 'AND' ? 'AND' : 'OR';
	unset( $conditions['relation'] );
	$condition_applies = true;

	foreach ( $conditions as $condition => $condition_value ) {
		$invert    = substr( $condition, 1 ) === '!';
		$condition = ltrim( $condition, '!' );

		if ( is_array( $condition_value ) ) {
			$this_condition_applies = cmplz_conditions_apply( $condition_value );
		} else {
			// check if it's a function
			if ( substr( $condition, -2 ) === '()' ) {
				$func = $condition;
				if ( preg_match( '/(.*)\:\:(.*)->(.*)/i', $func, $matches ) ) {
					$class                  = $matches[2];
					$func                   = $matches[3];
					$func                   = str_replace( '()', '', $func );
					$this_condition_applies = COMPLIANZ::${$class}->$func() === $condition_value;
				} else {
					$func                   = str_replace( '()', '', $func );
					$this_condition_applies = $func() === $condition_value;
				}
			} else {
				$this_condition_applies = cmplz_get_option( $condition ) === $condition_value;
			}

			if ( $invert ) {
				$this_condition_applies = ! $this_condition_applies;
			}
		}

		if ( $relation === 'AND' ) {
			$condition_applies = $condition_applies && $this_condition_applies;
		} else {
			$condition_applies = $condition_applies || $this_condition_applies;
		}
	}

	return $condition_applies;
}