<?php
/**
 * Per item fields on the classic menus screen.
 *
 * @package MenuVerse
 */

namespace WPXero\MenuVerse\Admin;

use WPXero\MenuVerse\Capabilities;
use WPXero\MenuVerse\Frontend\Icon_Library;
use WPXero\MenuVerse\Menus\Item_Extras;
use WPXero\MenuVerse\Module\Mega_Menu\Panel_Post_Type;
use WPXero\MenuVerse\Plugin;

defined( 'ABSPATH' ) || exit;

/**
 * Adds MenuVerse settings to each item on Appearance to Menus.
 *
 * Attaching a panel belongs next to the menu item, not in a separate screen:
 * it is a property of that item, and WordPress already owns that form.
 */
final class Nav_Menu_Fields {

	/**
	 * Registers hooks.
	 *
	 * @return void
	 */
	public function boot() {
		add_action( 'wp_nav_menu_item_custom_fields', array( $this, 'render_fields' ), 10, 2 );
		add_action( 'wp_update_nav_menu_item', array( $this, 'save_fields' ), 10, 2 );
	}

	/**
	 * Prints the extra fields for one menu item.
	 *
	 * @param int    $item_id Menu item ID.
	 * @param object $item    Menu item object.
	 * @return void
	 */
	public function render_fields( $item_id, $item ) {
		if ( ! Capabilities::current_user_can_manage() ) {
			return;
		}

		$item_id = (int) $item_id;
		$extras  = Item_Extras::get( $item_id );
		$is_top  = empty( $item->menu_item_parent );
		$mega_on = Plugin::instance()->modules()->is_enabled( 'mega_menu' );

		echo '<div class="menuverse-item-fields"><p class="description menuverse-item-fields__title"><strong>MenuVerse</strong></p>';

		if ( $mega_on && $is_top ) {
			$this->render_mega_fields( $item_id, $extras );
		}

		$this->render_icon_field( $item_id, $extras );
		$this->render_badge_field( $item_id, $extras );
		$this->render_visibility_fields( $item_id, $extras );

		echo '</div>';
	}

	/**
	 * Prints the mega panel controls.
	 *
	 * @param int   $item_id Menu item ID.
	 * @param array $extras  Stored extras.
	 * @return void
	 */
	private function render_mega_fields( $item_id, array $extras ) {
		$panels = Panel_Post_Type::all();

		printf(
			'<p class="description description-wide"><label for="menuverse-mega-%1$d"><input type="checkbox" id="menuverse-mega-%1$d" name="menuverse_item[%1$d][mega]" value="1"%2$s> %3$s</label></p>',
			(int) $item_id,
			checked( ! empty( $extras['mega'] ), true, false ),
			esc_html__( 'Open a mega panel for this item', 'menuverse' )
		);

		printf(
			'<p class="description description-wide"><label for="menuverse-panel-%1$d">%2$s</label><select id="menuverse-panel-%1$d" name="menuverse_item[%1$d][panel_id]" class="widefat">',
			(int) $item_id,
			esc_html__( 'Panel', 'menuverse' )
		);

		printf(
			'<option value="0">%s</option><option value="-1">%s</option>',
			esc_html__( '— none —', 'menuverse' ),
			esc_html__( '+ Create a new panel', 'menuverse' )
		);

		foreach ( $panels as $panel ) {
			printf(
				'<option value="%1$d"%2$s>%3$s</option>',
				(int) $panel->ID,
				selected( (int) $extras['panel_id'], (int) $panel->ID, false ),
				esc_html( '' !== $panel->post_title ? $panel->post_title : __( '(untitled panel)', 'menuverse' ) )
			);
		}

		echo '</select>';

		if ( ! empty( $extras['panel_id'] ) && get_post( (int) $extras['panel_id'] ) ) {
			printf(
				' <a href="%1$s">%2$s</a>',
				esc_url( admin_url( 'admin.php?page=menuverse#/mega-menu/panel/' . (int) $extras['panel_id'] ) ),
				esc_html__( 'Edit this panel', 'menuverse' )
			);
		}

		echo '</p>';
	}

	/**
	 * Prints the icon selector.
	 *
	 * @param int   $item_id Menu item ID.
	 * @param array $extras  Stored extras.
	 * @return void
	 */
	private function render_icon_field( $item_id, array $extras ) {
		printf(
			'<p class="description description-wide"><label for="menuverse-icon-%1$d">%2$s</label><select id="menuverse-icon-%1$d" name="menuverse_item[%1$d][icon]" class="widefat"><option value="">%3$s</option>',
			(int) $item_id,
			esc_html__( 'Icon', 'menuverse' ),
			esc_html__( '— none —', 'menuverse' )
		);

		foreach ( Icon_Library::selectable() as $slug => $icon ) {
			printf(
				'<option value="%1$s"%2$s>%3$s</option>',
				esc_attr( $slug ),
				selected( $extras['icon'], $slug, false ),
				esc_html( isset( $icon['label'] ) ? $icon['label'] : $slug )
			);
		}

		echo '</select></p>';
	}

