*/
namespace RankMath\Schema;
use RankMath\Helper;
use RankMath\Traits\Hooker;
use RankMath\Traits\Shortcode;
use RankMath\Helpers\Str;
use RankMath\Helpers\Param;
defined( 'ABSPATH' ) || exit;
/**
 * Snippet_Shortcode class.
 */
class Snippet_Shortcode {
	use Hooker, Shortcode;
	/**
	 * Post object.
	 *
	 * @var object
	 */
	private $post;
	/**
	 * Schema data.
	 *
	 * @var array
	 */
	private $schema;
	/**
	 * The Constructor.
	 */
	public function __construct() {
		$this->add_shortcode( 'rank_math_rich_snippet', 'rich_snippet' );
		$this->add_shortcode( 'rank_math_review_snippet', 'rich_snippet' );
		if ( ! is_admin() ) {
			$this->filter( 'the_content', 'output_schema_in_content', 11 );
		}
		if ( ! function_exists( 'register_block_type' ) ) {
			return;
		}
		register_block_type(
			'rank-math/rich-snippet',
			[
				'render_callback' => [ $this, 'rich_snippet' ],
				'attributes'      => [
					'id'      => [
						'default' => '',
						'type'    => 'string',
					],
					'post_id' => [
						'default' => '',
						'type'    => 'integer',
					],
				],
			]
		);
	}
	/**
	 * Schema shortcode.
	 *
	 * @param  array $atts Optional. Shortcode arguments - currently only 'show'
	 *                     parameter, which is a comma-separated list of elements to show.
	 *
	 * @return string Shortcode output.
	 */
	public function rich_snippet( $atts ) {
		$atts = shortcode_atts(
			[
				'id'        => false,
				'post_id'   => Param::get( 'post_id' ) ? Param::get( 'post_id' ) : get_the_ID(),
				'className' => '',
			],
			$atts,
			'rank_math_rich_snippet'
		);
		if ( 'edit' === Param::get( 'context' ) ) {
			rank_math()->variables->setup();
		}
		$data = $this->get_schema_data( $atts['id'], $atts['post_id'] );
		if ( empty( $data ) || empty( $data['schema'] ) ) {
			return esc_html__( 'No schema found.', 'rank-math' );
		}
		$post    = get_post( $data['post_id'] );
		$schemas = ! empty( $atts['id'] ) ? [ $data['schema'] ] : $data['schema'];
		$html = '';
		foreach ( $schemas as $schema ) {
			$schema = $this->replace_variables( $schema, $post );
			$schema = $this->do_filter( 'schema/shortcode/filter_attributes', $schema, $atts );
			/**
			 * Change the Schema HTML output.
			 *
			 * @param string            $unsigned HTML output.
			 * @param array             $schema   Schema data.
			 * @param WP_Post           $post     The post instance.
			 * @param Snippet_Shortcode $this     Snippet_Shortcode instance.
			 */
			$html .= $this->do_filter( 'snippet/html', $this->get_snippet_content( $schema, $post, $atts ), $schema, $post, $this );
		}
		return $html;
	}
	/**
	 * Get Snippet content.
	 *
	 * @param  array   $schema Schema to replace.
	 * @param  WP_Post $post   Post schema attached to.
	 * @param  array   $atts   Optional. Shortcode arguments - currently only 'show'
	 *                     parameter, which is a comma-separated list of elements to show.
	 *
	 * @return string Shortcode output.
	 */
	public function get_snippet_content( $schema, $post, $atts ) {
		wp_enqueue_style( 'rank-math-review-snippet', rank_math()->assets() . 'css/rank-math-snippet.css', null, rank_math()->version );
		$type         = \strtolower( $schema['@type'] );
		$type         = preg_replace( '/[^a-z0-9_-]+/i', '', $type );
		$this->post   = $post;
		$this->schema = $schema;
		if ( in_array( $type, [ 'article', 'blogposting', 'newsarticle' ], true ) ) {
			return;
		}
		if ( Str::ends_with( 'event', $type ) ) {
			$type = 'event';
		}
		if ( 'resturant' === $type ) {
			$type = 'restaurant';
		}
		$class = ! empty( $atts['className'] ) ? $atts['className'] : '';
		ob_start();
		?>
			
				plugin_dir() . "includes/modules/schema/shortcode/$type.php";
				if ( file_exists( $file ) ) {
					include $file;
				}
				$this->do_action( 'snippet/after_schema_content', $this );
				?>
			
		schema;
		if ( isset( $array[ $field_id ] ) ) {
			if ( isset( $array[ $field_id ]['@type'] ) ) {
				unset( $array[ $field_id ]['@type'] );
			}
			return $array[ $field_id ];
		}
		foreach ( explode( '.', $field_id ) as $segment ) {
			if ( ! is_array( $array ) || ! array_key_exists( $segment, $array ) ) {
				return $default;
			}
			$array = $array[ $segment ];
		}
		return $array;
	}
	/**
	 * Get field.
	 *
	 * @param  string $title        Field title.
	 * @param  string $field_id     Field id to get value.
	 * @param  string $convert_date Convert date value to proper format.
	 * @param  mixed  $default      Default value.
	 */
	public function get_field( $title, $field_id, $convert_date = false, $default = null ) {
		$value = $this->get_field_value( $field_id, $default );
		if ( empty( $value ) ) {
			return;
		}
		if ( $convert_date ) {
			$value = Helper::convert_date( $value );
		}
		$this->output_field( $title, $value );
	}
	/**
	 * Get Opening hours data.
	 *
	 * @param string $field_id Field id to get value.
	 */
	public function get_opening_hours( $field_id ) {
		$opening_hours = $this->get_field_value( $field_id );
		if ( empty( $opening_hours ) ) {
			return;
		}
		if ( count( array_filter( array_keys( $opening_hours ), 'is_string' ) ) > 0 ) {
			$this->get_opening_hour( $opening_hours );
			return;
		}
		echo '';
		echo '' . esc_html__( 'Opening Hours', 'rank-math' ) . '
';
		foreach ( $opening_hours as $opening_hour ) {
			$this->get_opening_hour( $opening_hour );
		}
		echo '
';
	}
	/**
	 * Get Opening hours.
	 *
	 * @param array $opening_hour Opening hours data.
	 */
	public function get_opening_hour( $opening_hour ) {
		$labels = [
			'dayOfWeek' => esc_html__( 'Days', 'rank-math' ),
			'opens'     => esc_html__( 'Opening Time', 'rank-math' ),
			'closes'    => esc_html__( 'Closing Time', 'rank-math' ),
		];
		foreach ( $labels as $key => $label ) {
			if ( empty( $opening_hour[ $key ] ) ) {
				continue;
			}
			$this->output_field( $label, $opening_hour[ $key ] );
		}
	}
	/**
	 * Get field.
	 *
	 * @param string $title Field title.
	 * @param mixed  $value Field value.
	 */
	public function output_field( $title, $value ) {
		?>
		
			: 
			
		
		schema['name'] ) && ! isset( $this->schema['title'] ) ) {
			return;
		}
		$title = isset( $this->schema['title'] ) ? $this->schema['title'] : $this->schema['name'];
		$title = $title && '' !== $title ? $title : Helper::replace_vars( '%title%', $this->post );
		?>
		
		post );
		if ( $description && '' !== $description ) {
			$description = $this->get_field_value( $description );
		}
		$description = $description && '' !== $description ? $description : ( $excerpt ? $excerpt : Helper::get_post_meta( 'description', $this->post->ID ) );
		?>
		
		schema['image'] ) ) {
			return;
		}
		$image = Helper::get_thumbnail_with_fallback( $this->post->ID, 'medium' );
		if ( empty( $image ) ) {
			return;
		}
		?>
		
		get_field_value( $field_id );
		if ( empty( $rating ) ) {
			return;
		}
		$best_rating = (int) $this->get_field_value( 'review.reviewRating.bestRating', 5 );
		?>
		
			do_filter( 'review/text', esc_html__( 'Editor\'s Rating:', 'rank-math' ) ); // phpcs:ignore ?>
			
			
				
					', $best_rating ); // phpcs:ignore ?>
					
						', $best_rating ); // phpcs:ignore ?>
					
				 
			 
		 
		get_schemas();
		if ( empty( $schemas ) ) {
			return $content;
		}
		foreach ( $schemas as $schema ) {
			$location = $this->get_content_location( $schema );
			if ( false === $location || 'custom' === $location ) {
				continue;
			}
			$review = do_shortcode( '[rank_math_rich_snippet id="' . $schema['metadata']['shortcode'] . '"]' );
			if ( in_array( $location, [ 'top', 'both' ], true ) ) {
				$content = $review . $content;
			}
			if ( in_array( $location, [ 'bottom', 'both' ], true ) && $this->can_add_multi_page() ) {
				$content .= $review;
			}
		}
		return $content;
	}
	/**
	 * Get schema data by shortcode/post ID.
	 *
	 * @param  string $shortcode_id Schema shortcode ID.
	 * @param  string $post_id      Post ID.
	 * @return array
	 */
	private function get_schema_data( $shortcode_id, $post_id = false ) {
		if ( ! empty( $shortcode_id ) && is_string( $shortcode_id ) ) {
			return DB::get_schema_by_shortcode_id( $shortcode_id );
		}
		if ( ! $post_id ) {
			$post_id = Param::get( 'post_id' ) ? Param::get( 'post_id' ) : get_the_ID();
		}
		$data = DB::get_schemas( $post_id );
		return empty( $data ) ? false : [
			'post_id' => $post_id,
			'schema'  => $data,
		];
	}
	/**
	 * Function to replace variables used in Schema fields.
	 *
	 * @param  array   $schemas Schema to replace.
	 * @param  WP_Post $post    Post schema attached to.
	 * @return array
	 */
	private function replace_variables( $schemas, $post ) {
		if ( ! is_array( $schemas ) && ! is_object( $schemas ) ) {
			return [];
		}
		$new_schemas = [];
		foreach ( $schemas as $key => $schema ) {
			if ( 'metadata' === $key ) {
				continue;
			}
			if ( is_array( $schema ) ) {
				$new_schemas[ $key ] = $this->replace_variables( $schema, $post );
				continue;
			}
			$new_schemas[ $key ] = Str::contains( '%', $schema ) ? Helper::replace_seo_fields( $schema, $post ) : $schema;
		}
		return $new_schemas;
	}
	/**
	 * Check if we can inject the review in the content.
	 *
	 * @param array $schema Schema Data.
	 *
	 * @return boolean|string
	 */
	private function get_content_location( $schema ) {
		$location = ! empty( $schema['metadata']['shortcode'] ) && isset( $schema['metadata']['reviewLocation'] ) ? $schema['metadata']['reviewLocation'] : false;
		return $this->do_filter( 'snippet/review/location', $location );
	}
	/**
	 * Get schema data to show in the content.
	 *
	 * @return boolean|array
	 *
	 * @since 1.0.59
	 */
	private function get_schemas() {
		/**
		 * Filter: Allow disabling the review display.
		 *
		 * @param bool $return True to disable.
		 */
		if ( ! is_main_query() || ! in_the_loop() || $this->do_filter( 'snippet/review/hide_data', false ) ) {
			return false;
		}
		$schemas = $this->get_schema_data( false );
		if ( empty( $schemas ) ) {
			return false;
		}
		return array_filter(
			$schemas['schema'],
			function( $schema ) {
				return ! empty( $schema['metadata']['reviewLocation'] );
			}
		);
	}
	/**
	 * Check if we can add content if multipage.
	 *
	 * @return bool
	 */
	private function can_add_multi_page() {
		global $multipage, $numpages, $page;
		return ( ! $multipage || $page === $numpages );
	}
}