<?php
/**
 * Manages block editor registration and configuration.
 *
 * @package Tasty_Roundups
 */

namespace Tasty_Roundups;

use Tasty\Framework\Utils\Vars;
use WP_REST_Request;

/**
 * Manages block editor registration and configuration.
 */
class Block_Editor {

	/**
	 * Register the scripts and block type.
	 */
	public static function action_init_register() {
		if ( ! function_exists( 'register_block_type' ) ) {
			return;
		}

		wp_register_style(
			'tasty-roundups-legacy-block',
			Utils::plugin_assets_url() . 'legacy-tasty-roundups-block.css',
			array(),
			TASTY_ROUNDUPS_PLUGIN_VERSION
		);
		register_block_type(
			'tasty-roundups/container',
			array(
				'render_callback'  => '\Tasty_Roundups\Blocks\Legacy_Blocks::render_container_block',
				'provides_context' => array( 'tasty-roundups/displayNumbers' => 'displayNumbers' ),
			)
		);
		register_block_type(
			'tasty-roundups/item',
			array(
				'render_callback' => '\Tasty_Roundups\Blocks\Legacy_Blocks::render_item_block',
				'uses_context'    => array( 'tasty-roundups/displayNumbers' ),
			)
		);

		wp_register_style(
			'tasty-roundups-block',
			Utils::plugin_assets_url() . 'tasty-roundups-block.css',
			array(),
			TASTY_ROUNDUPS_PLUGIN_VERSION
		);

		register_block_type(
			'tasty-roundups/parent',
			array(
				'render_callback'  => function ( $attributes, $content, $block ) {
					$block = new Blocks\Container_Block( $attributes, $content, $block );
					return $block->render();
				},
				'provides_context' => array(
					'tasty-roundups/displayNumbers'     => 'displayNumbers',
					'tasty-roundups/imageShape'         => 'imageShape',
					'tasty-roundups/customImageShape'   => 'customImageShape',
					'tasty-roundups/imagePosition'      => 'imagePosition',
					'tasty-roundups/buttonStyle'        => 'buttonStyle',
					'tasty-roundups/disableImage'       => 'disableImage',
					'tasty-roundups/disableDescription' => 'disableDescription',
					'tasty-roundups/disableButton'      => 'disableButton',
					'tasty-roundups/disableComments'    => 'disableComments',
					'tasty-roundups/disableRating'      => 'disableRating',
				),
			)
		);
		register_block_type(
			'tasty-roundups/child',
			array(
				'render_callback' => function ( $attributes, $content, $block ) {
					$block = new Blocks\Item_Block( $attributes, $content, $block );
					return $block->render();
				},
				'uses_context'    => array(
					'tasty-roundups/displayNumbers',
					'tasty-roundups/imageShape',
					'tasty-roundups/customImageShape',
					'tasty-roundups/imagePosition',
					'tasty-roundups/buttonStyle',
					'tasty-roundups/disableImage',
					'tasty-roundups/disableDescription',
					'tasty-roundups/disableButton',
					'tasty-roundups/disableComments',
					'tasty-roundups/disableRating',
				),
			)
		);
	}

