<?php
/**
 * Per menu item MenuVerse data.
 *
 * @package MenuVerse
 */

namespace WPXero\MenuVerse\Menus;

use WPXero\MenuVerse\Settings\Schema;
use WPXero\MenuVerse\Settings\Schema_Sanitizer;

defined( 'ABSPATH' ) || exit;

/**
 * Reads and writes the extra data MenuVerse attaches to a menu item.
 *
 * Classic menu items keep every extra in a single post meta row rather than
 * one row per setting, so a large menu does not multiply meta queries.
 */
final class Item_Extras {

	/**
	 * Meta key holding the extras array for a classic menu item.
	 *
	 * @var string
	 */
	const META_KEY = '_menuverse_item';

	/**
	 * Unfiltered schema definition, built once per request.
	 *
	 * `get()` runs for every item of every menu, so the literal below is built
	 * once and the filter still runs on every call — memoizing the filtered
	 * result would silently ignore a filter added after the first item.
	 *
	 * @var array|null
	 */
	private static $base_schema = null;

	/**
	 * Returns the schema describing per item extras.
	 *
	 * @return array
	 */
	public static function schema() {
		if ( null !== self::$base_schema ) {
			/** This filter is documented in includes/menus/class-item-extras.php */
			return apply_filters( 'menuverse_item_extras_schema', self::$base_schema );
		}

		$schema = array(
			'type'       => 'object',
			'properties' => array(
				'icon'         => array(
					'type'    => 'string',
					'format'  => 'icon',
					'default' => '',
				),
				'badge'        => array(
					'type'      => 'string',
					'default'   => '',
					'maxLength' => 32,
				),
				'mega'         => array(
					'type'    => 'boolean',
					'default' => false,
				),
				'panel_id'     => array(
					'type'    => 'integer',
					'default' => 0,
					'minimum' => 0,
				),
				'hide_mobile'  => array(
					'type'    => 'boolean',
					'default' => false,
				),
				'hide_desktop' => array(
					'type'    => 'boolean',
					'default' => false,
				),
			),
		);

		/**
		 * Filters the per menu item extras schema.
		 *
		 * @since 1.0.0
		 *
		 * @param array $schema Schema definition.
		 */
		self::$base_schema = $schema;

		return apply_filters( 'menuverse_item_extras_schema', $schema );
	}

	/**
	 * Returns the default extras array.
	 *
	 * @return array
	 */
	public static function defaults() {
		return Schema::defaults( self::schema() );
	}

	/**
	 * Reads extras for a classic menu item.
	 *
	 * @param int $item_id Menu item post ID.
	 * @return array
	 */
	public static function get( $item_id ) {
		$stored = get_post_meta( (int) $item_id, self::META_KEY, true );

		return Schema_Sanitizer::sanitize( is_array( $stored ) ? $stored : array(), self::schema() );
	}

	/**
	 * Writes extras for a classic menu item.
	 *
	 * @param int   $item_id Menu item post ID.
	 * @param array $extras  Extras to store.
	 * @return array Stored extras.
	 */
	public static function update( $item_id, array $extras ) {
		$item_id = (int) $item_id;
		$merged  = array_merge( self::get( $item_id ), $extras );
		$cleaned = Schema_Sanitizer::sanitize( $merged, self::schema() );

		if ( self::defaults() === $cleaned ) {
			delete_post_meta( $item_id, self::META_KEY );
		} else {
			update_post_meta( $item_id, self::META_KEY, $cleaned );
		}

		return $cleaned;
	}

	/**
	 * Normalizes an arbitrary extras array, used by block sourced items.
	 *
	 * @param mixed $raw Raw extras value.
	 * @return array
	 */
	public static function normalize( $raw ) {
		return Schema_Sanitizer::sanitize( is_array( $raw ) ? $raw : array(), self::schema() );
	}
}
