<?php
// phpcs:ignoreFile
/**
 * Facebook for WooCommerce.
 */

namespace WooCommerce\Facebook\Framework;

defined( 'ABSPATH' ) or exit;

/**
 * Admin Message Handler Class
 *
 * This class provides a reusable wordpress admin messaging facility for setting
 * and displaying messages and error messages across admin page requests without
 * resorting to passing the messages as query vars.
 *
 * ## Usage
 *
 * To use simple instantiate the class then set one or more messages:
 *
 * `
 * $admin_message_handler = new WP_Admin_Message_Handler( __FILE__ );
 * $admin_message_handler->add_message( 'Hello World!' );
 * `
 *
 * Then show the messages wherever you need, either with the built-in method
 * or by writing your own:
 *
 * `$admin_message_handler->show_messages();`
 *
 * @version 1.0.1
 */
class AdminMessageHandler {


	/** transient message prefix */
	const MESSAGE_TRANSIENT_PREFIX = '_wp_admin_message_';

	/** the message id GET name */
	const MESSAGE_ID_GET_NAME = 'wpamhid';


	/** @var string unique message identifier, defaults to __FILE__ unless otherwise set */
	private $message_id;

	/** @var array array of messages */
	private $messages = [];

	/** @var array array of error messages */
	private $errors = [];

	/** @var array array of warning messages */
	private $warnings = [];

	/** @var array array of info messages */
	private $infos = [];


	/**
	 * Construct and initialize the admin message handler class
	 *
	 * @since 1.0.0
	 * @param string $message_id optional message id.  Best practice is to set
	 *        this to a unique identifier based on the client plugin, such as __FILE__
	 */
	public function __construct( $message_id = null ) {
		$this->message_id = $message_id;
		// load any available messages
		$this->load_messages();
		add_filter( 'wp_redirect', array( $this, 'redirect' ), 1, 2 );
	}


	/**
	 * Persist messages
	 *
	 * @since 1.0.0
	 * @return boolean true if any messages were set, false otherwise
	 */
	public function set_messages() {
		// any messages to persist?
		if ( $this->message_count() > 0 || $this->info_count() > 0 || $this->warning_count() > 0 || $this->error_count() > 0 ) {
			set_transient(
				self::MESSAGE_TRANSIENT_PREFIX . $this->get_message_id(),
				array(
					'errors'   => $this->errors,
					'warnings' => $this->warnings,
					'infos'    => $this->infos,
					'messages' => $this->messages,
				),
				60 * 60
			);
			return true;
		}
		return false;
	}


	/**
	 * Loads messages
	 *
	 * @since 1.0.0
	 */
	public function load_messages() {
		if ( isset( $_GET[ self::MESSAGE_ID_GET_NAME ] ) && $this->get_message_id() == $_GET[ self::MESSAGE_ID_GET_NAME ] ) {
			$memo = get_transient( self::MESSAGE_TRANSIENT_PREFIX . $_GET[ self::MESSAGE_ID_GET_NAME ] );
			if ( isset( $memo['errors'] ) )   $this->errors   = $memo['errors'];
			if ( isset( $memo['warnings'] ) ) $this->warnings = $memo['warnings'];
			if ( isset( $memo['infos'] ) )    $this->infos    = $memo['infos'];
			if ( isset( $memo['messages'] ) ) $this->messages = $memo['messages'];
			$this->clear_messages( $_GET[ self::MESSAGE_ID_GET_NAME ] );
		}
	}


	/**
	 * Clear messages and errors
	 *
	 * @since 1.0.0
	 * @param string $id the messages identifier
	 */
	public function clear_messages( $id ) {
		delete_transient( self::MESSAGE_TRANSIENT_PREFIX . $id );
	}


	/**
	 * Add an error message.
	 *
	 * @since 1.0.0
	 * @param string $error error message
	 */
	public function add_error( $error ) {
		$this->errors[] = $error;
	}


	/**
	 * Adds a warning message.
	 *
	 * @since 5.1.0
	 *
	 * @param string $message warning message to add
	 */
	public function add_warning( $message ) {
		$this->warnings[] = $message;
	}


	/**
	 * Adds a info message.
	 *
	 * @since 5.1.0
	 *
	 * @param string $message info message to add
	 */
	public function add_info( $message ) {
		$this->infos[] = $message;
	}


	/**
	 * Add a message.
	 *
	 * @since 1.0.0
	 * @param string $message the message to add
	 */
	public function add_message( $message ) {
		$this->messages[] = $message;
	}


	/**
	 * Get error count.
	 *
	 * @since 1.0.0
	 * @return int error message count
	 */
	public function error_count() {
		return sizeof( $this->errors );
	}


	/**
	 * Gets the warning message count.
	 *
	 * @since 5.1.0
	 *
	 * @return int warning message count
	 */
	public function warning_count() {
		return sizeof( $this->warnings );
	}


