<?php
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}
/**
 * Check condition and include plugin.php file
 */
if ( ! function_exists( 'is_plugin_active' ) ) {
	include_once( ABSPATH . 'wp-admin/includes/plugin.php' );
}
// phpcs:disable WordPress.NamingConventions.PrefixAllGlobals
/**
 * Escape a WP_Error object for passing directly to wp_die().
 *
 * The wp_die() function accepts an WP_Error object as the first parameter, but it
 * does not escape it\'s contents before printing it out to the user. By passing
 * the object through this function before giving it to wp_die(), the potential for
 * XSS should be avoided.
 *
 * Example:
 *
 * wp_die( my_prefix_escape_wp_error( $error ) );
 *
 * @param WP_Error $error The error to escape.
 *
 * @return WP_Error The escaped error.
 */
function ppw_escape_wp_error( $error ) {

	$code = $error->get_error_code();

	$error_data = $error->error_data;

	if ( isset( $error_data[ $code ]['title'] ) ) {
		$error_data[ $code ]['title'] = wp_kses(
			$error->error_data[ $code ]['title'],
			'escape_wp_error_title'
		);
		$error->error_data            = $error_data;
	}

	$all_errors = $error->errors;

	foreach ( $all_errors as $code => $errors ) {
		foreach ( $errors as $key => $message ) {
			$all_errors[ $code ][ $key ] = wp_kses(
				$message,
				'escape_wp_error_message'
			);
		}
	}

	$error->errors = $all_errors;
	return $error;
}

/**
 * Check data before update setting
 *
 * @param array $request         Request data.
 * @param array $setting_keys    Keys need to check.
 * @param bool  $is_check_cookie Is check cookie.
 *
 * @return bool
 */
function ppw_free_is_setting_data_invalid( $request, $setting_keys, $is_check_cookie = true ) {
	if ( ppw_free_is_setting_keys_and_nonce_invalid( $request, PPW_Constants::GENERAL_FORM_NONCE ) ) {
		return true;
	}

	$settings = $request['settings'];
	foreach ( $setting_keys as $key ) {
		if ( ! array_key_exists( $key, $settings ) ) {
			return true;
		}
	}

	if ( ! $is_check_cookie ) {
		return false;
	}

	// Check regular expression.
	return ppw_core_validate_cookie_expiry( $settings[ PPW_Constants::COOKIE_EXPIRED ] );
}

/**
 * Check data before update entire site settings
 *
 * @param $request
 *
 * @return bool
 */
function ppw_free_is_entire_site_settings_data_invalid( $request ) {
	return ppw_free_is_setting_keys_and_nonce_invalid( $request, PPW_Constants::ENTIRE_SITE_FORM_NONCE );
}

/**
 * @param $request
 * @param $nonce_key
 *
 * @return bool
 */
function ppw_free_is_setting_keys_and_nonce_invalid( $request, $nonce_key ) {
	if ( ! array_key_exists( 'settings', $request ) ||
	     ! array_key_exists( 'security_check', $request ) ) {
		return true;
	}

	if ( ! wp_verify_nonce( $request['security_check'], $nonce_key ) ) {
		return true;
	}

	return false;
}

/**
 * Check error before create new password
 *
 * @param $request
 * @param $setting_keys
 *
 * @return bool
 */
function ppw_free_error_before_create_password( $request, $setting_keys ) {
	if ( ppw_free_is_setting_keys_and_nonce_invalid( $request, PPW_Constants::META_BOX_NONCE ) ) {
		return true;
	}

	$settings = $request["settings"];
	foreach ( $setting_keys as $key ) {
		if ( ! array_key_exists( $key, $settings ) ) {
			return true;
		}
	}

	return false;
}

/**
 * Validate password type is global
 *
 * @param $new_global_passwords
 * @param $current_global_passwords
 * @param $current_roles_password
 */
