<?php

namespace Simple_History\Loggers;

use Simple_History\Helpers;

/**
 * Logs WordPress menu edits
 */
class Menu_Logger extends Logger {
	/** @var string Logger slug */
	public $slug = 'SimpleMenuLogger';

	/**
	 * Get array with information about this logger
	 *
	 * @return array
	 */
	public function get_info() {

		return array(
			'name'        => __( 'Menu Logger', 'simple-history' ),
			'description' => __( 'Logs menu edits', 'simple-history' ),
			'capability'  => 'edit_theme_options',
			'messages'    => array(
				'created_menu'          => __( 'Created menu "{menu_name}"', 'simple-history' ),
				'edited_menu'           => __( 'Edited menu "{menu_name}"', 'simple-history' ),
				'deleted_menu'          => __( 'Deleted menu "{menu_name}"', 'simple-history' ),
				'edited_menu_item'      => __( 'Edited a menu item', 'simple-history' ),
				'edited_menu_locations' => __( 'Updated menu locations', 'simple-history' ),
			),
			'labels'      => array(
				'search' => array(
					'label'     => _x( 'Menus', 'Menu logger: search', 'simple-history' ),
					'label_all' => _x( 'All menu activity', 'Menu updates logger: search', 'simple-history' ),
					'options'   => array(
						_x( 'Created menus', 'Menu updates logger: search', 'simple-history' ) => array(
							'created_menu',
						),
						_x( 'Edited menus', 'Menu updates logger: search', 'simple-history' ) => array(
							'edited_menu',
							'edited_menu_item',
							'edited_menu_locations',
						),
						_x( 'Deleted menus', 'Menu updates logger: search', 'simple-history' ) => array(
							'deleted_menu',
						),
					),
				),
			),
		);
	}

	/**
	 * Called when logger is loaded.
	 */
	public function loaded() {
		/*
		 * Fires after a navigation menu has been successfully deleted.
		 *
		 * @since 3.0.0
		 *
		 * @param int $term_id ID of the deleted menu.
		*/
		add_action( 'load-nav-menus.php', array( $this, 'on_load_nav_menus_page_detect_delete' ) );

		/*
		 * Fires after a navigation menu is successfully created.
		 *
		 * @since 3.0.0
		 *
		 * @param int   $term_id   ID of the new menu.
		 * @param array $menu_data An array of menu data.
		*/
		add_action( 'wp_create_nav_menu', array( $this, 'on_wp_create_nav_menu' ), 10, 2 );

		// This is fired when adding nav items in the editor, not at save, so not
		// good to log because user might not end up saving the changes
		// add_action("wp_update_nav_menu_item", array($this, "on_wp_update_nav_menu_item"), 10, 3 );
		// Fired before "wp_update_nav_menu" below, to remember menu layout before it's updated
		// so we can't detect changes.
		add_action( 'load-nav-menus.php', array( $this, 'on_load_nav_menus_page_detect_update' ) );

		// Detect menu location change in "manage locations".
		add_action( 'load-nav-menus.php', array( $this, 'on_load_nav_menus_page_detect_locations_update' ) );

		add_filter( 'simple_history/categories_logger/skip_taxonomies', array( $this, 'on_categories_logger_skip_taxonomy' ) );
	}

	/**
	 * Add taxonomy "nav_menu" to list of categories to not log changes to,
	 * because menus are stored in this taxonomy,
	 * and the menu logger will log menu changes,
	 * so don't let categories logger log this
	 * or there will be duplicates.
	 *
	 * @param mixed $taxonomies_to_skip Array with taxonomies to skip.
	 * @return array
	 */
	public function on_categories_logger_skip_taxonomy( $taxonomies_to_skip ) {
		$taxonomies_to_skip[] = 'nav_menu';
		return $taxonomies_to_skip;
	}

	/**
	 * Can't use action "wp_delete_nav_menu" because
	 * it's fired after menu is deleted, so we don't have the name in this action
	 */
	public function on_load_nav_menus_page_detect_delete() {
		// Check that needed vars are set.
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		if ( ! isset( $_REQUEST['menu'], $_REQUEST['action'] ) ) {
			return;
		}

		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		if ( $_REQUEST['action'] !== 'delete' ) {
			return;
		}

		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		$menu_id = sanitize_text_field( wp_unslash( $_REQUEST['menu'] ) );
		if ( ! is_nav_menu( $menu_id ) ) {
			return;
		}

		$menu = wp_get_nav_menu_object( $menu_id );

		$this->info_message(
			'deleted_menu',
			array(
				'menu_term_id' => $menu_id,
				'menu_name'    => $menu->name,
			)
		);
	}

