<?php
/**
 * SEOvault HowTo Gutenberg block registration and static markup.
 *
 * Phase 39: server contract + visible fallback markup + readiness bridge.
 * Phase 40: Gutenberg editor UI.
 * Phase 41: HowToBlockCollector emits ready HowTo JSON-LD from block attributes.
 *
 * @package SEOvaultSEO\Blocks
 */

namespace SEOvaultSEO\Blocks;

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

/**
 * Registers and renders the seovault/howto block.
 */
class HowToBlock {

	const BLOCK_NAME = 'seovault/howto';

	/**
	 * 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/howto';
		$args      = array(
			'api_version'     => 2,
			'attributes'      => HowToBlockAttributeSanitizer::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/howto/src/block.json';
		if ( ! file_exists( $source_json ) ) {
			$source_json = trailingslashit( SEOVAULT_SEO_DIR ) . 'blocks/howto/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'] : 'How-to',
						'description' => isset( $metadata['description'] ) ? (string) $metadata['description'] : '',
						'category'    => isset( $metadata['category'] ) ? (string) $metadata['category'] : 'text',
						'icon'        => isset( $metadata['icon'] ) ? (string) $metadata['icon'] : 'list-view',
						'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 HowTo 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 = HowToBlockAttributeSanitizer::sanitize( is_array( $attributes ) ? $attributes : array() );
		$html      = self::build_static_markup( $sanitized['attributes'] );

		/**
		 * Filter rendered HowTo 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_howto_block_render_html', $html, $sanitized['attributes'], (string) $content );

		return wp_kses_post( $html );
	}

	/**
	 * Build static/fallback-visible markup used by save and render.
	 *
	 * Markup must match blocks/howto/src/save.js (+ utils/serialize.js) so
	 * Gutenberg block validation accepts converter/server-written content
	 * without "Attempt Recovery".
	 *
	 * @param array $attributes Sanitized attributes.
	 * @return string
	 */
	public static function build_static_markup( array $attributes ) {
		$name        = isset( $attributes['name'] ) ? (string) $attributes['name'] : '';
		$description = isset( $attributes['description'] ) ? (string) $attributes['description'] : '';
		$steps       = isset( $attributes['steps'] ) && is_array( $attributes['steps'] ) ? $attributes['steps'] : array();
		$supplies    = isset( $attributes['supplies'] ) && is_array( $attributes['supplies'] ) ? $attributes['supplies'] : array();
		$tools       = isset( $attributes['tools'] ) && is_array( $attributes['tools'] ) ? $attributes['tools'] : array();
		$total_time  = isset( $attributes['totalTime'] ) ? (string) $attributes['totalTime'] : '';
		$cost        = isset( $attributes['estimatedCost'] ) && is_array( $attributes['estimatedCost'] ) ? $attributes['estimatedCost'] : array();
		$style       = isset( $attributes['stylePreset'] ) ? (string) $attributes['stylePreset'] : 'clean';
		$color       = isset( $attributes['colorPreset'] ) ? (string) $attributes['colorPreset'] : 'blue';
		$density     = isset( $attributes['density'] ) ? (string) $attributes['density'] : 'comfortable';
		$display     = isset( $attributes['displayMode'] ) ? (string) $attributes['displayMode'] : 'numbered';
		$version     = isset( $attributes['schemaVersion'] ) ? (int) $attributes['schemaVersion'] : 1;

		$has_content = '' !== trim( $name ) || '' !== trim( $description ) || ! empty( $steps ) || ! empty( $supplies ) || ! empty( $tools );
		if ( ! $has_content ) {
			return '';
		}

		// Class order matches blocks/howto/src/utils/serialize.js buildHowToClassList().
		$classes = array(
			'wp-block-seovault-howto',
			'seovault-howto-block',
			'seovault-howto-block--display-' . sanitize_html_class( $display ),
			'seovault-howto-block--style-' . sanitize_html_class( $style ),
			'seovault-howto-block--color-' . sanitize_html_class( $color ),
			'seovault-howto-block--density-' . sanitize_html_class( $density ),
		);

		$name_html = '' !== trim( $name ) ? '<h2 class="seovault-howto-block__name">' . esc_html( $name ) . '</h2>' : '';
		$desc_html = '' !== trim( $description ) ? '<p class="seovault-howto-block__description">' . esc_html( $description ) . '</p>' : '';

		$currency   = isset( $cost['currency'] ) ? trim( (string) $cost['currency'] ) : '';
		$cost_value = isset( $cost['value'] ) ? trim( (string) $cost['value'] ) : '';
		$meta_html  = '';
		if ( '' !== trim( $total_time ) || ( '' !== $currency && '' !== $cost_value ) ) {
			$parts = array();
			if ( '' !== trim( $total_time ) ) {
				$parts[] = '<li class="seovault-howto-block__time">' . esc_html( $total_time ) . '</li>';
			}
			if ( '' !== $currency && '' !== $cost_value ) {
				$parts[] = '<li class="seovault-howto-block__cost">' . esc_html( $currency . ' ' . $cost_value ) . '</li>';
			}
			$meta_html = '<ul class="seovault-howto-block__meta">' . implode( '', $parts ) . '</ul>';
		}

		// Hardcoded English labels match JS save() (not translated) for block validation.
		$supplies_html = '';
		if ( ! empty( $supplies ) ) {
			$lis = '';
			foreach ( $supplies as $supply ) {
				$lis .= '<li>' . esc_html( (string) $supply ) . '</li>';
			}
			$supplies_html = '<div class="seovault-howto-block__supplies"><h3 class="seovault-howto-block__section-title">Supplies</h3><ul>' . $lis . '</ul></div>';
		}

		$tools_html = '';
		if ( ! empty( $tools ) ) {
			$lis = '';
			foreach ( $tools as $tool ) {
				$lis .= '<li>' . esc_html( (string) $tool ) . '</li>';
			}
			$tools_html = '<div class="seovault-howto-block__tools"><h3 class="seovault-howto-block__section-title">Tools</h3><ul>' . $lis . '</ul></div>';
		}

		$steps_html = '';
		$visible    = array();
		foreach ( $steps as $step ) {
			if ( ! is_array( $step ) ) {
				continue;
			}
			$step_name = isset( $step['name'] ) ? trim( (string) $step['name'] ) : '';
			$step_text = isset( $step['text'] ) ? (string) $step['text'] : '';
			if ( '' === $step_name && '' === trim( wp_strip_all_tags( $step_text ) ) ) {
				continue;
			}
			$visible[] = $step;
		}
		if ( ! empty( $visible ) ) {
			$lis = '';
			foreach ( $visible as $index => $step ) {
				$step_name = isset( $step['name'] ) ? trim( (string) $step['name'] ) : '';
				$step_text = isset( $step['text'] ) ? (string) $step['text'] : '';
				$step_id   = isset( $step['id'] ) ? (string) $step['id'] : '';
				$id_attr   = '' !== $step_id ? ' data-howto-step-id="' . esc_attr( $step_id ) . '"' : '';
				$name_part = '' !== $step_name ? '<h3 class="seovault-howto-block__step-name">' . esc_html( $step_name ) . '</h3>' : '';
				$text_part = '' !== trim( wp_strip_all_tags( $step_text ) )
					? '<div class="seovault-howto-block__step-text">' . wp_kses( $step_text, HowToBlockAttributeSanitizer::step_text_kses_allowed() ) . '</div>'
					: '';
				$lis      .= '<li class="seovault-howto-block__step" data-step-index="' . esc_attr( (string) ( $index + 1 ) ) . '"' . $id_attr . '>' . $name_part . $text_part . '</li>';
			}
			$steps_html = '<ol class="seovault-howto-block__steps">' . $lis . '</ol>';
		}

		return '<section class="' . esc_attr( implode( ' ', $classes ) ) . '" data-seovault-block="howto" data-schema-version="' . esc_attr( (string) $version ) . '">' . $name_html . $desc_html . $meta_html . $supplies_html . $tools_html . $steps_html . '</section>';
	}
}