function ppw_free_validate_password_type_global( $new_global_passwords, $current_global_passwords, $current_roles_password ) {
	if ( count( $new_global_passwords ) < 1 && empty( $current_global_passwords ) ) {
		wp_send_json(
			array(
				'is_error' => true,
				'message'  => PPW_Constants::EMPTY_PASSWORD,
			),
			400
		);
		wp_die();
	}

	$global_validate = ppw_free_check_duplicate_global_password( $new_global_passwords, $current_roles_password );
	if ( $global_validate ) {
		wp_send_json(
			array(
				'is_error' => true,
				'message'  => PPW_Constants::DUPLICATE_PASSWORD,
			),
			400
		);
		wp_die();
	}
}

/**
 * Check case duplicate password type is global
 *
 * @param $new_global_passwords
 * @param $current_roles_password
 *
 * @return bool
 */
function ppw_free_check_duplicate_global_password( $new_global_passwords, $current_roles_password ) {
	if ( empty( $current_roles_password ) ) {
		return false;
	}
	$password_duplicate = array_intersect( $new_global_passwords, array_values( $current_roles_password ) );

	return ! empty( $password_duplicate );
}

/**
 * Validate password type is role
 *
 * @param $role_selected
 * @param $new_role_password
 * @param $current_global_passwords
 * @param $current_roles_password
 */
function ppw_free_validate_password_type_role( $role_selected, $new_role_password, $current_global_passwords, $current_roles_password ) {
	if ( '' === $new_role_password && ( ! isset( $current_roles_password[ $role_selected ] ) || '' === $current_roles_password[ $role_selected ] ) ) {
		wp_send_json(
			array(
				'is_error' => true,
				'message'  => PPW_Constants::EMPTY_PASSWORD,
			),
			400
		);
		wp_die();
	}

	$role_validate = ppw_free_check_duplicate_role_password( $new_role_password, $current_global_passwords );
	if ( $role_validate ) {
		wp_send_json(
			array(
				'is_error' => true,
				'message'  => PPW_Constants::DUPLICATE_PASSWORD,
			),
			400
		);
		wp_die();
	}
}

/**
 * Check case duplicate password type is role
 *
 * @param $new_role_password
 * @param $current_global_passwords
 *
 * @return bool
 */
function ppw_free_check_duplicate_role_password( $new_role_password, $current_global_passwords ) {
	if ( empty( $current_global_passwords ) ) {
		return false;
	}
	$new_role_password = wp_unslash( $new_role_password );

	return in_array( $new_role_password, $current_global_passwords );
}

/**
 * Get all page and post
 *
 * @return array
 */
function ppw_free_get_all_page_post() {
	return array_merge( get_pages(), get_posts( array( 'post_status' => 'publish', 'numberposts' => - 1 ) ) );
}

/**
 * Helper to fix serialized data
 * TODO: write UT for this important function
 *
 * @param $raw_data
 * @param $is_un_slashed
 *
 * @return array
 */
function ppw_free_fix_serialize_data( $raw_data, $is_un_slashed = true ) {
	if ( ! $raw_data ) {
		return array();
	}

	if ( ! is_string( $raw_data ) ) {
		if ( is_array( $raw_data ) ) {
			return $raw_data;
		}

		return array();
	}

	$serialize_raw_data = @unserialize( $raw_data, array( 'allowed_classes' => false ) );
	if ( false === $serialize_raw_data ) {
		return $raw_data;
	}

	if ( ! is_array( $serialize_raw_data ) ) {
        return array();
    }

	return $is_un_slashed ? wp_unslash( $serialize_raw_data ) : $serialize_raw_data;
}

/**
 * @param $cookie
 * @param $expiration
 *
 * @return bool
 */
function ppw_free_bypass_cache_with_cookie_for_pro_version( $cookie, $expiration ) {
	if ( defined( 'COOKIEHASH' ) ) {
		$cookie_hash = preg_quote( constant( 'COOKIEHASH' ) );
	}
	setcookie( PPW_Constants::WP_POST_PASS . $cookie_hash, $cookie, $expiration, COOKIEPATH, COOKIE_DOMAIN );

	return true;
}

/**
 * Check custom login form is showing to avoid conflict with the_password_form default of WordPress.
 *  - Check post type is default type ( post or page )
 *  - Do not show login form product type because we handled it in PPW Pro version. ( woocommerce_before_single_product
 *  hook )
 *  - If Pro version is active then we check protection type in setting to show login form
 *
 * @param string $post_type Post Type of Post.
 *
 * @return bool True|False Is show login form.
 */
