<?php

class PPW_Content_Protection {
	/**
	 * @var PPW_Content_Protection
	 */
	protected static $instance;

	const POST_TYPE = 'ppwp-section';

	const SETTING_META_KEY = 'ppw_pcp_setting';

	const PASSWORD_GLOBAL_TYPE = 'PCPSection';

	const PASSWORD_ROLE_TYPE = 'PCPSectionRole_';

	const COOKIE_NAME = 'ppw_section-';

	const ADMIN_PATH = 'edit.php?post_type=ppwp-section';

	const SHORTCODE_COLUMN = 'ppw_pcp_shortcode';

	/**
	 * @var PPW_Password_Services
	 */
	private $password_service;

	/**
	 * @var PPW_Repository_Passwords
	 */
	private $password_repo;

	/**
	 * @return PPW_Content_Protection
	 */
	public static function get_instance() {
		if ( null == self::$instance ) {
			self::$instance = new self();
		}

		return self::$instance;
	}

	public function __construct() {
		$this->password_service = new PPW_Password_Services();
		$this->password_repo    = new PPW_Repository_Passwords();
	}

	public function register() {
		add_action( 'init', array( $this, 'register_post_type' ) );
		add_action( 'wp_ajax_ppw_pcp_validate_password', array( $this, 'validate_password' ) );
		add_action( 'wp_ajax_nopriv_ppw_pcp_validate_password', array( $this, 'validate_password' ) );
		add_filter( 'ppw_shortcode_render_content', array( $this, 'handle_shortcode_with_area' ), 10, 2 );
		add_filter( 'et_builder_load_actions', array( $this, 'add_action_to_divi' ) );
		add_filter( 'ppw_pcp_valid_shortcode', array( $this, 'valid_shortcode' ), 10, 2 );
		add_action( 'admin_init', array( $this, 'maybe_add_metabox' ) );
		add_filter( 'ppw_shortcode_unlock_content', array( $this, 'maybe_unlock_content_by_cookie' ), 15, 2 );
		add_filter( 'ppw_pcp_submenu_add_new_tab', array( $this, 'add_pcp_tab' ), 1000 );
		add_filter( 'manage_' . self::POST_TYPE . '_posts_columns', array( $this, 'add_shortcode_column' ) );
		add_action( 'manage_' . self::POST_TYPE . '_posts_custom_column', array(
			$this,
			'render_content_custom_column',
		), 10, 2 );
		add_action( 'admin_notices', array( $this, 'handle_admin_notices' ) );
	}

	public function add_shortcode_column( $columns ) {
		$inserted = array(
				self::SHORTCODE_COLUMN => 'Shortcode'
		);

		return array_slice( $columns, 0, 2, true )
		       + $inserted
		       + array_slice( $columns, 2, count( $columns ) - 1, true );
	}

	public function render_content_custom_column( $column, $post_id ) {
		if ( $column === self::SHORTCODE_COLUMN ) {
			echo '[ppwp section="' . absint( $post_id ) . '" /]';
		}
	}

	public function add_pcp_tab( $tabs ) {
		$tabs[] = array(
			'tab'      => 'section',
			'tab_name' => 'Section Protection',
			'link'     => self::ADMIN_PATH,
		);

		return $tabs;
	}

	public function valid_shortcode( $content, $attrs ) {
		if ( ! isset( $attrs['section'] ) || ! is_numeric( $attrs['section'] ) ) {
			return $content;
		}

		if ( absint( $attrs['section'] ) > 0 ) {
			return true;
		}

		return $content;
	}