	/**
	 * Retrieve a description to use when prepopulating a roundup item.
	 *
	 * @param int $post_id The post ID.
	 * @return string A description.
	 */
	public static function get_default_description( $post_id ) {
		$post = get_post( $post_id );

		// Respect existing use of the filter.
		$has_filter = has_filter( 'excerpt_more', '__return_empty_string' );
		// Add the filter if one doesn't already exist.
		if ( ! $has_filter ) {
			add_filter( 'excerpt_more', '__return_empty_string' );
		}

		$description = get_the_excerpt( $post_id );

		// If it didn't have the filter before, we want to remove it again.
		if ( ! $has_filter ) {
			remove_filter( 'excerpt_more', '__return_empty_string' );
		}

		// An excerpt was manually set on the post and should be used as the description.
		if ( ! empty( $post->post_excerpt ) ) {
			return $description;
		}

		// If WP Recipe Maker is available, look for a recipe block or the recipe's summary block.
		if ( has_block( 'wp-recipe-maker/recipe', $post ) || has_block( 'wp-recipe-maker/recipe-part', $post ) ) {
			$blocks = parse_blocks( $post->post_content );
			$blocks = self::flatten_blocks( $blocks );

			foreach ( $blocks as $block ) {
				if ( 'wp-recipe-maker/recipe' === $block['blockName'] ) {
					$recipe      = get_post( $block['attrs']['id'] );
					$description = $recipe ? wp_strip_all_tags( $recipe->post_content ) : '';
					break;
				} elseif ( 'wp-recipe-maker/recipe-part' === $block['blockName'] && isset( $block['attrs']['part'] ) && 'recipe-summary' === $block['attrs']['part'] ) {
					$recipe      = get_post( $block['attrs']['id'] );
					$description = $recipe ? wp_strip_all_tags( $recipe->post_content ) : '';
					break;
				}
			}
		}

		// If Mediavine Create is available, look for the recipe's description.
		if ( class_exists( '\Mediavine\Create\Plugin' ) && function_exists( 'mv_get_post_creations' ) ) {
			$mv_creations = mv_get_post_creations( $post_id );

			if ( 0 < count( $mv_creations ) ) {
				$mv_creation = mv_create_get_creation( $mv_creations[0] );

				if ( ! empty( $mv_creation ) && '' !== $mv_creation->description ) {
					$description = wp_strip_all_tags( $mv_creation->description );
				}
			}
		}

		// If Tasty Recipes is available, use an available description.
		if ( class_exists( '\Tasty_Recipes' ) ) {
			$recipes = \Tasty_Recipes::get_recipes_for_post( $post->ID );
			$recipe  = reset( $recipes );

			if ( $recipe ) {
				$recipe_description = $recipe->get_description();

				if ( '' !== trim( $recipe_description ) ) {
					return $recipe_description;
				}
			}
		}

		return $description;
	}

	/**
	 * Reduce a list of blocks and their inner blocks to a flat
	 * list of all blocks.
	 *
	 * @param array $blocks A list of WordPress blocks.
	 * @return array A flattened list of WordPress blocks.
	 */
	private static function flatten_blocks( $blocks ) {
		$flattened_blocks = array();

		foreach ( $blocks as $block ) {
			$flattened_blocks[] = $block;

			if ( 0 < count( $block['innerBlocks'] ) ) {
				$inner_blocks = self::flatten_blocks( $block['innerBlocks'] );

				$flattened_blocks = array_merge( $flattened_blocks, $inner_blocks );
			}
		}

		return $flattened_blocks;
	}

	/**
	 * Register the extra REST API fields.
	 */
	public static function action_rest_api_init() {
		register_rest_field(
			'search-result',
			'tastyRoundupsData',
			array(
				'get_callback' => function ( $result ) {
					$data = array();
					if ( 'post' === $result['type'] ) {
						$data = array(
							'description' => '',
							'mediaId'     => '',
							'mediaUrl'    => '',
							'mediaType'   => '',
							'postId'      => $result['id'],
							'comments'    => array(
								'open'  => comments_open( $result['id'] ),
								'count' => (int) get_comments_number( $result['id'] ),
							),
						);

						$data['description'] = \Tasty_Roundups\Block_Editor::get_default_description( $result['id'] );

						$thumbnail_id = get_post_thumbnail_id( $result['id'] );
						if ( $thumbnail_id ) {
							$image_url = wp_get_attachment_image_url( $thumbnail_id, 'large' );
							if ( $image_url ) {
								$data['mediaId']   = $thumbnail_id;
								$data['mediaUrl']  = $image_url;
								$data['mediaType'] = 'image';
							}
						}

						if ( ! empty( $result['id'] ) && defined( 'TASTY_RECIPES_PLUGIN_VERSION' ) && class_exists( '\Tasty_Recipes' ) ) {
							$has_recipe = \Tasty_Recipes::has_recipe( $result['id'] );

							if ( ! $has_recipe ) {
								return (object) $data;
							}

							$recipe_id = \Tasty_Recipes::get_recipe_ids_for_post( $result['id'] )[0];
							$recipe = \Tasty_Recipes\Objects\Recipe::get_by_id( $recipe_id );

							$data['tastyRecipe'] = array(
								'enabled'       => $has_recipe,
								'recipeId'      => $recipe_id,
								'ratingAverage' => $recipe ? $recipe->get_average_rating() : 0,
								'ratingCount'   => $recipe ? $recipe->get_total_reviews() : 0,
							);
						}
					}
					return (object) $data;
				},
			)
		);

		register_rest_route(
			'tasty-roundups/v1',
			'/fetch-external-link',
			array(
				'methods'             => 'POST',
				'callback'            => array( __CLASS__, 'fetch_external_link' ),
				'permission_callback' => function () {
					return current_user_can( 'edit_others_posts' );
				},
			)
		);
	}