function ppw_is_post_type_selected_in_setting( $post_type ) {
	/**
	 * Check default post type
	 * Free & Pro version default: post and page type.
	 */
	if ( 'post' === $post_type || 'page' === $post_type ) {
		return true;
	}

	$is_handle_old_product_type = apply_filters( PPW_Constants::HOOK_HANDLE_BEFORE_RENDER_WOO_PRODUCT, 'product' === $post_type, $post_type );
	if ( $is_handle_old_product_type || ! class_exists( 'PPW_Pro_Constants' ) ) {
		return false;
	}
	$post_type_selected = ppw_core_get_setting_type_array( PPW_Pro_Constants::WPP_WHITELIST_COLUMN_PROTECTIONS );

	/**
	 * Check post type in setting which user selected.
	 */
	return in_array( $post_type, $post_type_selected, true );
}

/**
 * Get post_id from referer url if Post data is not exist post_id.
 *
 * @return int post_id Post ID, 0 if post id not exist.
 */
function ppw_get_post_id_from_request() {
	$_server = wp_unslash( $_SERVER );
	$_post   = wp_unslash( $_POST ); // phpcs:ignore WordPress.Security.NonceVerification.Missing -- We no need to handle nonce verification for this function.
	if ( isset( $_post['post_id'] ) ) {
		return (int) wp_unslash( $_post['post_id'] );
	}
	/**
	 * Make sure http referer on server.
	 * Not make exception in url_to_postid.
	 */
	if ( ! isset( $_server['HTTP_REFERER'] ) ) {
		return 0;
	}

	// Get post id from referer url.
	return url_to_postid( $_server['HTTP_REFERER'] );
}

/**
 * WP introduced is_wp_version_compatible function from version 5.2.0 only.
 * (https://developer.wordpress.org/reference/functions/is_wp_version_compatible/)
 * Need to write the helper by our-self.
 *
 * @param string $required Version to check.
 *
 * @return bool
 */
function ppw_is_wp_version_compatible( $required ) {
	return empty( $required ) || version_compare( get_bloginfo( 'version' ), $required, '>=' );
}

/**
 * Get page title for home, category, tag or post
 *
 * @return string
 */
function ppw_get_page_title() {
	$site_title       = get_bloginfo( 'title' );
	$site_description = get_bloginfo( 'description' );
	$post_title       = wp_title( '', false ); // Post title, category tile, tag title.
	$dash_score_site  = '' === $site_title || '' === $site_description ? '' : ' – ';
	$dash_score_post  = '' === $site_title || '' === $post_title ? '' : ' – ';

	return is_home() || is_front_page()
		? sprintf( '%1$s%2$s%3$s', $site_title, $dash_score_site, $site_description )
		: sprintf( '%1$s%2$s%3$s', $post_title, $dash_score_post, $site_title );
}

/**
 * Get post excerpt if post is protected via Settings.
 *
 * @param WP_Post $post            Post WordPress Object.
 * @param string  $content         Content of post.
 * @param bool    $is_show_excerpt Is show excerpt.
 *                                 TODO: Need to refactor logic for this function.
 *
 * @return string
 */
function ppw_handle_protected_content( $post, $content, $is_show_excerpt ) {
	if ( $is_show_excerpt && $post->post_excerpt ) {
		$content = $post->post_excerpt . $content;
	}

	if ( ! is_singular() && ! preg_match( '/name=.+post_id/mi', $content ) ) {
		$content = '<em>[This is password-protected.]</em>';

		return apply_filters( 'the_ppw_password_message', $content );
	}

	return $content;
}

/**
 * Helper function to get Pro version.
 */
function ppw_get_pro_version() {
	if ( ! defined( 'PPW_PRO_VERSION' ) ) {
		return '';
	}

	return PPW_PRO_VERSION;
}

/**
 * Bypass function using to
 *    - Display feed content when user turn on sitewide protection.
 *
 * @return bool True is bypass sitewide.
 */