	public function register_post_type() {
		$args = array(
			'labels'          => array(
				'name'               => __( 'Section Protection', 'password-protect-page' ),
				'singular_name'      => __( 'Section Protection', 'password-protect-page' ),
				'add_new'            => __( 'Add New', 'password-protect-page' ),
				'add_new_item'       => __( 'Add New', 'password-protect-page' ),
				'edit_item'          => __( 'Edit', 'password-protect-page' ),
				'new_item'           => __( 'New', 'password-protect-page' ),
				'view_item'          => __( 'View', 'password-protect-page' ),
				'search_items'       => __( 'Search', 'password-protect-page' ),
				'not_found'          => __( 'No found', 'password-protect-page' ),
				'not_found_in_trash' => __( 'No found in Trash', 'password-protect-page' ),
			),
			'public'          => false,
			'hierarchical'    => true,
			'show_ui'         => true,
			'show_in_menu'    => self::ADMIN_PATH,
			'_builtin'        => false,
			'capability_type' => 'post',
			'supports'        => array( 'title', 'editor' ),
			'rewrite'         => false,
			'query_var'       => false,
			'show_in_rest'    => true,
		);

		if ( current_user_can( 'administrator' ) ) {
			$args['public']             = true;
			$args['publicly_queryable'] = true;
		}

//		if ( is_admin() ) {
//			global $pagenow, $typenow, $post;
//			if ( 'edit.php' === $pagenow || self::POST_TYPE === $typenow ) {
//				$args['show_in_menu'] = PPW_Constants::MENU_NAME;
//			} elseif ( isset( $_GET['post_type'] ) && self::POST_TYPE === $_GET['post_type'] ) {
//				$args['show_in_menu'] = PPW_Constants::MENU_NAME;
//			} elseif ( isset( $_GET['post'] ) && isset( $_GET['action'] ) ) {
//				$post_type = get_post_type( $_GET['post'] );
//
//				if ( $post_type === self::POST_TYPE ) {
//					$args['show_in_menu'] = PPW_Constants::MENU_NAME;
//				}
//			}
//		}

		register_post_type( self::POST_TYPE, $args );
	}

	/**
	 * Add ajax support for Divi builder.
	 *
	 * @param array $actions array of allowed actions.
	 *
	 * @return array
	 */
	public function add_action_to_divi( $actions ) {
		$actions[] = 'ppw_pcp_validate_password';

		return $actions;
	}

	public function handle_shortcode_with_area( $content, $attrs ) {
		if ( ! isset( $attrs['section'] ) ) {
			return $content;
		}
		$post_id = absint( $attrs['section'] );
		if ( ! $post_id ) {
			return $content;
		}

		$post = get_post( $post_id );
		if ( empty( $post ) || $post->post_type !== self::POST_TYPE ) {
			return $content;
		}

		$post_content = $this->massage_post_content( $post_id, $post->post_content );
		if ( is_null( $post_content ) ) {
			return $content;
		}

		return $post_content;
	}