	/**
	 * Detect menu being created
	 *
	 * @param int   $term_id ID of the new menu.
	 * @param array $menu_data An array of menu data.
	 */
	public function on_wp_create_nav_menu( $term_id, $menu_data ) {

		$menu = wp_get_nav_menu_object( $term_id );

		if ( ! $menu ) {
			return;
		}

		$this->info_message(
			'created_menu',
			array(
				'term_id'   => $term_id,
				'menu_name' => $menu->name,
			)
		);
	}

	/**
	 * Detect menu being saved
	 */
	public function on_load_nav_menus_page_detect_update() {
		/*
		This is the data to be saved
		$_REQUEST:
		Array
		(
			[action] => update
			[menu] => 25
			[menu-name] => Main menu edit
			[menu-item-title] => Array
				(
					[25243] => My new page edited
					[25244] => My new page
					[25245] => This is my new page. How does it look in the logs? <h1>Hej!</h1>
					[25264] => This page have revisions
					[25265] => Lorem ipsum dolor sit amet
				)
			[menu-locations] => Array
				(
					[primary] => 25
				)
		)
		*/

		// Check that needed vars are set.
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		if ( ! isset( $_REQUEST['menu'], $_REQUEST['action'], $_REQUEST['menu-name'] ) ) {
			return;
		}

		// Only go on for update action.
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		if ( $_REQUEST['action'] !== 'update' ) {
			return;
		}

		// Make sure we got the id of a menu.
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		$menu_id = sanitize_text_field( wp_unslash( $_REQUEST['menu'] ) );
		if ( ! is_nav_menu( $menu_id ) ) {
			return;
		}

		// Get saved menu. May be empty if this is the first time we save the menu.
		$arr_prev_menu_items = wp_get_nav_menu_items( $menu_id );

		// Compare new items to be saved with old version.
		$old_ids = wp_list_pluck( $arr_prev_menu_items, 'db_id' );
		// phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
		$new_ids = array_values( isset( $_POST['menu-item-db-id'] ) ? (array) wp_unslash( $_POST['menu-item-db-id'] ) : array() );

		// Get ids of added and removed post ids.
		$arr_removed = array_diff( $old_ids, $new_ids );
		$arr_added   = array_diff( $new_ids, $old_ids );

		$this->info_message(
			'edited_menu',
			array(
				'menu_id'            => $menu_id,
				// phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotValidated
				'menu_name'          => sanitize_text_field( wp_unslash( $_POST['menu-name'] ) ),
				'menu_items_added'   => count( $arr_added ),
				'menu_items_removed' => count( $arr_removed ),
			)
		);
	}

	/**
	 * Get detailed output
	 *
	 * @param object $row Log row.
	 */
	public function get_log_row_details_output( $row ) {

		$context     = $row->context;
		$message_key = $context['_message_key'];
		$output      = '';

		if ( $message_key === 'edited_menu' && ( ! empty( $context['menu_items_added'] ) || ! empty( $context['menu_items_removed'] ) ) ) {
			$output .= '<p>';
			$output .= '<span class="SimpleHistoryLogitem__inlineDivided">';
			$output .= sprintf(
					// translators: Number of menu items added.
				_nx( '%1$s menu item added', '%1$s menu items added', $context['menu_items_added'], 'menu logger', 'simple-history' ),
				esc_attr( $context['menu_items_added'] )
			);
			$output .= '</span> ';
			$output .= '<span class="SimpleHistoryLogitem__inlineDivided">';
			$output .= sprintf(
					// translators: Number of menu items removed.
				_nx( '%1$s menu item removed', '%1$s menu items removed', $context['menu_items_removed'], 'menu logger', 'simple-history' ),
				esc_attr( $context['menu_items_removed'] )
			);
			$output .= '</span> ';
			$output .= '</p>';
		}

		return $output;
	}

	/**
	 * Log updates to theme menu locations
	 */
	public function on_load_nav_menus_page_detect_locations_update() {

		// Check that needed vars are set.
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		if ( ! isset( $_REQUEST['menu'], $_REQUEST['action'] ) ) {
			return;
		}

		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		if ( $_REQUEST['action'] !== 'locations' ) {
			return;
		}

		// phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotValidated, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
		$menu_locations = (array) wp_unslash( $_POST['menu-locations'] );

		$this->info_message(
			'edited_menu_locations',
			array(
				'menu_locations' => Helpers::json_encode( $menu_locations ),
			)
		);
	}
}