function ppw_free_has_bypass_sitewide_protection() {
	$has_bypass = defined( 'PPWP_SITEWIDE_FEED_DISPLAY' ) && PPWP_SITEWIDE_FEED_DISPLAY && is_feed();

	return apply_filters( 'ppwp_sitewide_has_bypass', $has_bypass );
}

/**
 * Bypass function using to
 *    - Display feed content when post/page is protected by single protection.
 *
 * @return bool True is bypass post_password_required.
 */
function ppw_free_has_bypass_single_protection() {
	$has_bypass = defined( 'PPWP_SINGLE_FEED_DISPLAY' ) && PPWP_SINGLE_FEED_DISPLAY && is_feed();

	return apply_filters( 'ppwp_single_has_bypass', $has_bypass );
}

/**
 * Has support PPWP shortcode for page builder.
 *
 * @return bool
 */
function ppw_free_has_support_shortcode_page_builder() {
	// Have user turn on option.
	$enabled = ppw_core_get_setting_type_bool_by_option_name( PPW_Constants::USE_SHORTCODE_PAGE_BUILDER, PPW_Constants::SHORTCODE_OPTIONS );

	return apply_filters( 'ppwp_shortcode_enable_page_builder', $enabled );
}

/**
 * Checks the plaintext password against the encrypted Password.
 *
 * @param string $password Plaintext user's password
 * @param string $hash     Hash of the user's password to check against.
 *
 * @return bool False, if the $password does not match the hashed password
 * @link https://developer.wordpress.org/reference/functions/wp_check_password/
 */
function ppw_free_check_password( $password, $hash ) {
	/* global $wp_hasher;
	// If the stored hash is longer than an MD5,
	// presume the new style phpass portable hash.
	if ( empty( $wp_hasher ) ) {
		require_once ABSPATH . WPINC . '/class-phpass.php';
		// By default, use the portable hash from phpass.
		$wp_hasher = new PasswordHash( 8, true );
	}

	return $wp_hasher->CheckPassword( $password, $hash );*/
	return wp_check_password( $password, $hash );

}

/**
 * Retrieve the shortcode matches for searching.
 *
 * @param $content
 *
 * @return array The regular expression contains 6 different sub matches to help with parsing.
 * 1 - An extra [ to allow for escaping shortcodes with double [[]]
 * 2 – The shortcode name
 * 3 – The shortcode argument list
 * 4 – The self closing /
 * 5 – The content of a shortcode when it wraps some content.
 * 6 – An extra ] to allow for escaping shortcodes with double [[]]
 */
function ppw_free_search_shortcode_content( $content ) {
	preg_match_all( '/' . get_shortcode_regex( array( 'ppwp' ) ) . '/', $content, $matches, PREG_SET_ORDER );

	return $matches;
}

function ppw_free_valid_pcp_password( $shortcode, $password ) {
	$default_args = array(
		'is_valid_password' => false,
		'atts'              => array(),
	);
	// Check ppwp shortcode exist.
	if ( PPW_Constants::PPW_HOOK_SHORT_CODE_NAME !== $shortcode[2] || ! isset( $shortcode[3] ) ) {
		return $default_args;
	}
	// Parse shortcode string to array.
	$parsed_atts = shortcode_parse_atts( trim( $shortcode[3] ) );

	// Get attributes from shortcode.
	$atts      = PPW_Shortcode::get_instance()->get_attributes( $parsed_atts );
	$passwords = apply_filters( PPW_Constants::HOOK_SHORTCODE_PASSWORDS, array_filter( $atts['passwords'], 'strlen' ), $parsed_atts );

	// Check password exist.
	if ( in_array( $password, $passwords, true ) ) {
		$default_args['is_valid_password'] = true;
		$default_args['atts']              = $atts;
	}

	if ( !in_array( $password, $passwords, true ) && function_exists( 'ppw_pro_allowed_regex_password' ) && ppw_pro_allowed_regex_password() ) {
		$password_found = apply_filters( PPW_Constants::HOOK_SHORTCODE_WILDCARD_PASSWORDS, $parsed_atts, $password );
		if( !empty( $password_found ) ){
			$default_args['is_valid_password'] = true;
			$default_args['atts']              = $atts;
		}
	}

	if ( isset( $parsed_atts['error_msg'] ) ) {
		$default_args['message'] = wp_kses_post( $parsed_atts['error_msg'] );
	}

	return apply_filters( 'ppw_validated_pcp_password', $default_args, $password, $parsed_atts, $shortcode );
}