	/**
	 * Enqueue block assets on both frontend and backend.
	 */
	public static function action_enqueue_block_assets() {
		// Added directly inline on the frontend with render_container_block().
		if ( is_admin() ) {
			wp_enqueue_style( 'tasty-roundups-block' );
			wp_enqueue_style( 'tasty-roundups-legacy-block' );
		}
	}

	/**
	 * Enqueue our simple stylesheet in the block editor.
	 */
	public static function action_enqueue_block_editor_assets() {
		$version    = TASTY_ROUNDUPS_PLUGIN_VERSION;
		$assets_dir = Utils::plugin_assets_url();

		wp_enqueue_script(
			'tasty-roundups-block-editor',
			$assets_dir . 'block-editor.build.js',
			array(
				'wp-block-editor',
				'wp-components',
				'wp-data',
				'wp-dom',
				'wp-element',
				'wp-i18n',
				'wp-rich-text',
				'wp-url',
				'lodash',
			),
			$version,
			true
		);
		if ( function_exists( 'wp_set_script_translations' ) ) {
			wp_set_script_translations( 'tasty-roundups-block-editor', 'tasty-roundups' );
		}
		wp_localize_script(
			'tasty-roundups-block-editor',
			'tastyRoundupsBlockEditor',
			array(
				'images_url'     => Utils::plugin_images_url(),
				'options'        => self::get_customization_settings(),
				'external_nonce' => wp_create_nonce( 'tasty-roundups-external' ),
			)
		);

		wp_enqueue_style(
			'tasty-roundups-block-editor',
			$assets_dir . 'block-editor.css',
			array(),
			$version
		);

		wp_enqueue_style(
			'legacy-tasty-roundups-block-editor',
			$assets_dir . 'legacy-block-editor.css',
			array(),
			$version
		);
	}

	/**
	 * Renders a container block on the frontend.
	 *
	 * @param array  $attributes Block attributes.
	 * @param string $content    Block content.
	 * @return string
	 */
	public static function render_container_block( $attributes, $content ) {
		_deprecated_function( __METHOD__, '2.0', '\Blocks\Item_Block' );

		$block = new Blocks\Container_Block( $attributes, $content );
		return $block->render();
	}

	/**
	 * Renders an item block on the frontend.
	 *
	 * @param array     $attributes Block attributes.
	 * @param string    $content    Block content.
	 * @param \WP_Block $block      The block.
	 * @return string
	 */
	public static function render_item_block( $attributes, $content, $block ) {
		_deprecated_function( __METHOD__, '2.0', '\Blocks\Item_Block' );

		$block = new Blocks\Item_Block( $attributes, $content, $block );
		return $block->render();
	}

	/**
	 * Applies customization settings to roundup item output.
	 *
	 * @return void
	 */
	public static function apply_customization_settings() {
		_deprecated_function( __METHOD__, '2.0', '\Blocks\Item_Block::apply_customization_settings()' );
	}

	/**
	 * Gets the configuration settings for the plugin.
	 *
	 * @return array
	 */
	public static function get_customization_settings() {
		$defaults = array(
			'media_position'          => 'left',
			'numbers'                 => 'on',
			'heading_color'           => '',
			'text_color'              => '',
			'number_text_color'       => '',
			'number_background_color' => '',
			'number_border_color'     => '',
			'number_border_width'     => '',
			'button_text_color'       => '',
			'button_background_color' => '',
			'button_border_radius'    => '',
			'button_text'             => 'Read more',
			'block_background_color'  => '',
			'block_border_color'      => '',
			'block_border_width'      => '',
			'block_border_radius'     => '',
			'shareasale_affiliate_id' => '',
		);
		$options  = get_option( Admin::SETTINGS_OPTION, array() );
		return array_merge( $defaults, $options );
	}

