<?php
/**
 * Shortcode REST API controller.
 *
 * Handles rendering of WordPress shortcodes in the AMB editor preview.
 *
 * @package Antimanual_Builder
 * @since 1.0.0
 */

// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Class AMBLD_API_Shortcode_Api
 *
 * REST API endpoints for shortcode rendering.
 *
 * @since 1.0.0
 */
class AMBLD_API_Shortcode_Api {

	/**
	 * REST namespace.
	 *
	 * @since 1.0.0
	 * @var   string
	 */
	private $namespace = 'ambld/v1';

	/**
	 * Register routes.
	 *
	 * @since  1.0.0
	 * @return void
	 */
	public function register_routes() {
		register_rest_route(
			$this->namespace,
			'/render-shortcode',
			array(
				array(
					'methods'             => \WP_REST_Server::CREATABLE,
					'callback'            => array( $this, 'render_shortcode' ),
					'permission_callback' => array( $this, 'can_use_builder' ),
					'args'                => array(
						'shortcode' => array(
							'required'          => false,
							'sanitize_callback' => 'sanitize_text_field',
						),
						'html'      => array(
							'required'          => false,
							'sanitize_callback' => 'wp_kses_post',
						),
					),
				),
			)
		);
	}

	/**
	 * Permission check for the /render-shortcode endpoint.
	 *
	 * This endpoint runs `do_shortcode()` on arbitrary input, which can
	 * surface restricted content via shortcodes like `[gravityform]` or
	 * `[private-content]`. Gate to `edit_pages` (the builder's standard
	 * capability) so a low-privilege author can't probe sensitive
	 * shortcode output via the REST endpoint.
	 *
	 * Method renamed from `can_edit_pages()` (which misleadingly checked
	 * `edit_posts`) so name and check now agree.
	 *
	 * @since  1.0.0
	 * @param  \WP_REST_Request $request Request object.
	 * @return bool
	 */
	public function can_use_builder( $request ) {
		unset( $request );
		return current_user_can( 'edit_pages' );
	}

	/**
	 * Render a shortcode or resolve shortcode markers in HTML.
	 *
	 * If `html` is provided, resolves all data-shortcode markers in that HTML.
	 * If only `shortcode` is provided, returns do_shortcode() on it directly.
	 *
	 * @since  1.0.0
	 * @param  \WP_REST_Request $request Request object.
	 * @return \WP_REST_Response
	 */
	public function render_shortcode( $request ) {
		$html      = (string) $request->get_param( 'html' );
		$shortcode = (string) $request->get_param( 'shortcode' );

		if ( ! empty( $html ) ) {
			$resolved = AMBLD_Render_Shortcode_Resolver::resolve( $html );
			return new \WP_REST_Response(
				array( 'html' => $resolved ),
				200
			);
		}

		if ( ! empty( $shortcode ) ) {
			$rendered = do_shortcode( wp_unslash( $shortcode ) );
			return new \WP_REST_Response(
				array( 'html' => $rendered ),
				200
			);
		}

		return new \WP_REST_Response(
			array( 'html' => '' ),
			200
		);
	}
}