<?php
/** Version-bound, targeted writes for one static Spectra Advanced Heading contract. */

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

const WPAGENT_SPECTRA_STATIC_ADVANCED_HEADING_VERSION = '2.20.1';
const WPAGENT_SPECTRA_STATIC_ADVANCED_HEADING_BLOCK   = 'uagb/advanced-heading';

/** @return array<string,mixed> */
function wpagent_ability_update_spectra_static_heading_alignment(): array {
	return array(
		'label'       => __( 'Statische Spectra-Überschriftenausrichtung aktualisieren', 'wp-agent-companion' ),
		'description' => __( 'Ändert ausschließlich die Desktop-, Tablet- oder Mobil-Ausrichtung einer strukturell geprüften statischen Spectra-Überschrift. Der Pfad ist fest an Spectra 2.20.1 und sein serverseitig überprüfbares Frontend-CSS gebunden. Markup, Texte, block_id und alle anderen Attribute bleiben unverändert.', 'wp-agent-companion' ),
		'category'    => 'wp-agent',
		'input_schema' => array(
			'type'       => 'object',
			'properties' => array(
				'post_id' => array( 'type' => 'integer', 'minimum' => 1 ),
				'path' => array(
					'type' => 'array', 'minItems' => 1, 'maxItems' => 32,
					'items' => array( 'type' => 'integer', 'minimum' => 0, 'maximum' => 10000 ),
				),
				'alignment' => array( 'type' => 'string', 'enum' => array( 'left', 'center', 'right' ) ),
				'viewport' => array( 'type' => 'string', 'enum' => array( 'desktop', 'tablet', 'mobile' ), 'default' => 'desktop' ),
				'expected_hash' => array( 'type' => 'string', 'pattern' => '^[a-f0-9]{64}$' ),
			),
			'required'             => array( 'post_id', 'path', 'alignment', 'expected_hash' ),
			'additionalProperties' => false,
		),
		'output_schema' => array(
			'type'       => 'object',
			'properties' => array(
				'post_id'              => array( 'type' => 'integer' ),
				'block_name'           => array( 'type' => 'string', 'enum' => array( WPAGENT_SPECTRA_STATIC_ADVANCED_HEADING_BLOCK ) ),
				'path'                 => array( 'type' => 'array', 'items' => array( 'type' => 'integer' ) ),
				'alignment'            => array( 'type' => 'string', 'enum' => array( 'left', 'center', 'right' ) ),
				'viewport'             => array( 'type' => 'string', 'enum' => array( 'desktop', 'tablet', 'mobile' ) ),
				'provider_version'     => array( 'type' => 'string', 'enum' => array( WPAGENT_SPECTRA_STATIC_ADVANCED_HEADING_VERSION ) ),
				'changed'              => array( 'type' => 'boolean' ),
				'verified'             => array( 'type' => 'boolean' ),
				'revision_id'          => array( 'type' => 'integer' ),
				'rendered_html_length' => array( 'type' => 'integer' ),
				'previous_hash'        => array( 'type' => 'string', 'pattern' => '^[a-f0-9]{64}$' ),
				'hash'                 => array( 'type' => 'string', 'pattern' => '^[a-f0-9]{64}$' ),
				'cache'                => array(
					'type' => 'object', 'properties' => array(
						'builder' => array( 'type' => 'string', 'enum' => array( 'spectra' ) ),
						'executed' => array( 'type' => 'boolean' ), 'verified' => array( 'type' => 'boolean' ),
					), 'required' => array( 'builder', 'executed', 'verified' ), 'additionalProperties' => false,
				),
			),
			'required' => array( 'post_id', 'block_name', 'path', 'alignment', 'viewport', 'provider_version', 'changed', 'verified', 'revision_id', 'rendered_html_length', 'previous_hash', 'hash', 'cache' ),
			'additionalProperties' => false,
		),
		'execute_callback'    => 'wpagent_exec_update_spectra_static_heading_alignment',
		'permission_callback' => 'wpagent_perm_edit_posts',
		'meta'                => array(
			'show_in_rest' => true,
			'annotations'  => array( 'readonly' => false, 'destructive' => false, 'idempotent' => false ),
		),
	);
}