/**
 * Validate date.
 *
 * @param        $date
 * @param string $format
 *
 * @return bool
 */
function ppw_free_validate_date( $date ) {
	return false !== strtotime( $date );
}

function ppw_get_background_image( $image ) {
	$img = get_theme_mod( 'ppwp_pro_form_background_image', '' );
	if ( ! empty( $img ) ) {
		return $img;
	}

	return PPW_DIR_URL . 'includes/customizers/assets/images/backgrounds/' . $image;
}


/**
 * Support with builder plugin.
 *
 * @param integer $post_id      Post ID.
 * @param string  $post_content Post Content.
 *
 * @return string Post Content.
 */
function ppw_support_third_party_content_plugin( $post_id, $post_content ) {
	if ( method_exists( '\WPBMap', 'addAllMappedShortcodes' ) ) {
		\WPBMap::addAllMappedShortcodes();
	}
	if ( class_exists( '\TablePress' ) ) {
		\TablePress::$controller = \TablePress::load_controller( 'frontend' );
		\TablePress::$controller->init_shortcodes();
	}
	if ( class_exists( '\\Elementor\\Plugin' ) ) {
		if ( \Elementor\Plugin::$instance->db->is_built_with_elementor( $post_id ) ) {
			// Disable function check post_password_required because need to get content show to user.
			remove_all_filters( 'post_password_required' );
			$post_content = \Elementor\Plugin::$instance->frontend->get_builder_content( $post_id, true );
		}
	}

	return apply_filters( 'ppw_content_compatibility', $post_content );
}

/**
 * Get PPWP Pro plugin data version.
 *
 * @return false|string
 */
function ppw_get_pro_data_version() {
	if ( defined( 'PPW_PRO_VERSION' ) ) {
		return PPW_PRO_VERSION;
	}

	if ( ! function_exists( 'get_plugins' )
	     || ! function_exists( 'is_plugin_active' )
	     || ! function_exists( 'get_plugins' )
	) {
		require_once( ABSPATH . '/wp-admin/includes/plugin.php' );
	}

	// Check plugin is active from option data.
	if ( ! is_plugin_active( PPW_Constants::PRO_DIRECTORY ) && ! is_plugin_active( PPW_Constants::DEV_PRO_DIRECTORY ) ) {
		return false;
	}

	// Get plugin version from file.
	$installed_plugins = get_plugins();

	// Get Pro Production folder version.
	if ( isset( $installed_plugins[ PPW_Constants::PRO_DIRECTORY ], $installed_plugins[ PPW_Constants::PRO_DIRECTORY ]['Version'] ) ) {
		return $installed_plugins[ PPW_Constants::PRO_DIRECTORY ]['Version'];
	}

	// Get Pro Development folder version.
	if ( isset( $installed_plugins[ PPW_Constants::DEV_PRO_DIRECTORY ], $installed_plugins[ PPW_Constants::DEV_PRO_DIRECTORY ]['Version'] ) ) {
		return $installed_plugins[ PPW_Constants::DEV_PRO_DIRECTORY ]['Version'];
	}

	return false;
}

/**
 * Get allowed capability.
 *
 * @return string
 */
function ppw_get_allowed_capability() {
	if ( current_user_can( 'manage_options' ) ) {
		return 'manage_options';
	}

	return 'ppwp_manage_options';
}

/**
 * Allow user to display all PPWP option.
 *
 * @return bool
 */
function ppw_allow_manage_passwords() {
	$capability = ppw_get_allowed_capability();

	return current_user_can( $capability ) || current_user_can( 'edit_posts' );
}

function ppw_allow_manage_master_passwords() {
    $capability = ppw_get_allowed_capability();

    return current_user_can( $capability );
}

function ppw_allowed_master_protection_type() {
	return apply_filters( 'ppw_allowed_master_protection_type', false );
}