	public function massage_post_content( $post_id, $post_content ) {
		$post_content = ppw_support_third_party_content_plugin( $post_id, $post_content );

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

	public function maybe_add_metabox() {
		$attributes = apply_filters(
			'ppw_pcp_metabox_attributes',
			array(
				'title'    => __( 'Password Protect WordPress', PPW_Constants::DOMAIN ),
				'callback' => array( $this, 'display_metabox' ),
				'screen'   => array( self::POST_TYPE ),
				'context'  => 'side',
				'priority' => 'high',
			)
		);

		add_meta_box(
			'ppw_pcp_meta_box',
			$attributes['title'],
			$attributes['callback'],
			$attributes['screen'],
			$attributes['context'],
			$attributes['priority']
		);
	}

	public function display_metabox() {
		ob_start();
		?>
		<div id="ppw-pcp-metabox"></div>
		<?php
		wp_enqueue_script( 'ppw-pcp-metabox', PPW_DIR_URL . 'admin/js/dist/pcp-metabox.js', array(), PPW_VERSION, true );
		wp_localize_script(
			'ppw-pcp-metabox',
			'pcpMetabox',
			array(
				'rest_url'      => get_rest_url( null, '/wppp/v1/pcp' ),
				'nonce'         => wp_create_nonce( 'wp_rest' ),
				'post_id'       => get_the_ID(),
				'customize_url' => admin_url( 'customize.php' ),
				'extra_html'    => apply_filters( 'ppw_pcp_metabox_extra_html', '')
			)
		);

		echo ob_get_clean(); // phpcs:ignore -- we cannot escape ob_start ob_get_clean(), there are no variable to escape in statement above
	}

	public function validate_single_password( $params ) {
		$password = $params['password'];
		$area     = $params['area'];
		$roles    = ppw_core_get_current_role();
		$args     = array(
			'post_id'     => $area,
			'roles'       => $roles,
			'global_type' => self::PASSWORD_GLOBAL_TYPE,
			'role_type'   => self::PASSWORD_ROLE_TYPE,
		);

		$password_info = $this->password_repo->find_activated_password( $password, $args );
		if ( empty( $password_info ) ) {
			return false;
		}

		$this->password_service->set_cookie_bypass_cache( $password, self::COOKIE_NAME . $area . 'p' . $password_info->id );

		do_action( 'ppw_after_save_section_cookie', $password_info );

		return true;
	}

	public function validate_password() {
		if ( ! isset( $_POST['pss'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Processing form data without nonce verification. - Not verify nonce for password validate.
			wp_send_json(
				array(
					'success' => false,
					'message' => 'Please enter the correct password!',
				),
				403
			);
			exit();
		}

		if ( ! isset( $_POST['area'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Processing form data without nonce verification. - Not verify nonce for password validate.
			wp_send_json(
				array(
					'success' => false,
					'message' => 'Area value is required!',
				),
				403
			);
			exit();
		}

		if ( ! isset( $_POST['post_id'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Processing form data without nonce verification. - Not verify nonce for password validate.
			wp_send_json(
				array(
					'success' => false,
					'message' => 'Post ID is required!',
				),
				403
			);
			exit();
		}
		$password = wp_unslash( $_POST['pss'] ); // phpcs:ignore -- not sanitize password because we allow all character.
		$area     = absint( $_POST['area'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Processing form data without nonce verification. - Not verify nonce for password validate.
		$post_id  = absint( $_POST['post_id'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Processing form data without nonce verification. - Not verify nonce for password validate.

		$post = get_post( $area );
		if ( empty( $post ) ) {
			wp_send_json(
				array(
					'success' => false,
					'message' => 'Post does not exist',
				),
				403
			);
			exit();
		}
		if ( $post->post_type !== self::POST_TYPE ) {
			wp_send_json(
				array(
					'success' => false,
					'message' => 'Post type is not valid',
				),
				403
			);
			exit();
		}

		$setting = get_post_meta( $area, self::SETTING_META_KEY, true );
		$params  = array(
			'password' => $password,
			'area'     => $area,
			'post_id'  => $post_id,
			'setting'  => $setting,
		);

		$is_valid_by_single = $this->validate_single_password( $params );
		$is_valid_password  = apply_filters( 'ppw_pcp_area_is_valid_password', $is_valid_by_single, $params );
		if ( $is_valid_password ) {
			wp_send_json(
				array(
					'reload'  => ! ppw_core_get_setting_type_bool_by_option_name( PPW_Constants::NO_RELOAD_PAGE, PPW_Constants::MISC_OPTIONS ),
					'success' => true,
					'message' => '',
					'content' => $this->massage_post_content( $area, $post->post_content ),
				),
				200
			);
			exit();
		}

		wp_send_json(
			array(
				'success' => false,
				'message' => get_theme_mod( 'ppwp_pcp_err_msg_text', PPW_Constants::DEFAULT_SHORTCODE_ERROR_MSG ),
			),
			400
		);
	}

	public function check_area_exist( $post ) {
		if ( empty( $post ) ) {
			return false;
		}

		if ( $post->post_type !== self::POST_TYPE ) {
			return false;
		}

		return true;
	}

	public function get_info_from_area_cookie( $area ) {
		$_cookie = wp_unslash( $_COOKIE );
		if ( empty( $_cookie ) ) {
			return array();
		}

		$cookie_keys = array_filter(
			array_keys( $_cookie ),
			function ( $key ) {
				return false !== strpos( $key, self::COOKIE_NAME );
			}
		);

		if ( 0 === count( $cookie_keys ) ) {
			return array();
		}

		$results = array();
		foreach ( $cookie_keys as $cookie_key ) {
			$info = str_replace( self::COOKIE_NAME, '', $cookie_key );
			$info = str_replace( COOKIEHASH, '', $info );
			$info = explode( 'p', $info );

			$password_id = absint( ppw_get_value( $info, 1, 0 ) );
			$cookie_area = absint( ppw_get_value( $info, 0, 0 ) );

			if ( $area !== $cookie_area ) {
				continue;
			}

			$results[ $password_id ] = array(
				'cookie_name'  => $cookie_key,
				'cookie_value' => $_cookie[ $cookie_key ],
			);
		}

		return $results;
	}

	public function validate_cookie( $area ) {
		$cookie_passwords = $this->get_info_from_area_cookie( $area );
		if ( empty( $cookie_passwords ) ) {
			return false;
		}

		$password_ids = array_keys( $cookie_passwords );
		$roles        = ppw_core_get_current_role();
		$params       = array(
			'post_id'                => $area,
			'roles'                  => $roles,
			'global_type'            => self::PASSWORD_GLOBAL_TYPE,
			'role_type'              => self::PASSWORD_ROLE_TYPE,
			'allow_to_check_expired' => false,
		);

		$password_infos = $this->password_repo->find_activated_passwords_by_ids(
			$password_ids,
			$params
		);

		if ( empty( $password_infos ) ) {
			return false;
		}

		foreach ( $password_infos as $password_info ) {
			if ( ! isset( $cookie_passwords[ $password_info->id ] ) ) {
				continue;
			}

			$cookie          = $cookie_passwords[ $password_info->id ];
			$hashed_password = $cookie['cookie_value'];

			if ( ppw_free_check_password( $password_info->password, $hashed_password ) ) {
				return true;
			}
		}

		return false;
	}

	public function maybe_unlock_content_by_cookie( $is_valid, $attrs ) {
		if ( $is_valid || ! isset( $attrs['section'] ) ) {
			return $is_valid;
		}

		$area    = $attrs['section'];
		$setting = get_post_meta( $area, self::SETTING_META_KEY, true );

		$post = get_post( $area );
		if ( ! $this->check_area_exist( $post ) ) {
			return $is_valid;
		}

		$params = array(
			'area'    => absint( $area ),
			'setting' => $setting,
		);

		$is_valid_cookie = $this->validate_cookie( $params['area'] );

		return apply_filters( 'ppw_pcp_valid_area_password', $is_valid_cookie, $params );
	}

	public function handle_admin_notices() {
		if ( ! function_exists( 'get_current_screen' ) ) {
			return;
		}

		$current_screen = get_current_screen();
		if ( ! isset( $current_screen->post_type ) ) {
			return;
		}
		if ( $current_screen->post_type !== self::POST_TYPE ) {
			return;
		}

		$button_contexts = array( 'ppwp-section' );
		if ( in_array( $current_screen->id, $button_contexts ) ) {
			$edit_url = admin_url( self::ADMIN_PATH );
			$button   = '<span style="float: right;">
						<a href="' . $edit_url . '">
							<button class="button button-primary">
								Go back to all sections
							</button>
						</a>
					</span>';
		} else {
			$button = '';
		}


		?>
		<div class="notice">
			<p>
				<div>
					<b>Password Protect WordPress: Section Protection</b>
					<?php echo $button;?>
				</div>
				<a target="_blank" rel="noopener noreferrer"
				   href="https://passwordprotectwp.com/docs/section-protection/?utm_source=user-website&utm_medium=section-protection-list&utm_campaign=ppwp-free">Protect section of your
					content</a> by creating section templates below. Add these sections to your content using
				auto-generated section shortcodes.
			</p>
		</div>
		<?php
	}
}