	/**
	 * Prepare search arguments like post types to search in and keep it specific to our request only.
	 *
	 * @param array           $query_args Filter query args.
	 * @param WP_REST_Request $request Sent request.
	 *
	 * @return array
	 */
	public static function prepare_search_args( $query_args, $request ) {
		$tasty_referrer = $request->get_param( 'tasty_referrer' );
		if ( 'roundup' !== $tasty_referrer ) {
			return $query_args;
		}

		$post_types = array_diff(
			array_values(
				get_post_types(
					array(
						'public'              => true,
						'show_in_rest'        => true,
						'exclude_from_search' => false,
					),
					'names'
				)
			),
			array( 'attachment' )
		);

		/**
		 * Filters Search post types.
		 *
		 * @since 1.0.4
		 *
		 * @param array           $post_types Array of post types to search in.
		 * @param array           $query_args Full array of query arguments.
		 * @param WP_REST_Request $request Request instance.
		 */
		$query_args['post_type'] = (array) apply_filters( 'tasty_roundups_search_post_types', $post_types, $query_args, $request );

		return $query_args;
	}

	/**
	 * Search only in post titles.
	 *
	 * @param array $columns Columns to search in.
	 *
	 * @return string[]
	 */
	public static function search_only_in_titles( $columns ) {
		$tasty_referrer = Vars::request_param( 'tasty_referrer' );
		if ( ! Utils::is_rest_api_request() || 'roundup' !== $tasty_referrer ) {
			return $columns;
		}

		return array( 'post_title' );
	}

	/**
	 * Handles fetching external link data.
	 *
	 * @param WP_REST_Request $request - The request object.
	 * @return void
	 */
	public static function fetch_external_link( $request ) {
		$params = $request->get_params();

		if ( ! wp_verify_nonce( $params['nonce'], 'tasty-roundups-external' ) ) {
			wp_send_json_error(
				array(
					'message' => __( 'Unauthorized', 'tasty-roundups' ),
				)
			);
		}

		$url      = sanitize_url( $params['externalUrl'] );
		$response = wp_remote_get( $url );

		if ( is_wp_error( $response ) ) {
			if ( str_contains( $response->get_error_message(), 'cURL error 6' ) ) {
				wp_send_json_error(
					array(
						'message' => __( 'The URL could not be accessed. Please check the URL and try again.', 'tasty-roundups' ),
					)
				);
			}

			wp_send_json_error(
				array(
					'message' => $response->get_error_message(),
				)
			);
		}

		if ( 404 === (int) $response['response']['code'] ) {
			wp_send_json_error(
				array(
					'message' => __( 'The URL returned a \'404 Not Found\' error', 'tasty-roundups' ),
				)
			);
		}

		$html = wp_remote_retrieve_body( $response );

		if ( empty( $html ) ) {
			wp_send_json_error(
				array(
					'message' => __( 'Failed to retrieve the page content', 'tasty-roundups' ),
				)
			);
		}

		$dom = new \DOMDocument();

		// We prevent errors here to avoid malformed HTML warnings.
		//phpcs:ignore
		@$dom->loadHTML($html);

		$xpath = new \DOMXPath( $dom );

		$title = $xpath->query( '//meta[@property="og:title"]/@content' )->item( 0 )->nodeValue ?? false;

		if ( ! $title ) {
			$title = $xpath->query( '//title' )->item( 0 )->nodeValue ?? false;
		}

		$description = $xpath->query( '//meta[@property="og:description"]/@content' )->item( 0 )->nodeValue ?? false;
		$image       = $xpath->query( '//meta[@property="og:image"]/@content' )->item( 0 )->nodeValue ?? false;

		wp_send_json_success(
			array(
				'title'       => $title,
				'description' => $description,
				'image'       => $image,
			)
		);
	}
}