/** @return array<string,mixed> */
function wpagent_ability_update_spectra_static_heading_colors(): array {
	return array(
		'label'       => __( 'Statische Spectra-Überschriftenfarben aktualisieren', 'wp-agent-companion' ),
		'description' => __( 'Ändert ausschließlich die klassischen Überschriften- und Beschreibungsfarben sowie optional die Farbe eines vorhandenen, strukturell geprüften Separators einer statischen Spectra-Überschrift. Erlaubt sind sechsstellige Hex-Farben oder inherit. Der Pfad ist fest an Spectra 2.20.1 und sein serverseitig überprüfbares Frontend-CSS gebunden.', 'wp-agent-companion' ),
		'category'    => 'wp-agent',
		'input_schema' => array(
			'type'       => 'object',
			'properties' => array(
				'post_id' => array( 'type' => 'integer', 'minimum' => 1 ),
				'path' => array(
					'type' => 'array', 'minItems' => 1, 'maxItems' => 32,
					'items' => array( 'type' => 'integer', 'minimum' => 0, 'maximum' => 10000 ),
				),
			'heading_color'     => array( 'type' => 'string', 'pattern' => '^(?:inherit|#[a-fA-F0-9]{6})$' ),
			'description_color' => array( 'type' => 'string', 'pattern' => '^(?:inherit|#[a-fA-F0-9]{6})$' ),
			'separator_color'   => array( 'type' => 'string', 'pattern' => '^(?:inherit|#[a-fA-F0-9]{6})$' ),
				'expected_hash' => array( 'type' => 'string', 'pattern' => '^[a-f0-9]{64}$' ),
			),
			'required'             => array( 'post_id', 'path', 'heading_color', 'description_color', 'expected_hash' ),
			'additionalProperties' => false,
		),
		'output_schema' => array(
			'type'       => 'object',
			'properties' => array(
				'post_id'              => array( 'type' => 'integer' ),
				'block_name'           => array( 'type' => 'string', 'enum' => array( WPAGENT_SPECTRA_STATIC_ADVANCED_HEADING_BLOCK ) ),
				'path'                 => array( 'type' => 'array', 'items' => array( 'type' => 'integer' ) ),
			'heading_color'        => array( 'type' => 'string', 'pattern' => '^(?:inherit|#[a-f0-9]{6})$' ),
			'description_color'    => array( 'type' => 'string', 'pattern' => '^(?:inherit|#[a-f0-9]{6})$' ),
			'separator_color'      => array( 'type' => 'string', 'pattern' => '^(?:inherit|#[a-f0-9]{6})$' ),
				'provider_version'     => array( 'type' => 'string', 'enum' => array( WPAGENT_SPECTRA_STATIC_ADVANCED_HEADING_VERSION ) ),
				'changed'              => array( 'type' => 'boolean' ),
				'verified'             => array( 'type' => 'boolean' ),
				'revision_id'          => array( 'type' => 'integer' ),
				'rendered_html_length' => array( 'type' => 'integer' ),
				'previous_hash'        => array( 'type' => 'string', 'pattern' => '^[a-f0-9]{64}$' ),
				'hash'                 => array( 'type' => 'string', 'pattern' => '^[a-f0-9]{64}$' ),
				'cache'                => array(
					'type' => 'object', 'properties' => array(
						'builder' => array( 'type' => 'string', 'enum' => array( 'spectra' ) ),
						'executed' => array( 'type' => 'boolean' ), 'verified' => array( 'type' => 'boolean' ),
					), 'required' => array( 'builder', 'executed', 'verified' ), 'additionalProperties' => false,
				),
			),
			'required' => array( 'post_id', 'block_name', 'path', 'heading_color', 'description_color', 'provider_version', 'changed', 'verified', 'revision_id', 'rendered_html_length', 'previous_hash', 'hash', 'cache' ),
			'additionalProperties' => false,
		),
		'execute_callback'    => 'wpagent_exec_update_spectra_static_heading_colors',
		'permission_callback' => 'wpagent_perm_edit_posts',
		'meta'                => array(
			'show_in_rest' => true,
			'annotations'  => array( 'readonly' => false, 'destructive' => false, 'idempotent' => false ),
		),
	);
}

/** @return array{block_name:string,provider_version:string,alignments:array<int,string>,viewports:array<int,string>}|WP_Error */
function wpagent_spectra_static_advanced_heading_contract_for_version( string $version ) {
	if ( ! hash_equals( WPAGENT_SPECTRA_STATIC_ADVANCED_HEADING_VERSION, $version ) ) {
		return new WP_Error(
			'wpagent_spectra_static_heading_version',
			__( 'Der statische Spectra-Überschriftenvertrag ist nur für die explizit getestete Provider-Version verfügbar.', 'wp-agent-companion' ),
			array( 'status' => 409, 'expected_version' => WPAGENT_SPECTRA_STATIC_ADVANCED_HEADING_VERSION, 'actual_version' => $version )
		);
	}
	return array(
		'block_name'       => WPAGENT_SPECTRA_STATIC_ADVANCED_HEADING_BLOCK,
		'provider_version' => WPAGENT_SPECTRA_STATIC_ADVANCED_HEADING_VERSION,
		'alignments'       => array( 'left', 'center', 'right' ),
		'viewports'        => array( 'desktop', 'tablet', 'mobile' ),
	);
}

/** @return array{block_name:string,provider_version:string,alignments:array<int,string>,viewports:array<int,string>}|WP_Error */
function wpagent_spectra_static_advanced_heading_contract() {
	$available = wpagent_spectra_require_available();
	if ( is_wp_error( $available ) ) {
		return $available;
	}
	$contract = wpagent_spectra_static_advanced_heading_contract_for_version( wpagent_spectra_version() );
	if ( is_wp_error( $contract ) ) {
		return $contract;
	}
	$blocks = UAGB_Block_Module::get_blocks_info();
	$definition = is_array( $blocks ) ? ( $blocks[ WPAGENT_SPECTRA_STATIC_ADVANCED_HEADING_BLOCK ] ?? null ) : null;
	if ( ! is_array( $definition ) || ( $definition['dynamic_assets']['dir'] ?? null ) !== 'advanced-heading' || empty( $definition['default'] ) || ! empty( $definition['extension'] ) || ! empty( $definition['deprecated'] ) ) {
		return new WP_Error(
			'wpagent_spectra_static_heading_provider_contract',
			__( 'Die installierte Spectra-Definition der statischen Überschrift stimmt nicht mit dem geprüften Providervertrag überein.', 'wp-agent-companion' ),
			array( 'status' => 409 )
		);
	}
	$block_status = wpagent_spectra_block_option_snapshot();
	if ( is_wp_error( $block_status ) ) {
		return $block_status;
	}
	$state = wpagent_spectra_block_state( array( 'slug' => 'advanced-heading', 'default_enabled' => true ), $block_status['value'] );
	if ( empty( $state['enabled'] ) ) {
		return new WP_Error(
			'wpagent_spectra_static_heading_provider_contract',
			__( 'Spectras statische Überschrift ist deaktiviert. Der Schreibpfad bleibt gesperrt, weil ihr Frontend-Vertrag nicht überprüfbar ist.', 'wp-agent-companion' ),
			array( 'status' => 409 )
		);
	}
	$type = WP_Block_Type_Registry::get_instance()->get_registered( WPAGENT_SPECTRA_STATIC_ADVANCED_HEADING_BLOCK );
	if ( $type instanceof WP_Block_Type && is_callable( $type->render_callback ) ) {
		return new WP_Error(
			'wpagent_spectra_static_heading_provider_contract',
			__( 'Spectra registriert diese Überschrift inzwischen dynamisch. Der statische Vertrag wird nicht auf einen anderen Speicher- oder Renderpfad erweitert.', 'wp-agent-companion' ),
			array( 'status' => 409 )
		);
	}
	return $contract;
}

function wpagent_spectra_static_advanced_heading_alignment_valid( $alignment ): bool {
	return is_string( $alignment ) && in_array( $alignment, array( 'left', 'center', 'right' ), true );
}

