<?php
/**
 * SEOvault Quick Answer Gutenberg block registration and static markup.
 *
 * Phase 37: visible AEO/TL;DR content only. Does not emit Schema.org entities.
 *
 * @package SEOvaultSEO\Blocks
 */

namespace SEOvaultSEO\Blocks;

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Registers and renders the seovault/quick-answer block.
 */
class QuickAnswerBlock {

	const BLOCK_NAME = 'seovault/quick-answer';

	/**
	 * Register the block type.
	 *
	 * @return bool Whether registration succeeded.
	 */
	public static function register() {
		if ( ! function_exists( 'register_block_type' ) ) {
			return false;
		}

		$built_dir = trailingslashit( SEOVAULT_SEO_DIR ) . 'build/blocks/quick-answer';
		$args      = array(
			'api_version'     => 2,
			'attributes'      => QuickAnswerBlockAttributeSanitizer::attribute_schema(),
			'render_callback' => array( __CLASS__, 'render' ),
		);

		if ( file_exists( $built_dir . '/block.json' ) ) {
			$result = register_block_type( $built_dir, $args );
			return $result instanceof \WP_Block_Type;
		}

		$source_json = trailingslashit( SEOVAULT_SEO_DIR ) . 'blocks/quick-answer/src/block.json';
		if ( ! file_exists( $source_json ) ) {
			$source_json = trailingslashit( SEOVAULT_SEO_DIR ) . 'blocks/quick-answer/block.json';
		}
		if ( file_exists( $source_json ) ) {
			$metadata = json_decode( (string) file_get_contents( $source_json ), true ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents -- Local plugin file.
			if ( is_array( $metadata ) ) {
				$args = array_merge(
					array(
						'title'       => isset( $metadata['title'] ) ? (string) $metadata['title'] : 'Quick Answer',
						'description' => isset( $metadata['description'] ) ? (string) $metadata['description'] : '',
						'category'    => isset( $metadata['category'] ) ? (string) $metadata['category'] : 'text',
						'icon'        => isset( $metadata['icon'] ) ? (string) $metadata['icon'] : 'format-quote',
						'keywords'    => isset( $metadata['keywords'] ) && is_array( $metadata['keywords'] ) ? $metadata['keywords'] : array(),
						'supports'    => isset( $metadata['supports'] ) && is_array( $metadata['supports'] ) ? $metadata['supports'] : array(),
					),
					$args
				);
			}
		}

		$result = register_block_type( self::BLOCK_NAME, $args );
		return $result instanceof \WP_Block_Type;
	}

	/**
	 * Server render callback (active plugin path).
	 *
	 * Always re-sanitizes attributes. Does not emit Schema.org JSON-LD.
	 *
	 * @param array          $attributes Block attributes.
	 * @param string         $content    Saved inner content (fallback).
	 * @param \WP_Block|null $block      Block instance.
	 * @return string
	 */
	public static function render( $attributes, $content = '', $block = null ) {
		unset( $block );
		$sanitized = QuickAnswerBlockAttributeSanitizer::sanitize( is_array( $attributes ) ? $attributes : array() );
		$html      = self::build_static_markup( $sanitized['attributes'] );

		/**
		 * Filter rendered Quick Answer block HTML (no schema emission).
		 *
		 * The value returned from this filter is passed through wp_kses_post()
		 * immediately before output. Filtered HTML is restricted to WordPress
		 * post-content markup. Script, style, iframe, and event-handler markup
		 * are not supported.
		 *
		 * @param string $html       Markup.
		 * @param array  $attributes Sanitized attributes.
		 * @param string $content    Original saved content.
		 */
		$html = (string) apply_filters( 'seovaultseo_quick_answer_block_render_html', $html, $sanitized['attributes'], (string) $content );

		return wp_kses_post( $html );
	}

	/**
	 * Build static/fallback-visible markup used by save and render.
	 *
	 * Remains readable when the plugin is deactivated (saved inner HTML)
	 * and when JavaScript is unavailable.
	 *
	 * @param array $attributes Sanitized attributes.
	 * @return string
	 */
	public static function build_static_markup( array $attributes ) {
		$label   = isset( $attributes['label'] ) ? (string) $attributes['label'] : 'Quick answer';
		$answer  = isset( $attributes['answer'] ) ? (string) $attributes['answer'] : '';
		$style   = isset( $attributes['stylePreset'] ) ? (string) $attributes['stylePreset'] : 'clean';
		$color   = isset( $attributes['colorPreset'] ) ? (string) $attributes['colorPreset'] : 'blue';
		$density = isset( $attributes['density'] ) ? (string) $attributes['density'] : 'comfortable';
		$version = isset( $attributes['schemaVersion'] ) ? (int) $attributes['schemaVersion'] : 1;

		if ( '' === trim( $answer ) ) {
			return '';
		}

		$classes = array(
			'seovault-quick-answer-block',
			'seovault-quick-answer-block--style-' . sanitize_html_class( $style ),
			'seovault-quick-answer-block--color-' . sanitize_html_class( $color ),
			'seovault-quick-answer-block--density-' . sanitize_html_class( $density ),
		);

		$buffer_level = ob_get_level();
		ob_start();
		try {
			?>
		<aside
			class="<?php echo esc_attr( implode( ' ', $classes ) ); ?>"
			data-seovault-block="quick-answer"
			data-schema-version="<?php echo esc_attr( (string) $version ); ?>"
		>
			<?php if ( '' !== trim( $label ) ) : ?>
				<p class="seovault-quick-answer-block__label"><?php echo esc_html( $label ); ?></p>
			<?php endif; ?>
			<p class="seovault-quick-answer-block__answer"><?php echo esc_html( $answer ); ?></p>
		</aside>
			<?php

			return (string) ob_get_clean();
		} finally {
			while ( ob_get_level() > $buffer_level ) {
				ob_end_clean();
			}
		}
	}
}
