<?php
/** Strict, version-bound CTA writes for one Kadence Blocks Free single button. */

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

const WPAGENT_KADENCE_SINGLE_BUTTON_VERSION           = '3.7.8';
const WPAGENT_KADENCE_SINGLE_BUTTON_BLOCK             = 'kadence/singlebtn';
const WPAGENT_KADENCE_SINGLE_BUTTON_PARENT            = 'kadence/advancedbtn';
const WPAGENT_KADENCE_SINGLE_BUTTON_MAX_TEXT_LENGTH   = 200;
const WPAGENT_KADENCE_SINGLE_BUTTON_MAX_LINK_LENGTH   = 2048;
const WPAGENT_KADENCE_SINGLE_BUTTON_MAX_CONTENT_BYTES = 1048576;

/** @return array{provider_version:string,block_name:string,parent_name:string}|WP_Error */
function wpagent_kadence_single_button_contract() {
	if ( ! defined( 'KADENCE_BLOCKS_VERSION' ) || ! hash_equals( WPAGENT_KADENCE_SINGLE_BUTTON_VERSION, (string) KADENCE_BLOCKS_VERSION ) ) {
		return new WP_Error( 'wpagent_kadence_single_button_provider', __( 'Der Kadence-Single-Button-Vertrag erfordert exakt Kadence Blocks 3.7.8.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	$registry = WP_Block_Type_Registry::get_instance();
	$button   = $registry->get_registered( WPAGENT_KADENCE_SINGLE_BUTTON_BLOCK );
	$parent   = $registry->get_registered( WPAGENT_KADENCE_SINGLE_BUTTON_PARENT );
	if ( ! $button instanceof WP_Block_Type || ! $parent instanceof WP_Block_Type
		|| WPAGENT_KADENCE_SINGLE_BUTTON_BLOCK !== $button->name || WPAGENT_KADENCE_SINGLE_BUTTON_PARENT !== $parent->name
		|| 3 !== (int) $button->api_version || 3 !== (int) $parent->api_version
		|| ! is_callable( $button->render_callback ) || ! is_callable( $parent->render_callback )
		|| array( WPAGENT_KADENCE_SINGLE_BUTTON_PARENT ) !== array_values( (array) $button->parent ) ) {
		return new WP_Error( 'wpagent_kadence_single_button_provider', __( 'Der registrierte Kadence-Single-Button-, Eltern- oder Rendervertrag ist nicht verfügbar.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	$attributes = $button->get_attributes();
	foreach ( array( 'text' => 'string', 'link' => 'string', 'target' => 'string', 'noFollow' => 'boolean', 'sponsored' => 'boolean', 'download' => 'boolean', 'buttonRole' => 'boolean' ) as $attribute => $type ) {
		if ( ! is_array( $attributes[ $attribute ] ?? null ) || $type !== ( $attributes[ $attribute ]['type'] ?? null ) ) {
			return new WP_Error( 'wpagent_kadence_single_button_provider', __( 'Das registrierte Kadence-Single-Button-Schema stimmt nicht mit dem getesteten Providervertrag überein.', 'wp-agent-companion' ), array( 'status' => 409 ) );
		}
	}
	if ( '_self' !== ( $attributes['target']['default'] ?? null ) || false !== ( $attributes['noFollow']['default'] ?? null )
		|| false !== ( $attributes['sponsored']['default'] ?? null ) || false !== ( $attributes['download']['default'] ?? null ) || false !== ( $attributes['buttonRole']['default'] ?? null ) ) {
		return new WP_Error( 'wpagent_kadence_single_button_provider', __( 'Die Kadence-Single-Button-Vorgaben stimmen nicht mit dem getesteten Rendervertrag überein.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	return array( 'provider_version' => (string) KADENCE_BLOCKS_VERSION, 'block_name' => $button->name, 'parent_name' => $parent->name );
}

/** @return array<string,mixed> */
function wpagent_ability_update_kadence_single_button(): array {
	$button = array(
		'text'       => array( 'type' => 'string', 'minLength' => 1, 'maxLength' => WPAGENT_KADENCE_SINGLE_BUTTON_MAX_TEXT_LENGTH ),
		'link'       => array( 'type' => 'string', 'minLength' => 1, 'maxLength' => WPAGENT_KADENCE_SINGLE_BUTTON_MAX_LINK_LENGTH ),
		'target'     => array( 'type' => 'string', 'enum' => array( '_self', '_blank' ) ),
		'noFollow'   => array( 'type' => 'boolean' ),
		'sponsored'  => array( 'type' => 'boolean' ),
		'download'   => array( 'type' => 'boolean' ),
		'buttonRole' => array( 'type' => 'boolean' ),
	);
	return array(
		'label'       => __( 'Kadence-Single-Button aktualisieren', 'wp-agent-companion' ),
		'description' => __( 'Ändert ausschließlich Text, Link, Ziel und vier native Link-Flags eines eindeutig einzigen Kadence-Single-Buttons in einem Kadence-Advanced-Button. Markup, Stil, Icons, CSS und alle übrigen Providerattribute 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' => 2, 'maxItems' => 32, 'items' => array( 'type' => 'integer', 'minimum' => 0, 'maximum' => 10000 ) ),
				'patch'         => array( 'type' => 'object', 'properties' => $button, 'minProperties' => 1, 'maxProperties' => 7, 'additionalProperties' => false ),
				'expected_hash' => array( 'type' => 'string', 'pattern' => '^[a-f0-9]{64}$' ),
			),
			'required'             => array( 'post_id', 'path', 'patch', 'expected_hash' ),
			'additionalProperties' => false,
		),
		'output_schema' => array(
			'type'       => 'object',
			'properties' => array(
				'post_id'          => array( 'type' => 'integer' ),
				'block_name'       => array( 'type' => 'string', 'enum' => array( WPAGENT_KADENCE_SINGLE_BUTTON_BLOCK ) ),
				'path'             => array( 'type' => 'array', 'items' => array( 'type' => 'integer' ) ),
				'button'           => array( 'type' => 'object', 'properties' => $button, 'required' => array_keys( $button ), 'additionalProperties' => false ),
				'provider_version' => array( 'type' => 'string', 'enum' => array( WPAGENT_KADENCE_SINGLE_BUTTON_VERSION ) ),
				'changed'          => array( 'type' => 'boolean' ),
				'verified'         => array( 'type' => 'boolean' ),
				'revision_id'      => array( 'type' => 'integer', 'minimum' => 0 ),
				'rendered_html_length' => array( 'type' => 'integer', 'minimum' => 1 ),
				'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( 'kadence' ) ), 'executed' => array( 'type' => 'boolean' ), 'verified' => array( 'type' => 'boolean' ),
				), 'required' => array( 'builder', 'executed', 'verified' ), 'additionalProperties' => false ),
			),
			'required'             => array( 'post_id', 'block_name', 'path', 'button', 'provider_version', 'changed', 'verified', 'revision_id', 'rendered_html_length', 'previous_hash', 'hash', 'cache' ),
			'additionalProperties' => false,
		),
		'execute_callback'    => 'wpagent_exec_update_kadence_single_button',
		'permission_callback' => 'wpagent_perm_edit_posts',
		'meta'                => array( 'show_in_rest' => true, 'annotations' => array( 'readonly' => false, 'destructive' => false, 'idempotent' => false ) ),
	);
}

/** @return string|WP_Error */
function wpagent_kadence_single_button_plain_text( $value, string $field, int $status = 400 ) {
	$text = is_string( $value ) ? $value : '';
	$decoded = is_string( $value ) ? html_entity_decode( $value, ENT_QUOTES | ENT_HTML5, 'UTF-8' ) : '';
	$invalid = ! is_string( $value ) || '' === $text || $text !== trim( $text ) || wpagent_native_block_string_length( $text ) > WPAGENT_KADENCE_SINGLE_BUTTON_MAX_TEXT_LENGTH
		|| wp_check_invalid_utf8( $text ) !== $text || $decoded !== $text
		|| preg_match( '/(?:&(?:#[0-9]+|#x[0-9a-f]+|[a-z][a-z0-9]+);|[<>]|[\x00-\x1F\x7F-\x9F]|[\x{061C}\x{200E}\x{200F}\x{202A}-\x{202E}\x{2066}-\x{2069}])/iu', $text )
		|| preg_match( '/\[[^\]\r\n]{1,200}\]/u', $text );
	if ( $invalid ) {
		return new WP_Error( 'wpagent_kadence_single_button_text', sprintf( __( '%s muss reiner, nicht steuernder Klartext mit höchstens 200 Zeichen sein.', 'wp-agent-companion' ), $field ), array( 'status' => $status ) );
	}
	return $text;
}

/** @return string|WP_Error */
function wpagent_kadence_single_button_validate_link( $value, string $field = 'link', int $status = 400 ) {
	$link = is_string( $value ) ? $value : '';
	if ( ! is_string( $value ) || '' === $link || $link !== trim( $link ) || strlen( $link ) > WPAGENT_KADENCE_SINGLE_BUTTON_MAX_LINK_LENGTH
		|| wp_check_invalid_utf8( $link ) !== $link || preg_match( '/[\s<>"\'\x00-\x1F\x7F-\x9F\x{061C}\x{200E}\x{200F}\x{202A}-\x{202E}\x{2066}-\x{2069}]/u', $link )
		|| preg_match( '/&(?:#[0-9]+|#x[0-9a-f]+|[a-z][a-z0-9]+);/iu', $link ) || preg_match( '/\[[^\]\r\n]{1,200}\]/u', $link )
		|| esc_url_raw( $link ) !== $link ) {
		return new WP_Error( 'wpagent_kadence_single_button_link', sprintf( __( '%s muss eine sichere Same-Origin- oder HTTPS-URL sein.', 'wp-agent-companion' ), $field ), array( 'status' => $status ) );
	}
	if ( str_starts_with( $link, '/' ) ) {
		if ( str_starts_with( $link, '//' ) ) {
			return new WP_Error( 'wpagent_kadence_single_button_link', __( 'Protokollrelative Links sind nicht erlaubt.', 'wp-agent-companion' ), array( 'status' => $status ) );
		}
		return $link;
	}
	if ( str_starts_with( $link, '?' ) || str_starts_with( $link, '#' ) ) {
		return $link;
	}
	$parts = wp_parse_url( $link );
	if ( ! is_array( $parts ) || ! isset( $parts['scheme'], $parts['host'] ) || isset( $parts['user'], $parts['pass'] ) || ! is_string( $parts['scheme'] ) || ! is_string( $parts['host'] ) ) {
		return new WP_Error( 'wpagent_kadence_single_button_link', __( 'Der Buttonlink muss absolut HTTPS oder relativ zur eigenen Website sein.', 'wp-agent-companion' ), array( 'status' => $status ) );
	}
	$scheme = strtolower( $parts['scheme'] );
	if ( 'https' === $scheme ) {
		return $link;
	}
	$home = wp_parse_url( home_url( '/' ) );
	$same_origin = is_array( $home ) && isset( $home['scheme'], $home['host'] )
		&& strtolower( (string) $home['scheme'] ) === $scheme && strtolower( (string) $home['host'] ) === strtolower( $parts['host'] )
		&& (int) ( $home['port'] ?? 0 ) === (int) ( $parts['port'] ?? 0 );
	if ( ! $same_origin ) {
		return new WP_Error( 'wpagent_kadence_single_button_link', __( 'Der Buttonlink muss HTTPS verwenden oder exakt zur eigenen Website gehören.', 'wp-agent-companion' ), array( 'status' => $status ) );
	}
	return $link;
}

/** @return array<string,mixed>|WP_Error */
function wpagent_kadence_single_button_validate_patch( $patch ) {
	if ( ! is_array( $patch ) || wp_is_numeric_array( $patch ) || array() === $patch || count( $patch ) > 7 ) {
		return new WP_Error( 'wpagent_kadence_single_button_patch', __( 'patch muss ein nicht leeres Objekt mit höchstens sieben freigegebenen Buttonwerten sein.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$allowed = array( 'text', 'link', 'target', 'noFollow', 'sponsored', 'download', 'buttonRole' );
	foreach ( $patch as $key => $value ) {
		if ( ! is_string( $key ) || ! in_array( $key, $allowed, true ) ) {
			return new WP_Error( 'wpagent_kadence_single_button_patch', __( 'patch enthält ein nicht freigegebenes Buttonattribut.', 'wp-agent-companion' ), array( 'status' => 400 ) );
		}
		if ( 'text' === $key ) {
			$valid = wpagent_kadence_single_button_plain_text( $value, 'text' );
		} elseif ( 'link' === $key ) {
			$valid = wpagent_kadence_single_button_validate_link( $value );
		} elseif ( 'target' === $key ) {
			$valid = is_string( $value ) && in_array( $value, array( '_self', '_blank' ), true ) ? $value : new WP_Error( 'wpagent_kadence_single_button_target', __( 'target muss _self oder _blank sein.', 'wp-agent-companion' ), array( 'status' => 400 ) );
		} else {
			$valid = is_bool( $value ) ? $value : new WP_Error( 'wpagent_kadence_single_button_flag', __( 'Die nativen Link-Flags müssen boolesch sein.', 'wp-agent-companion' ), array( 'status' => 400 ) );
		}
		if ( is_wp_error( $valid ) ) {
			return $valid;
		}
		$patch[ $key ] = $valid;
	}
	return $patch;
}

/** @return array{post:WP_Post,post_type:string,status:string}|WP_Error */
function wpagent_kadence_single_button_editable_post( int $post_id ) {
	$post = get_post( $post_id );
	if ( ! $post instanceof WP_Post ) {
		return new WP_Error( 'wpagent_kadence_single_button_not_found', __( 'Der Kadence-Button-Beitrag wurde nicht gefunden.', 'wp-agent-companion' ), array( 'status' => 404 ) );
	}
	if ( ! current_user_can( 'edit_post', $post_id ) ) {
		return new WP_Error( 'wpagent_kadence_single_button_forbidden', __( 'Keine Berechtigung für diesen Kadence-Button-Beitrag.', 'wp-agent-companion' ), array( 'status' => 403 ) );
	}
	if ( ! post_type_supports( $post->post_type, 'editor' ) || ! in_array( $post->post_status, array( 'publish', 'future', 'draft', 'pending', 'private' ), true ) ) {
		return new WP_Error( 'wpagent_kadence_single_button_post_state', __( 'Der Zielbeitrag besitzt keinen bearbeitbaren Blockzustand.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	return array( 'post' => $post, 'post_type' => (string) $post->post_type, 'status' => (string) $post->post_status );
}

/** @param array{post:WP_Post,post_type:string,status:string} $before @param array{post:WP_Post,post_type:string,status:string} $after */
function wpagent_kadence_single_button_same_post_state( array $before, array $after ): bool {
	return (int) $before['post']->ID === (int) $after['post']->ID && hash_equals( $before['post_type'], $after['post_type'] ) && hash_equals( $before['status'], $after['status'] );
}

/** @param array<string,mixed> $block @return array{text:string,link:string,target:string,noFollow:bool,sponsored:bool,download:bool,buttonRole:bool}|WP_Error */
function wpagent_kadence_single_button_state_from_block( array $block ) {
	if ( WPAGENT_KADENCE_SINGLE_BUTTON_BLOCK !== ( $block['blockName'] ?? null ) || ! is_array( $block['innerBlocks'] ?? null ) || array() !== $block['innerBlocks']
		|| '' !== ( $block['innerHTML'] ?? null ) || array() !== ( $block['innerContent'] ?? null ) || ! is_array( $block['attrs'] ?? null ) ) {
		return new WP_Error( 'wpagent_kadence_single_button_target', __( 'Der Zielblock erfüllt nicht den engen nativen Kadence-Single-Button-Markupvertrag.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	$attrs = $block['attrs'];
	$text  = wpagent_kadence_single_button_plain_text( $attrs['text'] ?? null, 'gespeicherter Buttontext', 409 );
	$link  = wpagent_kadence_single_button_validate_link( $attrs['link'] ?? null, 'gespeicherter Buttonlink', 409 );
	$target = $attrs['target'] ?? '_self';
	if ( is_wp_error( $text ) || is_wp_error( $link ) || ! is_string( $target ) || ! in_array( $target, array( '_self', '_blank' ), true ) ) {
		return new WP_Error( 'wpagent_kadence_single_button_target', __( 'Der gespeicherte Kadence-Single-Button enthält keinen verifizierbaren sicheren CTA-Zustand.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	$state = array( 'text' => $text, 'link' => $link, 'target' => $target );
	foreach ( array( 'noFollow', 'sponsored', 'download', 'buttonRole' ) as $flag ) {
		$value = $attrs[ $flag ] ?? false;
		if ( ! is_bool( $value ) ) {
			return new WP_Error( 'wpagent_kadence_single_button_target', __( 'Der gespeicherte Kadence-Single-Button enthält ein ungültiges Link-Flag.', 'wp-agent-companion' ), array( 'status' => 409 ) );
		}
		$state[ $flag ] = $value;
	}
	return $state;
}

/** @param array<int,array<string,mixed>> $blocks @param array<int,int> $path @return array{block:array<string,mixed>,parent:array<string,mixed>,button:array<string,mixed>}|WP_Error */
function wpagent_kadence_single_button_target_at_path( array $blocks, array $path, int $depth = 0, ?array $parent = null ) {
	$index = $path[ $depth ];
	if ( ! isset( $blocks[ $index ] ) || ! is_array( $blocks[ $index ] ) ) {
		return new WP_Error( 'wpagent_kadence_single_button_path', __( 'Der Kadence-Single-Buttonpfad wurde im aktuellen Dokument nicht gefunden.', 'wp-agent-companion' ), array( 'status' => 404 ) );
	}
	$block = $blocks[ $index ];
	if ( $depth + 1 < count( $path ) ) {
		return is_array( $block['innerBlocks'] ?? null ) ? wpagent_kadence_single_button_target_at_path( $block['innerBlocks'], $path, $depth + 1, $block ) : new WP_Error( 'wpagent_kadence_single_button_path', __( 'Der Kadence-Single-Buttonpfad wurde im aktuellen Dokument nicht gefunden.', 'wp-agent-companion' ), array( 'status' => 404 ) );
	}
	if ( ! is_array( $parent ) || 0 !== $index || WPAGENT_KADENCE_SINGLE_BUTTON_PARENT !== ( $parent['blockName'] ?? null )
		|| ! is_array( $parent['innerBlocks'] ?? null ) || count( $parent['innerBlocks'] ) !== 1 ) {
		return new WP_Error( 'wpagent_kadence_single_button_parent', __( 'Der Zielbutton muss der einzige direkte Kadence-Single-Button eines Kadence-Advanced-Buttons sein.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	$button = wpagent_kadence_single_button_state_from_block( $block );
	return is_wp_error( $button ) ? $button : array( 'block' => $block, 'parent' => $parent, 'button' => $button );
}

/** @param array<int,array<string,mixed>> $blocks @param array<int,int> $path @param array<string,mixed> $patch @return array{block_name:string,button:array<string,mixed>,changed:bool}|WP_Error */
function wpagent_kadence_single_button_patch_path( array &$blocks, array $path, array $patch, int $depth = 0, ?array $parent = null ) {
	$index = $path[ $depth ];
	if ( ! isset( $blocks[ $index ] ) || ! is_array( $blocks[ $index ] ) ) {
		return new WP_Error( 'wpagent_kadence_single_button_path', __( 'Der Kadence-Single-Buttonpfad wurde im aktuellen Dokument nicht gefunden.', 'wp-agent-companion' ), array( 'status' => 404 ) );
	}
	if ( $depth + 1 < count( $path ) ) {
		if ( ! is_array( $blocks[ $index ]['innerBlocks'] ?? null ) ) {
			return new WP_Error( 'wpagent_kadence_single_button_path', __( 'Der Kadence-Single-Buttonpfad wurde im aktuellen Dokument nicht gefunden.', 'wp-agent-companion' ), array( 'status' => 404 ) );
		}
		return wpagent_kadence_single_button_patch_path( $blocks[ $index ]['innerBlocks'], $path, $patch, $depth + 1, $blocks[ $index ] );
	}
	if ( ! is_array( $parent ) || 0 !== $index || WPAGENT_KADENCE_SINGLE_BUTTON_PARENT !== ( $parent['blockName'] ?? null )
		|| ! is_array( $parent['innerBlocks'] ?? null ) || count( $parent['innerBlocks'] ) !== 1 ) {
		return new WP_Error( 'wpagent_kadence_single_button_parent', __( 'Der Zielbutton muss der einzige direkte Kadence-Single-Button eines Kadence-Advanced-Buttons sein.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	$before = wpagent_kadence_single_button_state_from_block( $blocks[ $index ] );
	if ( is_wp_error( $before ) ) {
		return $before;
	}
	$attrs = $blocks[ $index ]['attrs'];
	foreach ( $patch as $key => $value ) {
		if ( $before[ $key ] !== $value ) {
			$attrs[ $key ] = $value;
		}
	}
	$blocks[ $index ]['attrs'] = $attrs;
	$after = wpagent_kadence_single_button_state_from_block( $blocks[ $index ] );
	return is_wp_error( $after ) ? $after : array( 'block_name' => WPAGENT_KADENCE_SINGLE_BUTTON_BLOCK, 'button' => $after, 'changed' => $after !== $before );
}

/** @param array<int,array<string,mixed>> $blocks @param array<int,int> $path @return array<int,array<string,mixed>> */
function wpagent_kadence_single_button_mask_patch_values( array $blocks, array $path, int $depth = 0 ): array {
	$index = $path[ $depth ];
	if ( ! isset( $blocks[ $index] ) || ! is_array( $blocks[ $index ] ) ) {
		return $blocks;
	}
	if ( $depth + 1 < count( $path ) && is_array( $blocks[ $index ]['innerBlocks'] ?? null ) ) {
		$blocks[ $index ]['innerBlocks'] = wpagent_kadence_single_button_mask_patch_values( $blocks[ $index ]['innerBlocks'], $path, $depth + 1 );
		return $blocks;
	}
	if ( $depth + 1 === count( $path ) && is_array( $blocks[ $index ]['attrs'] ?? null ) ) {
		foreach ( array( 'text', 'link', 'target', 'noFollow', 'sponsored', 'download', 'buttonRole' ) as $key ) {
			unset( $blocks[ $index ]['attrs'][ $key ] );
		}
	}
	return $blocks;
}

/** @param array{parent:array<string,mixed>,button:array<string,mixed>} $target @return string|WP_Error */
function wpagent_kadence_single_button_render_target( array $target ) {
	$content = serialize_blocks( array( $target['parent'] ) );
	if ( '' === $content || serialize_blocks( parse_blocks( $content ) ) !== $content ) {
		return new WP_Error( 'wpagent_kadence_single_button_render', __( 'Der isolierte Kadence-CTA-Zweig ist nicht stabil serialisierbar.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	try {
		$html = do_blocks( $content );
	} catch ( Throwable $error ) {
		return new WP_Error( 'wpagent_kadence_single_button_render', __( 'Der Kadence-Single-Button konnte nicht serverseitig gerendert werden.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	if ( ! is_string( $html ) || 1 !== preg_match_all( '/<a\\b[^>]*>.*?<\\/a>/is', $html, $anchors ) ) {
		return new WP_Error( 'wpagent_kadence_single_button_render', __( 'Der Kadence-Single-Button-Output erfüllt nicht den getesteten einzelnen Linkvertrag.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	$anchor = $anchors[0][0];
	if ( 1 !== preg_match( '/<span\\s+class="kt-btn-inner-text">([^<]*)<\\/span>/D', $anchor, $text ) || ! hash_equals( $target['button']['text'], $text[1] ) ) {
		return new WP_Error( 'wpagent_kadence_single_button_render', __( 'Der sichtbare Kadence-Single-Button-Text weicht vom verifizierten Klartext ab.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	$attribute = static function ( string $name ) use ( $anchor ): ?string {
		$pattern = '/\\s' . preg_quote( $name, '/' ) . '\\s*=\\s*(["\\\'])(.*?)\\1/is';
		return 1 === preg_match( $pattern, $anchor, $match ) ? html_entity_decode( $match[2], ENT_QUOTES | ENT_HTML5, 'UTF-8' ) : null;
	};
	if ( $attribute( 'href' ) !== $target['button']['link'] || ( '_blank' === $target['button']['target'] && '_blank' !== $attribute( 'target' ) ) || ( '_self' === $target['button']['target'] && null !== $attribute( 'target' ) ) ) {
		return new WP_Error( 'wpagent_kadence_single_button_render', __( 'Der gerenderte Kadence-Single-Button-Link oder sein Ziel weicht vom geprüften Zustand ab.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	$expected_rel = array();
	if ( '_blank' === $target['button']['target'] ) {
		$expected_rel = array( 'noreferrer', 'noopener' );
	}
	foreach ( array( 'noFollow' => 'nofollow', 'sponsored' => 'sponsored' ) as $flag => $token ) {
		if ( $target['button'][ $flag ] ) {
			$expected_rel[] = $token;
		}
	}
	$actual_rel = null === $attribute( 'rel' ) ? array() : preg_split( '/\\s+/', trim( (string) $attribute( 'rel' ) ) );
	sort( $expected_rel, SORT_STRING );
	sort( $actual_rel, SORT_STRING );
	$has_download = 1 === preg_match( '/\\sdownload(?:\\s|=|>)/i', $anchor );
	if ( $expected_rel !== $actual_rel || $has_download !== $target['button']['download'] || ( $target['button']['buttonRole'] && 'button' !== $attribute( 'role' ) ) || ( ! $target['button']['buttonRole'] && null !== $attribute( 'role' ) ) ) {
		return new WP_Error( 'wpagent_kadence_single_button_render', __( 'Der gerenderte Kadence-Single-Button-Linkvertrag weicht bei rel, download oder role ab.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	return $html;
}

/** @param array<int,array<string,mixed>> $blocks @param array<int,int> $path @return array{target:array{parent:array<string,mixed>,button:array<string,mixed>},html:string}|WP_Error */
function wpagent_kadence_single_button_target_state( array $blocks, array $path ) {
	$target = wpagent_kadence_single_button_target_at_path( $blocks, $path );
	if ( is_wp_error( $target ) ) {
		return $target;
	}
	$html = wpagent_kadence_single_button_render_target( $target );
	return is_wp_error( $html ) ? $html : array( 'target' => array( 'parent' => $target['parent'], 'button' => $target['button'] ), 'html' => $html );
}

/** @return array{builder:string,executed:bool,verified:bool} */
function wpagent_kadence_single_button_refresh_cache( int $post_id ): array {
	try {
		clean_post_cache( $post_id );
		wp_cache_delete( $post_id, 'posts' );
		return array( 'builder' => 'kadence', 'executed' => true, 'verified' => true );
	} catch ( Throwable $error ) {
		return array( 'builder' => 'kadence', 'executed' => true, 'verified' => false );
	}
}

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

/** @return array{rolled_back:bool,rollback_verified:bool,recovery_required:bool} */
function wpagent_kadence_single_button_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_kadence_single_button_refresh_cache( $post_id );
	$raw   = wpagent_native_block_raw_content( $post_id );
	$state = wpagent_native_block_document_state( $post_id );
	if ( ! $cache['verified'] || is_wp_error( $raw ) || $raw !== $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_kadence_single_button_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'] );
	return $rollback['recovery_required'] ? new WP_Error( 'wpagent_kadence_single_button_recovery_required', __( 'Der Kadence-Single-Button konnte nicht vollständig verifiziert werden. Die angelegte Revision bleibt für eine manuelle Wiederherstellung erhalten.', 'wp-agent-companion' ), $data ) : new WP_Error( $code, $message, $data );
}

/** @return WP_Error */
function wpagent_kadence_single_button_lock_lost_after_write( int $revision_id, int $post_id, string $before_content, string $candidate_content ) {
	$raw = wpagent_native_block_raw_content( $post_id );
	$rollback = is_string( $raw ) && $raw === $candidate_content ? wpagent_kadence_single_button_rollback_after_cache( $post_id, $before_content, $candidate_content ) : array( 'rolled_back' => false, 'rollback_verified' => false, 'recovery_required' => true );
	// A byte-exact rollback can restore the content, but the lock's ownership was
	// already lost. Do not advertise that cross-process state as fully verified.
	$rollback['rollback_verified'] = false;
	$rollback['recovery_required'] = true;
	return wpagent_kadence_single_button_write_error( 'wpagent_kadence_single_button_lock_lost', __( 'Die exklusive Sperre ging nach Beginn der Kadence-Single-Buttonänderung verloren. Es wurde nur bei bytegenauem Besitz bedingt zurückgesetzt.', 'wp-agent-companion' ), $revision_id, $rollback );
}

/** @return array<string,mixed>|WP_Error */
function wpagent_exec_update_kadence_single_button( $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 ) || count( $path ) < 2 ) {
		return is_wp_error( $path_ok ) ? $path_ok : new WP_Error( 'wpagent_kadence_single_button_path', __( 'path muss einen direkten Single-Button innerhalb eines Advanced-Buttons bezeichnen.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$patch = wpagent_kadence_single_button_validate_patch( $input['patch'] ?? null );
	if ( is_wp_error( $patch ) ) {
		return $patch;
	}
	$expected_hash = is_string( $input['expected_hash'] ?? null ) ? $input['expected_hash'] : '';
	if ( 1 !== preg_match( '/^[a-f0-9]{64}$/D', $expected_hash ) ) {
		return new WP_Error( 'wpagent_kadence_single_button_hash', __( 'expected_hash muss ein SHA-256-Hash sein.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$editable = wpagent_kadence_single_button_editable_post( $post_id );
	if ( is_wp_error( $editable ) ) {
		return $editable;
	}
	$contract = wpagent_kadence_single_button_contract();
	if ( is_wp_error( $contract ) ) {
		return $contract;
	}
	$blog_id = (int) get_current_blog_id();
	$lock = wpagent_site_editor_acquire_lock( 'kadence-single-button', (string) $post_id );
	if ( is_wp_error( $lock ) ) {
		return $lock;
	}
	try {
		$fresh_editable = wpagent_kadence_single_button_editable_post( $post_id );
		if ( is_wp_error( $fresh_editable ) || ! wpagent_kadence_single_button_same_post_state( $editable, $fresh_editable ) || $blog_id !== (int) get_current_blog_id() || is_wp_error( wpagent_kadence_single_button_contract() ) ) {
			return new WP_Error( 'wpagent_kadence_single_button_precondition_changed', __( 'Berechtigung, Blog, Postzustand oder Kadence-Laufzeit änderten sich vor dem Schreiben.', 'wp-agent-companion' ), array( 'status' => 409 ) );
		}
		$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_kadence_single_button_conflict', __( 'Das Kadence-Button-Dokument wurde seit dem Lesen verändert.', 'wp-agent-companion' ), array( 'status' => 409, 'current_hash' => $before['hash'] ) );
		}
		if ( strlen( $before['content'] ) > WPAGENT_KADENCE_SINGLE_BUTTON_MAX_CONTENT_BYTES || serialize_blocks( $blocks = parse_blocks( $before['content'] ) ) !== $before['content'] ) {
			return new WP_Error( 'wpagent_kadence_single_button_document', __( 'Das Kadence-Button-Dokument ist zu groß oder nicht kanonisch parse- und serialisierbar.', 'wp-agent-companion' ), array( 'status' => 409 ) );
		}
		$target = wpagent_kadence_single_button_patch_path( $blocks, $path, $patch );
		if ( is_wp_error( $target ) ) {
			return $target;
		}
		if ( ! wpagent_site_editor_refresh_lock( 'kadence-single-button', (string) $post_id, $lock ) ) {
			return new WP_Error( 'wpagent_kadence_single_button_lock_lost', __( 'Die exklusive Sperre ging vor der Kadence-Single-Buttonänderung verloren.', 'wp-agent-companion' ), array( 'status' => 409 ) );
		}
		if ( ! $target['changed'] ) {
			$fresh = wpagent_native_block_document_state( $post_id );
			$state = is_wp_error( $fresh ) ? $fresh : wpagent_kadence_single_button_target_state( parse_blocks( $fresh['content'] ), $path );
			$final_editable = wpagent_kadence_single_button_editable_post( $post_id );
			if ( is_wp_error( $fresh ) || is_wp_error( $state ) || ! hash_equals( $before['hash'], $fresh['hash'] ) || ! wpagent_site_editor_lock_is_owned( 'kadence-single-button', (string) $post_id, $lock ) || is_wp_error( $final_editable ) || ! wpagent_kadence_single_button_same_post_state( $editable, $final_editable ) || $blog_id !== (int) get_current_blog_id() ) {
				return new WP_Error( 'wpagent_kadence_single_button_noop_conflict', __( 'Der Kadence-Single-Button änderte sich während der No-op-Prüfung.', 'wp-agent-companion' ), array( 'status' => 409, 'current_hash' => is_array( $fresh ) ? $fresh['hash'] : '' ) );
			}
			return array( 'post_id' => $post_id, 'block_name' => $target['block_name'], 'path' => $path, 'button' => $state['target']['button'], 'provider_version' => $contract['provider_version'], 'changed' => false, 'verified' => true, 'revision_id' => 0, 'rendered_html_length' => strlen( $state['html'] ), 'previous_hash' => $before['hash'], 'hash' => $fresh['hash'], 'cache' => wpagent_kadence_single_button_noop_cache() );
		}
		$candidate = serialize_blocks( $blocks );
		$candidate_blocks = parse_blocks( $candidate );
		if ( strlen( $candidate ) > WPAGENT_KADENCE_SINGLE_BUTTON_MAX_CONTENT_BYTES || serialize_blocks( $candidate_blocks ) !== $candidate
			|| maybe_serialize( wpagent_kadence_single_button_mask_patch_values( parse_blocks( $before['content'] ), $path ) ) !== maybe_serialize( wpagent_kadence_single_button_mask_patch_values( $candidate_blocks, $path ) ) ) {
			return new WP_Error( 'wpagent_kadence_single_button_document', __( 'Die Kadence-Single-Buttonänderung würde außerhalb der sieben freigegebenen Werte Struktur oder Markup verändern.', 'wp-agent-companion' ), array( 'status' => 400 ) );
		}
		$candidate_state = wpagent_kadence_single_button_target_state( $candidate_blocks, $path );
		if ( is_wp_error( $candidate_state ) || $candidate_state['target']['button'] !== $target['button'] ) {
			return new WP_Error( 'wpagent_kadence_single_button_document', __( 'Der geänderte Kadence-Single-Button verletzt den nativen CTA- oder Rendervertrag.', 'wp-agent-companion' ), array( 'status' => 400 ) );
		}
		if ( ! wpagent_site_editor_refresh_lock( 'kadence-single-button', (string) $post_id, $lock ) ) {
			return new WP_Error( 'wpagent_kadence_single_button_lock_lost', __( 'Die exklusive Sperre ging vor dem Kadence-Single-Button-Write verloren.', 'wp-agent-companion' ), array( 'status' => 409 ) );
		}
		$prewrite = wpagent_native_block_document_state( $post_id );
		$write_editable = wpagent_kadence_single_button_editable_post( $post_id );
		if ( is_wp_error( $prewrite ) || ! hash_equals( $before['hash'], $prewrite['hash'] ) || is_wp_error( $write_editable ) || ! wpagent_kadence_single_button_same_post_state( $editable, $write_editable ) || $blog_id !== (int) get_current_blog_id() || is_wp_error( wpagent_kadence_single_button_contract() ) ) {
			return new WP_Error( 'wpagent_kadence_single_button_conflict', __( 'Das Kadence-Single-Button-Dokument oder seine Schreibvoraussetzungen änderten sich unmittelbar vor dem Speichern.', 'wp-agent-companion' ), array( 'status' => 409, 'current_hash' => is_array( $prewrite ) ? $prewrite['hash'] : '' ) );
		}
		$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( 'kadence-single-button', (string) $post_id, $lock ) ) {
			return new WP_Error( 'wpagent_kadence_single_button_lock_lost', __( 'Die exklusive Sperre ging vor dem Kadence-Single-Button-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 ) ) {
			$data = $saved->get_error_data();
			return new WP_Error( $saved->get_error_code(), $saved->get_error_message(), array_merge( is_array( $data ) ? $data : array(), array( 'revision_id' => $revision_id ) ) );
		}
		if ( ! wpagent_site_editor_lock_is_owned( 'kadence-single-button', (string) $post_id, $lock ) ) {
			return wpagent_kadence_single_button_lock_lost_after_write( $revision_id, $post_id, $before['content'], $candidate );
		}
		$after_raw = wpagent_native_block_raw_content( $post_id );
		$after = wpagent_native_block_document_state( $post_id );
		$after_state = is_string( $after_raw ) && $after_raw === $candidate && is_array( $after ) && ! is_wp_error( $after ) && $after['content'] === $candidate ? wpagent_kadence_single_button_target_state( parse_blocks( $after_raw ), $path ) : null;
		$verified = is_string( $after_raw ) && $after_raw === $candidate && is_array( $after ) && ! is_wp_error( $after ) && $after['content'] === $candidate && is_array( $after_state ) && $after_state['target']['button'] === $target['button'] && $blog_id === (int) get_current_blog_id();
		if ( ! $verified ) {
			$rollback = wpagent_kadence_single_button_rollback_after_cache( $post_id, $before['content'], $candidate );
			return wpagent_kadence_single_button_write_error( 'wpagent_kadence_single_button_verify_failed', __( 'Der Kadence-Single-Button bestand die Parse-, Rücklese- oder Frontend-Prüfung nicht.', 'wp-agent-companion' ), $revision_id, $rollback );
		}
		if ( ! wpagent_site_editor_refresh_lock( 'kadence-single-button', (string) $post_id, $lock ) ) {
			return wpagent_kadence_single_button_lock_lost_after_write( $revision_id, $post_id, $before['content'], $candidate );
		}
		$cache = wpagent_kadence_single_button_refresh_cache( $post_id );
		if ( ! wpagent_site_editor_lock_is_owned( 'kadence-single-button', (string) $post_id, $lock ) ) {
			return wpagent_kadence_single_button_lock_lost_after_write( $revision_id, $post_id, $before['content'], $candidate );
		}
		$after_cache_raw = wpagent_native_block_raw_content( $post_id );
		$after_cache = wpagent_native_block_document_state( $post_id );
		$after_cache_state = is_string( $after_cache_raw ) && $after_cache_raw === $candidate && is_array( $after_cache ) && ! is_wp_error( $after_cache ) && $after_cache['content'] === $candidate ? wpagent_kadence_single_button_target_state( parse_blocks( $after_cache_raw ), $path ) : null;
		if ( ! $cache['verified'] || ! is_array( $after_cache_state ) || $after_cache_state['target']['button'] !== $target['button'] || ! is_array( $after_cache ) || is_wp_error( $after_cache ) || $blog_id !== (int) get_current_blog_id() ) {
			$rollback = wpagent_kadence_single_button_rollback_after_cache( $post_id, $before['content'], $candidate );
			return wpagent_kadence_single_button_write_error( 'wpagent_kadence_single_button_cache_readback_failed', __( 'Der Kadence-Cache-Nachlauf veränderte den gespeicherten CTA-Zustand oder konnte ihn nicht erneut verifizieren.', 'wp-agent-companion' ), $revision_id, $rollback );
		}
		return array( 'post_id' => $post_id, 'block_name' => $target['block_name'], 'path' => $path, 'button' => $after_cache_state['target']['button'], 'provider_version' => $contract['provider_version'], 'changed' => true, 'verified' => true, 'revision_id' => $revision_id, 'rendered_html_length' => strlen( $after_cache_state['html'] ), 'previous_hash' => $before['hash'], 'hash' => $after_cache['hash'], 'cache' => $cache );
	} finally {
		wpagent_site_editor_release_lock( 'kadence-single-button', (string) $post_id, $lock );
	}
}