function wpagent_spectra_static_advanced_heading_viewport_valid( $viewport ): bool {
	return is_string( $viewport ) && in_array( $viewport, array( 'desktop', 'tablet', 'mobile' ), true );
}

function wpagent_spectra_static_advanced_heading_alignment_key( string $viewport ): string {
	return array(
		'desktop' => 'headingAlign',
		'tablet'  => 'headingAlignTablet',
		'mobile'  => 'headingAlignMobile',
	)[ $viewport ];
}

function wpagent_spectra_static_advanced_heading_color_input( $color ) {
	if ( ! is_string( $color ) ) {
		return false;
	}
	if ( 'inherit' === $color ) {
		return '';
	}
	$normalized = strtolower( $color );
	return preg_match( '/^#[a-f0-9]{6}$/D', $normalized ) ? $normalized : false;
}

function wpagent_spectra_static_advanced_heading_stored_color_valid( $color ): bool {
	return is_string( $color ) && ( '' === $color || (bool) preg_match( '/^#[a-fA-F0-9]{6}$/D', $color ) );
}

/** @param array<string,mixed> $block */
function wpagent_spectra_static_advanced_heading_separator_markup_valid( array $block ): bool {
	$inner_html = is_string( $block['innerHTML'] ?? null ) ? trim( $block['innerHTML'] ) : '';
	if ( '' === $inner_html || ! class_exists( 'WP_HTML_Processor' ) ) {
		return false;
	}
	try {
		$processor = WP_HTML_Processor::create_fragment( $inner_html );
	} catch ( Throwable ) {
		return false;
	}
	$wrapper_count = 0;
	$separator_count = 0;
	$inside_wrapper = false;
	$wrapper_has_separator = false;
	while ( $processor->next_tag() ) {
		$depth = count( $processor->get_breadcrumbs() );
		if ( $inside_wrapper ) {
			if ( $depth <= 4 ) {
				if ( ! $wrapper_has_separator ) {
					return false;
				}
				$inside_wrapper = false;
			} elseif ( ! $wrapper_has_separator ) {
				if ( 5 !== $depth || 'DIV' !== $processor->get_tag() || ! $processor->has_class( 'uagb-separator' ) ) {
					return false;
				}
				$wrapper_has_separator = true;
				++$separator_count;
				continue;
			} else {
				return false;
			}
		}
		if ( $processor->has_class( 'uagb-separator-wrap' ) ) {
			if ( 4 !== $depth || 'DIV' !== $processor->get_tag() || 0 !== $wrapper_count ) {
				return false;
			}
			++$wrapper_count;
			$inside_wrapper = true;
			$wrapper_has_separator = false;
			continue;
		}
		if ( $processor->has_class( 'uagb-separator' ) ) {
			return false;
		}
	}
	return 1 === $wrapper_count && 1 === $separator_count && ( ! $inside_wrapper || $wrapper_has_separator );
}

/** @param array<string,mixed> $block */
function wpagent_spectra_static_advanced_heading_markup_valid( array $block, string $block_id ): bool {
	$inner_html = is_string( $block['innerHTML'] ?? null ) ? $block['innerHTML'] : '';
	$inner_content = $block['innerContent'] ?? null;
	if ( '' === $inner_html || ! is_array( $inner_content ) || 1 !== count( $inner_content ) || $inner_content[0] !== $inner_html
		|| ! isset( $block['innerBlocks'] ) || ! is_array( $block['innerBlocks'] ) || array() !== $block['innerBlocks']
		|| preg_match( '/<\\/?(?:script|style|iframe|object|embed)\\b|<!--|\\bon[a-z][a-z0-9_-]*\\s*=|(?:javascript|vbscript)\\s*:/i', $inner_html ) ) {
		return false;
	}
	$trimmed = trim( $inner_html );
	if ( ! str_starts_with( $trimmed, '<div' ) || ! str_ends_with( $trimmed, '</div>' ) || ! class_exists( 'WP_HTML_Processor' ) ) {
		return false;
	}
	try {
		$processor = WP_HTML_Processor::create_fragment( $trimmed );
	} catch ( Throwable ) {
		return false;
	}
	$root_found = false;
	$has_heading = false;
	while ( $processor->next_tag() ) {
		$breadcrumbs = $processor->get_breadcrumbs();
		if ( 3 === count( $breadcrumbs ) ) {
			if ( $root_found || 'DIV' !== $processor->get_tag()
				|| 'uagb-adv-heading-' . $block_id !== $processor->get_attribute( 'id' ) || ! $processor->has_class( 'wp-block-uagb-advanced-heading' ) ) {
				return false;
			}
			$root_found = true;
			continue;
		}
		if ( ! $root_found || count( $breadcrumbs ) < 4 ) {
			return false;
		}
		if ( $processor->has_class( 'uagb-heading-text' ) ) {
			$has_heading = true;
		}
	}
	return $root_found && $has_heading;
}