	/**
	 * Prints the badge field.
	 *
	 * @param int   $item_id Menu item ID.
	 * @param array $extras  Stored extras.
	 * @return void
	 */
	private function render_badge_field( $item_id, array $extras ) {
		printf(
			'<p class="description description-wide"><label for="menuverse-badge-%1$d">%2$s</label><input type="text" id="menuverse-badge-%1$d" name="menuverse_item[%1$d][badge]" class="widefat" maxlength="32" value="%3$s"></p>',
			(int) $item_id,
			esc_html__( 'Badge', 'menuverse' ),
			esc_attr( $extras['badge'] )
		);
	}

	/**
	 * Prints the visibility checkboxes.
	 *
	 * @param int   $item_id Menu item ID.
	 * @param array $extras  Stored extras.
	 * @return void
	 */
	private function render_visibility_fields( $item_id, array $extras ) {
		printf(
			'<p class="description description-wide"><label><input type="checkbox" name="menuverse_item[%1$d][hide_mobile]" value="1"%2$s> %3$s</label><br><label><input type="checkbox" name="menuverse_item[%1$d][hide_desktop]" value="1"%4$s> %5$s</label></p>',
			(int) $item_id,
			checked( ! empty( $extras['hide_mobile'] ), true, false ),
			esc_html__( 'Hide on mobile', 'menuverse' ),
			checked( ! empty( $extras['hide_desktop'] ), true, false ),
			esc_html__( 'Hide on desktop', 'menuverse' )
		);
	}

	/**
	 * Saves the extra fields for one menu item.
	 *
	 * @param int $menu_id Menu term ID.
	 * @param int $item_id Menu item ID.
	 * @return void
	 */
	public function save_fields( $menu_id, $item_id ) {
		if ( ! Capabilities::current_user_can_manage() ) {
			return;
		}

		// The menus screen posts its own nonce; bail unless this save came
		// from that form.
		if ( ! isset( $_POST['update-nav-menu-nonce'] ) || ! wp_verify_nonce( sanitize_key( wp_unslash( $_POST['update-nav-menu-nonce'] ) ), 'update-nav_menu' ) ) {
			return;
		}

		if ( ! isset( $_POST['menuverse_item'] ) || ! is_array( $_POST['menuverse_item'] ) ) {
			return;
		}

		$item_id = (int) $item_id;
		$raw     = wp_unslash( $_POST['menuverse_item'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- sanitized against the extras schema below.

		if ( ! isset( $raw[ $item_id ] ) || ! is_array( $raw[ $item_id ] ) ) {
			return;
		}

		$fields = $raw[ $item_id ];

		$extras = array(
			'icon'         => isset( $fields['icon'] ) ? (string) $fields['icon'] : '',
			'badge'        => isset( $fields['badge'] ) ? (string) $fields['badge'] : '',
			'mega'         => ! empty( $fields['mega'] ),
			'hide_mobile'  => ! empty( $fields['hide_mobile'] ),
			'hide_desktop' => ! empty( $fields['hide_desktop'] ),
			'panel_id'     => isset( $fields['panel_id'] ) ? (int) $fields['panel_id'] : 0,
		);

		if ( -1 === $extras['panel_id'] ) {
			$extras['panel_id'] = $this->create_panel( $item_id );
		}

		Item_Extras::update( $item_id, $extras );

		Plugin::instance()->menu_sources()->invalidate( (int) $menu_id );
	}

	/**
	 * Creates an empty panel named after a menu item.
	 *
	 * @param int $item_id Menu item ID.
	 * @return int Panel post ID, zero on failure.
	 */
	private function create_panel( $item_id ) {
		$item  = get_post( $item_id );
		$title = $item instanceof \WP_Post && '' !== $item->post_title
			? $item->post_title
			: __( 'Mega panel', 'menuverse' );

		$panel_id = wp_insert_post(
			array(
				'post_type'   => Panel_Post_Type::POST_TYPE,
				'post_status' => 'publish',
				'post_title'  => $title,
			),
			true
		);

		return is_wp_error( $panel_id ) ? 0 : (int) $panel_id;
	}
}