function ppw_get_current_user_agent() {
	return ! empty( $server_env['HTTP_USER_AGENT'] ) ? $server_env['HTTP_USER_AGENT'] : 'N/A';
}

function ppw_get_current_ip_address() {
	$server = wp_unslash( $_SERVER );
	if ( ! empty( $server['HTTP_CF_CONNECTING_IP'] ) ) {
		return $server['HTTP_CF_CONNECTING_IP'];
	}

	if ( ! empty( $server['HTTP_CLIENT_IP'] ) ) {
		return $server['HTTP_CLIENT_IP'];
	}

	if ( ! empty( $server['HTTP_X_FORWARDED_FOR'] ) ) {
		return $server['HTTP_X_FORWARDED_FOR'];
	}

	return $server['REMOTE_ADDR'];
}

/**
 * Get current user name.
 *
 * @return string
 */
function ppw_get_current_username() {
	$current_user = wp_get_current_user();
	return 0 === $current_user->ID ? 'N/A' : $current_user->user_login;
}

function ppw_tracking_master_password( $post_id, $password, $type = 'single' ) {
	$meta_data         = array(
		'protection_type' => $type,
	);
	$meta_data         = apply_filters( 'ppw_master_pcp_password_meta', $meta_data );
	$meta_data_encoded = wp_json_encode( $meta_data );
	$data              = array(
		'user_agent'  => ppw_get_current_user_agent(),
		'ip_address'  => ppw_get_current_ip_address(),
		'password'    => $password,
		'username'    => ppw_get_current_username(),
		'post_type'   => 'ppwp_master',
		'access_date' => time(),
		'post_id'     => $post_id,
		'meta_data'   => $meta_data_encoded,
	);

	do_action( 'ppwp_track_password', $data );
}

function ppw_get_pcp_post_content_with_third_party( $post, $index ) {
	$allowed = did_action( 'elementor/loaded' );
	$allowed = apply_filters( 'ppw_pcp_third_party_content_allowed', $allowed );
	if ( ! $allowed ) {
		return false;
	}

	setup_postdata( $post );
	$post_content = ppw_support_third_party_content_plugin( $post->ID, false );
	if ( empty( $post_content ) ) {
		return false;
	}

	wp_reset_postdata();
	$matches = ppw_free_search_shortcode_content( $post_content );
	if ( isset( $matches[ $index ] ) ) {
		$new_shortcode = $matches[ $index ];

		return isset( $new_shortcode[5] ) ? $new_shortcode[5] : false;
	}

	return false;
}

function ppw_get_value( $data, $key, $default = '' ) {
	if ( ! isset( $data[ $key ] ) ) {
		return $default;
	}

	return $data[ $key ];
}

function ppw_free_render_sidebar() {
	if ( ! is_pro_active_and_valid_license() ) {
		include PPW_DIR_PATH . 'includes/views/sidebar/view-ppw-sidebar.php';
	} else {
		do_action( PPW_Constants::HOOK_SIDEBAR_SHORTCODE );
	}
}

function ppw_get_utc() {
	$min    = 60 * get_option('gmt_offset');
	$sign   = $min < 0 ? "-" : "+";
	$absmin = abs($min);
	return sprintf("UTC%s%02d:%02d", $sign, $absmin/60, $absmin%60);
}

function ppw_get_terms_with_all_lang( $args ) {
	global $sitepress;

	if ( $sitepress ) {
		remove_filter( 'get_terms_args', array( $sitepress, 'get_terms_args_filter' ) );
		remove_filter( 'get_term', array( $sitepress, 'get_term_adjust_id' ) );
		remove_filter( 'terms_clauses', array( $sitepress, 'terms_clauses' ) );

		$terms = get_terms( $args );

		add_filter( 'terms_clauses', array( $sitepress, 'terms_clauses' ), 10, 4 );
		add_filter( 'get_term', array( $sitepress, 'get_term_adjust_id' ), 1, 1 );
		add_filter( 'get_terms_args', array( $sitepress, 'get_terms_args_filter' ), 10, 2 );
	} else {
		$terms = get_terms( $args );
	}

	return $terms;
}