/** @param array<int,array<string,mixed>> $blocks @param array<int,int> $path @return array<string,mixed>|WP_Error */
function wpagent_spectra_static_advanced_heading_patch_path( array &$blocks, array $path, string $alignment, string $viewport = 'desktop', int $depth = 0 ) {
	if ( ! wpagent_spectra_static_advanced_heading_alignment_valid( $alignment ) || ! wpagent_spectra_static_advanced_heading_viewport_valid( $viewport ) ) {
		return new WP_Error( 'wpagent_spectra_static_heading_alignment', __( 'Ausrichtung und Viewport entsprechen nicht dem engen statischen Spectra-Vertrag.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$index = $path[ $depth ];
	if ( ! isset( $blocks[ $index ] ) || ! is_array( $blocks[ $index ] ) ) {
		return new WP_Error( 'wpagent_spectra_static_heading_path_not_found', __( 'Der Blockpfad wurde im aktuellen Dokument nicht gefunden.', 'wp-agent-companion' ), array( 'status' => 404 ) );
	}
	if ( $depth + 1 < count( $path ) ) {
		if ( ! isset( $blocks[ $index ]['innerBlocks'] ) || ! is_array( $blocks[ $index ]['innerBlocks'] ) ) {
			return new WP_Error( 'wpagent_spectra_static_heading_path_not_found', __( 'Der Blockpfad wurde im aktuellen Dokument nicht gefunden.', 'wp-agent-companion' ), array( 'status' => 404 ) );
		}
		return wpagent_spectra_static_advanced_heading_patch_path( $blocks[ $index ]['innerBlocks'], $path, $alignment, $viewport, $depth + 1 );
	}
	if ( WPAGENT_SPECTRA_STATIC_ADVANCED_HEADING_BLOCK !== ( $blocks[ $index ]['blockName'] ?? '' ) ) {
		return new WP_Error( 'wpagent_spectra_static_heading_not_allowed', __( 'Am Zielpfad liegt keine freigegebene statische Spectra-Überschrift.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	$attrs = is_array( $blocks[ $index ]['attrs'] ?? null ) ? $blocks[ $index ]['attrs'] : array();
	$block_id = $attrs['block_id'] ?? null;
	$alignment_keys = array( 'headingAlign', 'headingAlignTablet', 'headingAlignMobile' );
	$stored_alignments_valid = true;
	foreach ( $alignment_keys as $alignment_key ) {
		$stored_alignment = $attrs[ $alignment_key ] ?? '';
		if ( ! is_string( $stored_alignment ) || ! in_array( $stored_alignment, array( '', 'left', 'center', 'right' ), true ) ) {
			$stored_alignments_valid = false;
			break;
		}
	}
	if ( ! is_string( $block_id ) || ! preg_match( '/^[A-Za-z0-9_-]{6,64}$/D', $block_id ) || ( isset( $attrs['classMigrate'] ) && false !== $attrs['classMigrate'] )
		|| ! $stored_alignments_valid
		|| ! wpagent_spectra_static_advanced_heading_markup_valid( $blocks[ $index ], $block_id ) ) {
		return new WP_Error( 'wpagent_spectra_static_heading_structure', __( 'Die gespeicherte statische Spectra-Überschrift weicht vom eng geprüften Strukturvertrag ab und wird nicht automatisch geändert.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	$before = $attrs;
	$attrs[ wpagent_spectra_static_advanced_heading_alignment_key( $viewport ) ] = $alignment;
	$blocks[ $index ]['attrs'] = $attrs;
	return array( 'block_name' => WPAGENT_SPECTRA_STATIC_ADVANCED_HEADING_BLOCK, 'block_id' => $block_id, 'changed' => $attrs !== $before );
}

/** @param array<int,array<string,mixed>> $blocks @param array<int,int> $path @return array<string,mixed>|WP_Error */
function wpagent_spectra_static_advanced_heading_patch_colors( array &$blocks, array $path, string $heading_color, string $description_color, $separator_color = null, int $depth = 0 ) {
	$normalized_heading = wpagent_spectra_static_advanced_heading_color_input( $heading_color );
	$normalized_description = wpagent_spectra_static_advanced_heading_color_input( $description_color );
	$normalized_separator = null === $separator_color ? null : wpagent_spectra_static_advanced_heading_color_input( $separator_color );
	if ( false === $normalized_heading || false === $normalized_description || false === $normalized_separator ) {
		return new WP_Error( 'wpagent_spectra_static_heading_color', __( 'Farben müssen exakt inherit oder sechsstellige Hex-Farben sein.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$index = $path[ $depth ];
	if ( ! isset( $blocks[ $index ] ) || ! is_array( $blocks[ $index ] ) ) {
		return new WP_Error( 'wpagent_spectra_static_heading_path_not_found', __( 'Der Blockpfad wurde im aktuellen Dokument nicht gefunden.', 'wp-agent-companion' ), array( 'status' => 404 ) );
	}
	if ( $depth + 1 < count( $path ) ) {
		if ( ! isset( $blocks[ $index ]['innerBlocks'] ) || ! is_array( $blocks[ $index ]['innerBlocks'] ) ) {
			return new WP_Error( 'wpagent_spectra_static_heading_path_not_found', __( 'Der Blockpfad wurde im aktuellen Dokument nicht gefunden.', 'wp-agent-companion' ), array( 'status' => 404 ) );
		}
		return wpagent_spectra_static_advanced_heading_patch_colors( $blocks[ $index ]['innerBlocks'], $path, $heading_color, $description_color, $separator_color, $depth + 1 );
	}
	if ( WPAGENT_SPECTRA_STATIC_ADVANCED_HEADING_BLOCK !== ( $blocks[ $index ]['blockName'] ?? '' ) ) {
		return new WP_Error( 'wpagent_spectra_static_heading_not_allowed', __( 'Am Zielpfad liegt keine freigegebene statische Spectra-Überschrift.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	$attrs = is_array( $blocks[ $index ]['attrs'] ?? null ) ? $blocks[ $index ]['attrs'] : array();
	$block_id = $attrs['block_id'] ?? null;
	if ( ! is_string( $block_id ) || ! preg_match( '/^[A-Za-z0-9_-]{6,64}$/D', $block_id )
		|| ( $attrs['headingColorType'] ?? 'classic' ) !== 'classic'
		|| ! wpagent_spectra_static_advanced_heading_stored_color_valid( $attrs['headingColor'] ?? '' )
		|| ! wpagent_spectra_static_advanced_heading_stored_color_valid( $attrs['subHeadingColor'] ?? '' )
		|| ( isset( $attrs['classMigrate'] ) && false !== $attrs['classMigrate'] )
		|| ! wpagent_spectra_static_advanced_heading_markup_valid( $blocks[ $index ], $block_id ) ) {
		return new WP_Error( 'wpagent_spectra_static_heading_structure', __( 'Die gespeicherte statische Spectra-Überschrift weicht vom eng geprüften Struktur- oder Farbvertrag ab und wird nicht automatisch geändert.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	if ( null !== $normalized_separator && (
		! in_array( $attrs['seperatorStyle'] ?? 'none', array( 'solid', 'double', 'dashed', 'dotted' ), true )
		|| ! wpagent_spectra_static_advanced_heading_stored_color_valid( $attrs['separatorColor'] ?? '#0170b9' )
		|| ! wpagent_spectra_static_advanced_heading_separator_markup_valid( $blocks[ $index ] )
	) ) {
		return new WP_Error( 'wpagent_spectra_static_heading_separator_structure', __( 'Die gespeicherte Spectra-Trennlinie weicht vom eng geprüften statischen Providervertrag ab und wird nicht automatisch geändert.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	$before = $attrs;
	$attrs['headingColor'] = $normalized_heading;
	$attrs['subHeadingColor'] = $normalized_description;
	if ( null !== $normalized_separator ) {
		$attrs['separatorColor'] = $normalized_separator;
	}
	$blocks[ $index ]['attrs'] = $attrs;
	$result = array(
		'block_name' => WPAGENT_SPECTRA_STATIC_ADVANCED_HEADING_BLOCK,
		'block_id' => $block_id,
		'heading_color' => '' === $normalized_heading ? 'inherit' : $normalized_heading,
		'description_color' => '' === $normalized_description ? 'inherit' : $normalized_description,
		'changed' => $attrs !== $before,
	);
	if ( null !== $normalized_separator ) {
		$result['separator_color'] = '' === $normalized_separator ? 'inherit' : $normalized_separator;
	}
	return $result;
}

/** @param array<int,array<string,mixed>> $blocks */
function wpagent_spectra_static_advanced_heading_has_patchable_block( array $blocks ): bool {
	if ( is_wp_error( wpagent_spectra_static_advanced_heading_contract() ) ) {
		return false;
	}
	foreach ( $blocks as $block ) {
		if ( WPAGENT_SPECTRA_STATIC_ADVANCED_HEADING_BLOCK === ( $block['blockName'] ?? '' ) ) {
			$candidate = array( $block );
			if ( ! is_wp_error( wpagent_spectra_static_advanced_heading_patch_path( $candidate, array( 0 ), 'center' ) ) ) {
				return true;
			}
		}
		if ( ! empty( $block['innerBlocks'] ) && is_array( $block['innerBlocks'] ) && wpagent_spectra_static_advanced_heading_has_patchable_block_in_children( $block['innerBlocks'] ) ) {
			return true;
		}
	}
	return false;
}

/** @param array<int,array<string,mixed>> $blocks */
function wpagent_spectra_static_advanced_heading_has_patchable_block_in_children( array $blocks ): bool {
	foreach ( $blocks as $block ) {
		if ( WPAGENT_SPECTRA_STATIC_ADVANCED_HEADING_BLOCK === ( $block['blockName'] ?? '' ) ) {
			$candidate = array( $block );
			if ( ! is_wp_error( wpagent_spectra_static_advanced_heading_patch_path( $candidate, array( 0 ), 'center' ) ) ) {
				return true;
			}
		}
		if ( ! empty( $block['innerBlocks'] ) && is_array( $block['innerBlocks'] ) && wpagent_spectra_static_advanced_heading_has_patchable_block_in_children( $block['innerBlocks'] ) ) {
			return true;
		}
	}
	return false;
}

/**
 * Validates only the target static block's immutable markup.
 *
 * Calling do_blocks() on the whole post would run arbitrary dynamic block callbacks
 * outside this narrow static contract. The end-to-end test proves the real HTTP/CSS
 * effect separately, after Spectra's own asset path has processed the saved post.
 *
 * @param array<int,array<string,mixed>> $blocks
 * @param array<int,int>                 $path
 * @return string|WP_Error
 */
function wpagent_spectra_static_advanced_heading_static_markup_at_path( array $blocks, array $path, string $block_id ) {
	$current_blocks = $blocks;
	$block = null;
	foreach ( $path as $depth => $index ) {
		if ( ! isset( $current_blocks[ $index ] ) || ! is_array( $current_blocks[ $index ] ) ) {
			return new WP_Error( 'wpagent_spectra_static_heading_path_not_found', __( 'Der Blockpfad wurde im aktuellen Dokument nicht gefunden.', 'wp-agent-companion' ), array( 'status' => 404 ) );
		}
		$block = $current_blocks[ $index ];
		if ( $depth + 1 < count( $path ) ) {
			$current_blocks = isset( $block['innerBlocks'] ) && is_array( $block['innerBlocks'] ) ? $block['innerBlocks'] : array();
		}
	}
	if ( ! is_array( $block ) ) {
		return new WP_Error( 'wpagent_spectra_static_heading_path_not_found', __( 'Der Blockpfad wurde im aktuellen Dokument nicht gefunden.', 'wp-agent-companion' ), array( 'status' => 404 ) );
	}
	$attrs = is_array( $block['attrs'] ?? null ) ? $block['attrs'] : array();
	if ( WPAGENT_SPECTRA_STATIC_ADVANCED_HEADING_BLOCK !== ( $block['blockName'] ?? '' )
		|| ! isset( $attrs['block_id'] ) || ! is_string( $attrs['block_id'] ) || ! hash_equals( $block_id, $attrs['block_id'] )
		|| ! wpagent_spectra_static_advanced_heading_markup_valid( $block, $block_id ) ) {
		return new WP_Error( 'wpagent_spectra_static_heading_structure', __( 'Die gespeicherte statische Spectra-Überschrift weicht vom eng geprüften Strukturvertrag ab und wird nicht automatisch geändert.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	return $block['innerHTML'];
}

/** @return array{builder:string,executed:bool,verified:bool} */
function wpagent_spectra_static_heading_refresh_cache( int $post_id ): array {
	$cache = wpagent_refresh_builder_cache_spectra( $post_id );
	return array( 'builder' => 'spectra', 'executed' => ! empty( $cache['executed'] ), 'verified' => ! empty( $cache['verified'] ) );
}

/** @return array{builder:string,executed:bool,verified:bool} */
function wpagent_spectra_static_heading_noop_cache(): array {
	return array( 'builder' => 'spectra', 'executed' => false, 'verified' => true );
}

/**
 * Re-reads a no-op candidate before reporting it as verified.
 *
 * The wpagently lock excludes cooperating writers, but a provider or another
 * WordPress request can still change post_content directly. A stale no-op must
 * therefore fail as a conflict instead of returning the earlier document hash.
 *
 * @param array<int,int> $path
 * @param callable       $verify_patch Receives a parsed block array by reference.
 * @return array<string,mixed>|WP_Error
 */
function wpagent_spectra_static_heading_verify_noop_state( int $post_id, string $expected_content, array $path, string $block_id, string $expected_markup, callable $verify_patch ) {
	$raw_content = wpagent_native_block_raw_content( $post_id );
	$state = wpagent_native_block_document_state( $post_id );
	if ( is_wp_error( $raw_content ) || ! is_array( $state ) || ! is_string( $state['content'] ?? null )
		|| $raw_content !== $expected_content || $state['content'] !== $expected_content ) {
		$data = array( 'status' => 409 );
		if ( is_array( $state ) && is_string( $state['hash'] ?? null ) ) {
			$data['current_hash'] = $state['hash'];
		}
		return new WP_Error( 'wpagent_spectra_static_heading_noop_conflict', __( 'Das Blockdokument wurde während der No-op-Prüfung verändert.', 'wp-agent-companion' ), $data );
	}
	$blocks = parse_blocks( $raw_content );
	if ( serialize_blocks( $blocks ) !== $raw_content ) {
		return new WP_Error( 'wpagent_spectra_static_heading_noop_conflict', __( 'Das Blockdokument ist während der No-op-Prüfung nicht mehr kanonisch lesbar.', 'wp-agent-companion' ), array( 'status' => 409, 'current_hash' => $state['hash'] ) );
	}
	$target = $verify_patch( $blocks );
	$markup = wpagent_spectra_static_advanced_heading_static_markup_at_path( $blocks, $path, $block_id );
	if ( ! is_array( $target ) || ! empty( $target['changed'] ) || ! is_string( $markup ) || ! hash_equals( $expected_markup, $markup ) ) {
		return new WP_Error( 'wpagent_spectra_static_heading_noop_conflict', __( 'Der Zielblock änderte sich während der No-op-Prüfung.', 'wp-agent-companion' ), array( 'status' => 409, 'current_hash' => $state['hash'] ) );
	}
	return $state;
}

/**
 * A post-cache failure needs both a byte-exact content restore and a second
 * verified provider cache refresh. A content-only rollback would leave Spectra
 * assets potentially bound to the rejected candidate.
 *
 * @return array{rolled_back:bool,rollback_verified:bool,recovery_required:bool}
 */
function wpagent_spectra_static_heading_rollback_after_cache( int $post_id, string $before_content, string $candidate_content ): array {
	$rollback = wpagent_native_block_rollback( $post_id, $before_content, $candidate_content );
	if ( ! $rollback['rolled_back'] ) {
		return $rollback;
	}
	$cache = wpagent_spectra_static_heading_refresh_cache( $post_id );
	$raw_content = wpagent_native_block_raw_content( $post_id );
	$state = wpagent_native_block_document_state( $post_id );
	if ( ! $cache['verified'] || is_wp_error( $raw_content ) || $raw_content !== $before_content || is_wp_error( $state ) || $state['content'] !== $before_content ) {
		return array( 'rolled_back' => true, 'rollback_verified' => false, 'recovery_required' => true );
	}
	return $rollback;
}

/** @param array{rolled_back:bool,rollback_verified:bool,recovery_required:bool} $rollback @return WP_Error */
function wpagent_spectra_static_heading_write_error( string $code, string $message, int $revision_id, array $rollback ) {
	$data = array(
		'status' => 500, 'revision_id' => $revision_id,
		'rolled_back' => $rollback['rolled_back'], 'rollback_verified' => $rollback['rollback_verified'], 'recovery_required' => $rollback['recovery_required'],
	);
	if ( $rollback['recovery_required'] ) {
		return new WP_Error(
			'wpagent_spectra_static_heading_recovery_required',
			__( 'Der aktuelle Dokument- oder Spectra-Cachezustand konnte nach der statischen Änderung nicht vollständig verifiziert werden. Prüfe die angelegte Revision, bevor du die Änderung erneut ausführst.', 'wp-agent-companion' ),
			$data
		);
	}
	return new WP_Error( $code, $message, $data );
}

/** @return WP_Error */
function wpagent_spectra_static_heading_lock_lost_after_write( int $revision_id ) {
	return wpagent_spectra_static_heading_write_error(
		'wpagent_spectra_static_heading_lock_lost',
		__( 'Die exklusive Sperre ging nach Beginn der statischen Spectra-Änderung verloren. Die aktuelle Änderung bleibt zur manuellen Prüfung erhalten.', 'wp-agent-companion' ),
		$revision_id,
		array( 'rolled_back' => false, 'rollback_verified' => false, 'recovery_required' => true )
	);
}

/** @return array<string,mixed>|WP_Error */
function wpagent_exec_update_spectra_static_heading_alignment( $input ) {
	$input = is_array( $input ) ? $input : array();
	$post_id = absint( $input['post_id'] ?? 0 );
	$path = is_array( $input['path'] ?? null ) ? $input['path'] : array();
	$path_ok = wpagent_native_block_validate_path( $path );
	if ( is_wp_error( $path_ok ) ) {
		return $path_ok;
	}
	$alignment = $input['alignment'] ?? null;
	if ( ! wpagent_spectra_static_advanced_heading_alignment_valid( $alignment ) ) {
		return new WP_Error( 'wpagent_spectra_static_heading_alignment', __( 'alignment muss exakt left, center oder right sein.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$viewport = $input['viewport'] ?? 'desktop';
	if ( ! wpagent_spectra_static_advanced_heading_viewport_valid( $viewport ) ) {
		return new WP_Error( 'wpagent_spectra_static_heading_viewport', __( 'viewport muss exakt desktop, tablet oder mobile sein.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$expected_hash = is_string( $input['expected_hash'] ?? null ) ? $input['expected_hash'] : '';
	if ( ! preg_match( '/^[a-f0-9]{64}$/D', $expected_hash ) ) {
		return new WP_Error( 'wpagent_spectra_static_heading_hash', __( 'expected_hash muss ein SHA-256-Hash sein.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$lock = wpagent_site_editor_acquire_lock( 'spectra-static-heading', (string) $post_id );
	if ( is_wp_error( $lock ) ) {
		return $lock;
	}
	try {
		$contract = wpagent_spectra_static_advanced_heading_contract();
		if ( is_wp_error( $contract ) ) {
			return $contract;
		}
		$before = wpagent_native_block_document_state( $post_id );
		if ( is_wp_error( $before ) ) {
			return $before;
		}
		if ( ! hash_equals( $before['hash'], $expected_hash ) ) {
			return new WP_Error( 'wpagent_spectra_static_heading_conflict', __( 'Das Blockdokument wurde seit dem Lesen verändert.', 'wp-agent-companion' ), array( 'status' => 409, 'current_hash' => $before['hash'] ) );
		}
		if ( strlen( $before['content'] ) > WPAGENT_SPECTRA_MAX_CONTENT_BYTES ) {
			return new WP_Error( 'wpagent_spectra_static_heading_content_limit', __( 'Das Blockdokument ist größer als 1 MB und wird nicht automatisch geändert.', 'wp-agent-companion' ), array( 'status' => 413 ) );
		}
		$blocks = parse_blocks( $before['content'] );
		if ( serialize_blocks( $blocks ) !== $before['content'] ) {
			return new WP_Error( 'wpagent_spectra_static_heading_noncanonical_document', __( 'Das bestehende statische Blockdokument ist nicht exakt parse- und serialisierbar und wird deshalb nicht automatisch verändert.', 'wp-agent-companion' ), array( 'status' => 409 ) );
		}
		$target = wpagent_spectra_static_advanced_heading_patch_path( $blocks, $path, $alignment, $viewport );
		if ( is_wp_error( $target ) ) {
			return $target;
		}
		$before_markup = wpagent_spectra_static_advanced_heading_static_markup_at_path( $blocks, $path, $target['block_id'] );
		if ( is_wp_error( $before_markup ) ) {
			return $before_markup;
		}
			if ( ! $target['changed'] ) {
				if ( ! wpagent_site_editor_refresh_lock( 'spectra-static-heading', (string) $post_id, $lock ) ) {
					return new WP_Error( 'wpagent_spectra_static_heading_lock_lost', __( 'Die exklusive Sperre ging vor der No-op-Prüfung verloren.', 'wp-agent-companion' ), array( 'status' => 409 ) );
				}
				$fresh = wpagent_spectra_static_heading_verify_noop_state(
					$post_id,
					$before['content'],
					$path,
					$target['block_id'],
					$before_markup,
					static function( array &$candidate ) use ( $path, $alignment, $viewport ) {
						return wpagent_spectra_static_advanced_heading_patch_path( $candidate, $path, $alignment, $viewport );
					}
				);
				if ( is_wp_error( $fresh ) ) {
					return $fresh;
				}
				if ( ! wpagent_site_editor_lock_is_owned( 'spectra-static-heading', (string) $post_id, $lock ) ) {
					return new WP_Error( 'wpagent_spectra_static_heading_lock_lost', __( 'Die exklusive Sperre ging während der No-op-Prüfung verloren.', 'wp-agent-companion' ), array( 'status' => 409 ) );
				}
				return array(
					'post_id' => $post_id, 'block_name' => $target['block_name'], 'path' => $path, 'alignment' => $alignment, 'viewport' => $viewport,
					'provider_version' => $contract['provider_version'], 'changed' => false, 'verified' => true, 'revision_id' => 0,
					'rendered_html_length' => strlen( $before_markup ), 'previous_hash' => $before['hash'], 'hash' => $fresh['hash'], 'cache' => wpagent_spectra_static_heading_noop_cache(),
				);
			}
		$candidate = serialize_blocks( $blocks );
		if ( strlen( $candidate ) > WPAGENT_SPECTRA_MAX_CONTENT_BYTES || serialize_blocks( parse_blocks( $candidate ) ) !== $candidate ) {
			return new WP_Error( 'wpagent_spectra_static_heading_serialization', __( 'Das geänderte statische Blockdokument ist nicht stabil serialisierbar oder überschreitet 1 MB.', 'wp-agent-companion' ), array( 'status' => 400 ) );
		}
		$before_report = array( 'block_count' => 0, 'freeform_count' => 0, 'block_types' => array() );
		$after_report = array( 'block_count' => 0, 'freeform_count' => 0, 'block_types' => array() );
		wpagent_native_block_report_walk( parse_blocks( $before['content'] ), $before_report );
		wpagent_native_block_report_walk( parse_blocks( $candidate ), $after_report );
		if ( $before_report !== $after_report ) {
			return new WP_Error( 'wpagent_spectra_static_heading_structure_changed', __( 'Der Ausrichtungs-Patch würde die Blockstruktur verändern und wurde abgelehnt.', 'wp-agent-companion' ), array( 'status' => 400 ) );
		}
		$candidate_blocks = parse_blocks( $candidate );
		$candidate_target = wpagent_spectra_static_advanced_heading_patch_path( $candidate_blocks, $path, $alignment, $viewport );
		$candidate_markup = wpagent_spectra_static_advanced_heading_static_markup_at_path( $candidate_blocks, $path, $target['block_id'] );
		if ( ! is_array( $candidate_target ) || ! is_string( $candidate_markup ) || $candidate_target['changed'] || ! hash_equals( $before_markup, $candidate_markup ) ) {
			return new WP_Error( 'wpagent_spectra_static_heading_structure_changed', __( 'Der Ausrichtungs-Patch würde das statische Ziel-Markup oder seinen Strukturvertrag verändern und wurde abgelehnt.', 'wp-agent-companion' ), array( 'status' => 400 ) );
		}
		if ( ! wpagent_site_editor_refresh_lock( 'spectra-static-heading', (string) $post_id, $lock ) ) {
			return new WP_Error( 'wpagent_spectra_static_heading_lock_lost', __( 'Die exklusive Sperre ging vor der statischen Spectra-Änderung verloren.', 'wp-agent-companion' ), array( 'status' => 409 ) );
		}
		$revision_id = wpagent_native_block_create_revision( $post_id, $before['content'] );
		if ( is_wp_error( $revision_id ) ) {
			return $revision_id;
		}
		if ( ! wpagent_site_editor_refresh_lock( 'spectra-static-heading', (string) $post_id, $lock ) ) {
			return new WP_Error( 'wpagent_spectra_static_heading_lock_lost', __( 'Die exklusive Sperre ging vor dem statischen Spectra-Write verloren.', 'wp-agent-companion' ), array( 'status' => 409, 'revision_id' => $revision_id ) );
		}
		$saved = wpagent_native_block_write_if_current( $post_id, $before['content'], $candidate );
		if ( is_wp_error( $saved ) ) {
			$error_data = $saved->get_error_data();
			return new WP_Error( $saved->get_error_code(), $saved->get_error_message(), array_merge( is_array( $error_data ) ? $error_data : array(), array( 'revision_id' => $revision_id ) ) );
		}
		if ( ! wpagent_site_editor_lock_is_owned( 'spectra-static-heading', (string) $post_id, $lock ) ) {
			return wpagent_spectra_static_heading_lock_lost_after_write( $revision_id );
		}
		$after_raw = wpagent_native_block_raw_content( $post_id );
		$after = wpagent_native_block_document_state( $post_id );
		$verified_blocks = ! is_wp_error( $after_raw ) && $after_raw === $candidate && ! is_wp_error( $after ) && $after['content'] === $candidate ? parse_blocks( $after_raw ) : array();
		$verified_target = $verified_blocks ? wpagent_spectra_static_advanced_heading_patch_path( $verified_blocks, $path, $alignment, $viewport ) : null;
		$verified_markup = $verified_blocks ? wpagent_spectra_static_advanced_heading_static_markup_at_path( $verified_blocks, $path, $target['block_id'] ) : null;
		$verified = is_string( $after_raw ) && $after_raw === $candidate && is_array( $after ) && ! is_wp_error( $after ) && $after['content'] === $candidate && is_array( $verified_target ) && ! $verified_target['changed'] && is_string( $verified_markup ) && hash_equals( $before_markup, $verified_markup );
		if ( ! $verified ) {
			$rollback = wpagent_native_block_rollback( $post_id, $before['content'], $candidate );
			return wpagent_spectra_static_heading_write_error( 'wpagent_spectra_static_heading_verify_failed', __( 'Die statische Spectra-Überschrift bestand die Parse-, Rücklese- oder Frontend-Prüfung nicht.', 'wp-agent-companion' ), $revision_id, $rollback );
		}
		if ( ! wpagent_site_editor_refresh_lock( 'spectra-static-heading', (string) $post_id, $lock ) ) {
			return wpagent_spectra_static_heading_lock_lost_after_write( $revision_id );
		}
		$cache = wpagent_spectra_static_heading_refresh_cache( $post_id );
		if ( ! wpagent_site_editor_lock_is_owned( 'spectra-static-heading', (string) $post_id, $lock ) ) {
			return wpagent_spectra_static_heading_lock_lost_after_write( $revision_id );
		}
		if ( ! $cache['verified'] ) {
			$rollback = wpagent_spectra_static_heading_rollback_after_cache( $post_id, $before['content'], $candidate );
			return wpagent_spectra_static_heading_write_error( 'wpagent_spectra_static_heading_cache_failed', __( 'Spectras Beitrags- und Asset-Cache konnte nicht verifiziert aktualisiert werden.', 'wp-agent-companion' ), $revision_id, $rollback );
		}
		$after_cache_raw = wpagent_native_block_raw_content( $post_id );
		$after_cache = wpagent_native_block_document_state( $post_id );
		$after_cache_blocks = ! is_wp_error( $after_cache_raw ) && $after_cache_raw === $candidate && ! is_wp_error( $after_cache ) && $after_cache['content'] === $candidate ? parse_blocks( $after_cache_raw ) : array();
		$after_cache_target = $after_cache_blocks ? wpagent_spectra_static_advanced_heading_patch_path( $after_cache_blocks, $path, $alignment, $viewport ) : null;
		$after_cache_markup = $after_cache_blocks ? wpagent_spectra_static_advanced_heading_static_markup_at_path( $after_cache_blocks, $path, $target['block_id'] ) : null;
		$cache_verified = is_string( $after_cache_raw ) && $after_cache_raw === $candidate && is_array( $after_cache ) && ! is_wp_error( $after_cache ) && $after_cache['content'] === $candidate
			&& is_array( $after_cache_target ) && ! $after_cache_target['changed'] && is_string( $after_cache_markup ) && hash_equals( $before_markup, $after_cache_markup );
		if ( ! $cache_verified ) {
			$rollback = wpagent_spectra_static_heading_rollback_after_cache( $post_id, $before['content'], $candidate );
			return wpagent_spectra_static_heading_write_error( 'wpagent_spectra_static_heading_cache_readback_failed', __( 'Spectras Cache-Nachlauf veränderte den gespeicherten statischen Blockzustand oder konnte ihn nicht erneut verifizieren.', 'wp-agent-companion' ), $revision_id, $rollback );
		}
		if ( ! wpagent_site_editor_refresh_lock( 'spectra-static-heading', (string) $post_id, $lock ) ) {
			return wpagent_spectra_static_heading_lock_lost_after_write( $revision_id );
		}
		return array(
			'post_id' => $post_id, 'block_name' => $target['block_name'], 'path' => $path, 'alignment' => $alignment, 'viewport' => $viewport,
			'provider_version' => $contract['provider_version'], 'changed' => true, 'verified' => true, 'revision_id' => $revision_id,
			'rendered_html_length' => strlen( $verified_markup ), 'previous_hash' => $before['hash'], 'hash' => $after_cache['hash'], 'cache' => $cache,
		);
	} finally {
		wpagent_site_editor_release_lock( 'spectra-static-heading', (string) $post_id, $lock );
	}
}