	/**
	 * Gets the info message count.
	 *
	 * @since 5.1.0
	 *
	 * @return int info message count
	 */
	public function info_count() {
		return sizeof( $this->infos );
	}


	/**
	 * Get message count.
	 *
	 * @since 1.0.0
	 * @return int message count
	 */
	public function message_count() {
		return sizeof( $this->messages );
	}


	/**
	 * Get error messages
	 *
	 * @since 1.0.0
	 * @return array of error message strings
	 */
	public function get_errors() {
		return $this->errors;
	}


	/**
	 * Get an error message
	 *
	 * @since 1.0.0
	 * @param int $index the error index
	 * @return string the error message
	 */
	public function get_error( $index ) {
		return isset( $this->errors[ $index ] ) ? $this->errors[ $index ] : '';
	}


	/**
	 * Gets all warning messages.
	 *
	 * @since 5.1.0
	 *
	 * @return array
	 */
	public function get_warnings() {
		return $this->warnings;
	}


	/**
	 * Gets a specific warning message.
	 *
	 * @since 5.1.0
	 *
	 * @param int $index warning message index
	 * @return string
	 */
	public function get_warning( $index ) {
		return isset( $this->warnings[ $index ] ) ? $this->warnings[ $index ] : '';
	}


	/**
	 * Gets all info messages.
	 *
	 * @since 5.1.0
	 *
	 * @return array
	 */
	public function get_infos() {
		return $this->infos;
	}


	/**
	 * Gets a specific info message.
	 *
	 * @since 5.0.0
	 *
	 * @param int $index info message index
	 * @return string
	 */
	public function get_info( $index ) {
		return isset( $this->infos[ $index ] ) ? $this->infos[ $index ] : '';
	}


	/**
	 * Get messages
	 *
	 * @since 1.0.0
	 * @return array of message strings
	 */
	public function get_messages() {
		return $this->messages;
	}


	/**
	 * Get a message
	 *
	 * @since 1.0.0
	 * @param int $index the message index
	 * @return string the message
	 */
	public function get_message( $index ) {
		return isset( $this->messages[ $index ] ) ? $this->messages[ $index ] : '';
	}


	/**
	 * Render the errors and messages.
	 *
	 * @since 1.0.0
	 * @param array $params {
	 *     Optional parameters.
	 *
	 *     @type array $capabilities Any user capabilities to check if the user is allowed to view the messages,
	 *                               default: `manage_woocommerce`
	 * }
	 */
	public function show_messages( $params = [] ) {
		$params = wp_parse_args( $params, array(
			'capabilities' => array(
				'manage_woocommerce',
			),
		) );
		$check_user_capabilities = [];
		// check if user has at least one capability that allows to see messages
		foreach ( $params['capabilities'] as $capability ) {
			$check_user_capabilities[] = current_user_can( $capability );
		}
		// bail out if user has no minimum capabilities to see messages
		if ( ! in_array( true, $check_user_capabilities, true ) ) {
			return;
		}
		$output = '';
		if ( $this->error_count() > 0 ) {
			$output .= '<div id="wp-admin-message-handler-error" class="notice-error notice"><ul><li><strong>' . implode( '</strong></li><li><strong>', $this->get_errors() ) . '</strong></li></ul></div>';
		}
		if ( $this->warning_count() > 0 ) {
			$output .= '<div id="wp-admin-message-handler-warning"  class="notice-warning notice"><ul><li><strong>' . implode( '</strong></li><li><strong>', $this->get_warnings() ) . '</strong></li></ul></div>';
		}
		if ( $this->info_count() > 0 ) {
			$output .= '<div id="wp-admin-message-handler-warning"  class="notice-info notice"><ul><li><strong>' . implode( '</strong></li><li><strong>', $this->get_infos() ) . '</strong></li></ul></div>';
		}
		if ( $this->message_count() > 0 ) {
			$output .= '<div id="wp-admin-message-handler-message"  class="notice-success notice"><ul><li><strong>' . implode( '</strong></li><li><strong>', $this->get_messages() ) . '</strong></li></ul></div>';
		}
		echo wp_kses_post( $output );
	}


	/**
	 * Redirection hook which persists messages into session data.
	 *
	 * @since 1.0.0
	 * @param string $location the URL to redirect to
	 * @param int $status the http status
	 * @return string the URL to redirect to
	 */
	public function redirect( $location, $status ) {
		// add the admin message id param to the
		if ( $this->set_messages() ) {
			$location = add_query_arg( self::MESSAGE_ID_GET_NAME, $this->get_message_id(), $location );
		}
		return $location;
	}


	/**
	 * Generate a unique id to identify the messages
	 *
	 * @since 1.0.0
	 * @return string unique identifier
	 */
	protected function get_message_id() {
		if ( ! isset( $this->message_id ) ) $this->message_id = __FILE__;
		return wp_create_nonce( $this->message_id );
	}
}
