<?php
/** Verified, static-only Beaver Builder template and global-settings writes. */

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

/** @return array<string,mixed> */
function wpagent_beaver_template_write_output_schema(): array {
	$schema                              = wpagent_beaver_user_template_output_schema();
	$schema['properties']['changed']     = array( 'type' => 'boolean' );
	$schema['properties']['verified']    = array( 'type' => 'boolean' );
	$schema['properties']['revision_id'] = array( 'type' => 'integer' );
	$schema['properties']['source_hash'] = array( 'type' => 'string', 'pattern' => '^[a-f0-9]{64}$' );
	$schema['properties']['cache_refreshed'] = array( 'type' => 'boolean' );
	$schema['required'] = array_merge( $schema['required'], array( 'changed', 'verified', 'revision_id', 'source_hash', 'cache_refreshed' ) );
	return $schema;
}

/** @return array<string,mixed> */
function wpagent_beaver_global_settings_write_output_schema(): array {
	$schema = wpagent_beaver_global_settings_output_schema();
	$schema['properties']['changed']     = array( 'type' => 'boolean' );
	$schema['properties']['verified']    = array( 'type' => 'boolean' );
	$schema['properties']['previous_hash'] = array( 'type' => 'string', 'pattern' => '^[a-f0-9]{64}$' );
	$schema['properties']['revision_id'] = array( 'type' => 'string' );
	$schema['required'] = array_merge( $schema['required'], array( 'changed', 'verified', 'previous_hash', 'revision_id' ) );
	return $schema;
}

/** @return array{post:WP_Post,data:array<string,object>,settings:mixed,hash:string}|WP_Error */
function wpagent_beaver_template_source_state( int $post_id, string $expected_hash, string $node_id = '' ) {
	$post = wpagent_beaver_editable_post( $post_id );
	if ( is_wp_error( $post ) ) {
		return $post;
	}
	$data     = FLBuilderModel::get_layout_data( 'published', $post_id );
	$settings = FLBuilderModel::get_layout_settings( 'published', $post_id );
	if ( ! is_array( $data ) ) {
		return new WP_Error( 'wpagent_beaver_template_read_failed', __( 'Beaver Builder lieferte keine gültigen Layoutdaten für den Template-Write.', 'wp-agent-companion' ), array( 'status' => 502 ) );
	}
	$hash = wpagent_beaver_state_hash( $data, $settings );
	if ( ! hash_equals( $hash, $expected_hash ) ) {
		return new WP_Error( 'wpagent_beaver_conflict', __( 'Das Beaver-Builder-Layout wurde seit dem Lesen verändert.', 'wp-agent-companion' ), array( 'status' => 409, 'current_hash' => $hash ) );
	}
	$validation_data = $data;
	if ( '' !== $node_id ) {
		$validation_data = wpagent_beaver_template_subtree_data( $data, $node_id );
		if ( is_wp_error( $validation_data ) ) {
			return $validation_data;
		}
	}
	$valid = wpagent_beaver_template_validate_state( $validation_data, $settings );
	if ( is_wp_error( $valid ) ) {
		return $valid;
	}
	return array( 'post' => $post, 'data' => $data, 'settings' => $settings, 'hash' => $hash );
}

function wpagent_beaver_template_latest_revision_id( int $post_id ): int {
	$revisions = wp_get_post_revisions( $post_id, array( 'numberposts' => 1 ) );
	if ( ! is_array( $revisions ) || array() === $revisions ) {
		return 0;
	}
	$revision = reset( $revisions );
	return is_object( $revision ) ? absint( $revision->ID ?? 0 ) : absint( $revision );
}

function wpagent_beaver_template_cache_contains( int $post_id, string $type ): bool {
	$native = FLBuilderModel::get_user_templates( $type );
	if ( ! is_array( $native ) ) {
		return false;
	}
	foreach ( is_array( $native['templates'] ?? null ) ? $native['templates'] : array() as $template ) {
		if ( is_array( $template ) && $post_id === absint( $template['postId'] ?? 0 ) ) {
			return true;
		}
	}
	return false;
}

function wpagent_beaver_template_lock_owned( string $token ): bool {
	return wpagent_companion_option_lock_is_owned( WPAGENT_BEAVER_TEMPLATE_LOCK_OPTION, $token );
}

function wpagent_beaver_global_settings_lock_owned( string $token ): bool {
	return wpagent_companion_option_lock_is_owned( WPAGENT_BEAVER_GLOBAL_SETTINGS_LOCK_OPTION, $token );
}

function wpagent_ability_save_beaver_user_template(): array {
	return array(
		'label'               => __( 'Beaver-Builder-Template speichern', 'wp-agent-companion' ),
		'description'         => __( 'Speichert ausschließlich den vollständig statischen Inhalt eines vorhandenen Beaver-Builder-Layouts über die native User-Template-API.', 'wp-agent-companion' ),
		'category'            => 'wp-agent',
		'input_schema'        => array(
			'type'       => 'object',
			'properties' => array(
				'source_post_id' => array( 'type' => 'integer' ),
				'name'           => array( 'type' => 'string', 'maxLength' => WPAGENT_BEAVER_TEMPLATE_MAX_NAME_BYTES ),
				'category'       => array( 'type' => 'string', 'maxLength' => WPAGENT_BEAVER_TEMPLATE_MAX_NAME_BYTES ),
				'expected_hash'  => array( 'type' => 'string', 'pattern' => '^[a-f0-9]{64}$' ),
			),
			'required' => array( 'source_post_id', 'name', 'expected_hash' ),
		),
		'output_schema'       => wpagent_beaver_template_write_output_schema(),
		'execute_callback'    => 'wpagent_exec_save_beaver_user_template',
		'permission_callback' => 'wpagent_perm_edit_posts',
		'meta'                => array( 'show_in_rest' => true, 'annotations' => array( 'readonly' => false, 'destructive' => false, 'idempotent' => false ) ),
	);
}

/** @return array<string,mixed>|WP_Error */
function wpagent_exec_save_beaver_user_template( $input ) {
	if ( ! wpagent_beaver_user_templates_available() ) {
		return wpagent_beaver_user_templates_unavailable_error();
	}
	$input = is_array( $input ) ? $input : array();
	$name  = wpagent_beaver_template_plain_name( $input['name'] ?? '', 'name' );
	if ( is_wp_error( $name ) ) {
		return $name;
	}
	$category = wpagent_beaver_template_plain_name( $input['category'] ?? '', 'category', false );
	if ( is_wp_error( $category ) ) {
		return $category;
	}
	$expected_hash = wpagent_beaver_templates_expected_hash( $input['expected_hash'] ?? '' );
	if ( is_wp_error( $expected_hash ) ) {
		return $expected_hash;
	}
	$source_post_id = absint( $input['source_post_id'] ?? 0 );
	$source         = wpagent_beaver_template_source_state( $source_post_id, $expected_hash );
	if ( is_wp_error( $source ) ) {
		return $source;
	}
	$lock = wpagent_beaver_templates_acquire_lock();
	if ( is_wp_error( $lock ) ) {
		return $lock;
	}
	try {
		if ( ! current_user_can( 'edit_post', $source_post_id ) ) {
			return new WP_Error( 'wpagent_beaver_forbidden', __( 'Die Berechtigung für den Beaver-Builder-Quellinhalt wurde vor dem Write entzogen.', 'wp-agent-companion' ), array( 'status' => 403 ) );
		}
		$current = wpagent_beaver_template_source_state( $source_post_id, $expected_hash );
		if ( is_wp_error( $current ) ) {
			return $current;
		}
		$provider_settings = array( 'name' => $name, 'type' => 'user' );
		if ( '' !== $category ) {
			$provider_settings['category'] = $category;
		}
		$response = null;
		try {
			FLBuilderModel::set_post_id( $source_post_id );
			try {
				$response = FLBuilderModel::save_user_template( $provider_settings );
			} finally {
				FLBuilderModel::reset_post_id();
			}
		} catch ( Throwable $error ) {
			return wpagent_beaver_templates_recovery_required( 'user-template-save-provider', $source_post_id, '', array( 'source_hash' => $expected_hash ) );
		}
		$post_id = is_array( $response ) ? absint( $response['postId'] ?? 0 ) : 0;
		if ( $post_id <= 0 || ! current_user_can( 'edit_post', $source_post_id ) || ! wpagent_beaver_template_lock_owned( $lock ) ) {
			return wpagent_beaver_templates_recovery_required( 'user-template-save', $post_id > 0 ? $post_id : $source_post_id, '', array( 'source_hash' => $expected_hash ) );
		}
		if ( ! wpagent_beaver_refresh_template_cache() ) {
			return wpagent_beaver_templates_recovery_required( 'user-template-cache', $post_id, '', array( 'source_hash' => $expected_hash ) );
		}
		$target = wpagent_beaver_user_template_state( $post_id );
		if ( is_wp_error( $target ) || ! empty( $target['is_global'] ) || ! empty( $target['is_dynamic_editing'] ) || empty( $target['writable'] ) ) {
			return wpagent_beaver_templates_recovery_required( 'user-template-readback', $post_id, '', array( 'source_hash' => $expected_hash ) );
		}
		$target_data = FLBuilderModel::get_layout_data( 'published', $post_id );
		$source_sig  = wpagent_beaver_template_data_signature( $current['data'] );
		$target_sig  = wpagent_beaver_template_data_signature( $target_data );
		$source_after_hash = wpagent_beaver_state_hash( FLBuilderModel::get_layout_data( 'published', $source_post_id ), FLBuilderModel::get_layout_settings( 'published', $source_post_id ) );
		if ( is_wp_error( $source_sig ) || is_wp_error( $target_sig ) || ! hash_equals( (string) $source_sig, (string) $target_sig ) || ! hash_equals( $expected_hash, $source_after_hash ) || ! wpagent_beaver_template_cache_contains( $post_id, 'layout' ) ) {
			return wpagent_beaver_templates_recovery_required( 'user-template-verify', $post_id, '', array( 'source_hash' => $expected_hash, 'current_source_hash' => $source_after_hash ) );
		}
		$revision_id = wpagent_beaver_template_latest_revision_id( $post_id );
		if ( $revision_id <= 0 ) {
			$revision_id = wpagent_beaver_create_revision( $post_id );
			if ( is_wp_error( $revision_id ) ) {
				return wpagent_beaver_templates_recovery_required( 'user-template-revision', $post_id, '', array( 'source_hash' => $expected_hash ) );
			}
		}
		if ( ! current_user_can( 'edit_post', $source_post_id ) || ! wpagent_beaver_template_lock_owned( $lock ) ) {
			return wpagent_beaver_templates_recovery_required( 'user-template-lock', $post_id, (string) $revision_id, array( 'source_hash' => $expected_hash ) );
		}
		return array_merge( $target, array( 'changed' => true, 'verified' => true, 'revision_id' => (int) $revision_id, 'source_hash' => $expected_hash, 'cache_refreshed' => true ) );
	} finally {
		wpagent_beaver_templates_release_lock( $lock );
	}
}

function wpagent_ability_save_beaver_node_template(): array {
	return array(
		'label'               => __( 'Beaver-Builder-Knoten-Template speichern', 'wp-agent-companion' ),
		'description'         => __( 'Speichert ausschließlich einen statischen Beaver-Builder-Knoten-Teilbaum als User-Template. Globale und dynamische Knoten sind ausgeschlossen.', 'wp-agent-companion' ),
		'category'            => 'wp-agent',
		'input_schema'        => array(
			'type'       => 'object',
			'properties' => array(
				'source_post_id' => array( 'type' => 'integer' ),
				'node_id'        => array( 'type' => 'string' ),
				'name'           => array( 'type' => 'string', 'maxLength' => WPAGENT_BEAVER_TEMPLATE_MAX_NAME_BYTES ),
				'category'       => array( 'type' => 'string', 'maxLength' => WPAGENT_BEAVER_TEMPLATE_MAX_NAME_BYTES ),
				'expected_hash'  => array( 'type' => 'string', 'pattern' => '^[a-f0-9]{64}$' ),
			),
			'required' => array( 'source_post_id', 'node_id', 'name', 'expected_hash' ),
		),
		'output_schema'       => wpagent_beaver_template_write_output_schema(),
		'execute_callback'    => 'wpagent_exec_save_beaver_node_template',
		'permission_callback' => 'wpagent_perm_edit_posts',
		'meta'                => array( 'show_in_rest' => true, 'annotations' => array( 'readonly' => false, 'destructive' => false, 'idempotent' => false ) ),
	);
}

/** @return array<string,mixed>|WP_Error */
function wpagent_exec_save_beaver_node_template( $input ) {
	if ( ! wpagent_beaver_user_templates_available() ) {
		return wpagent_beaver_user_templates_unavailable_error();
	}
	$input = is_array( $input ) ? $input : array();
	$name  = wpagent_beaver_template_plain_name( $input['name'] ?? '', 'name' );
	if ( is_wp_error( $name ) ) {
		return $name;
	}
	$category = wpagent_beaver_template_plain_name( $input['category'] ?? '', 'category', false );
	if ( is_wp_error( $category ) ) {
		return $category;
	}
	$node_id = is_string( $input['node_id'] ?? null ) ? $input['node_id'] : '';
	if ( '' === $node_id || sanitize_key( $node_id ) !== $node_id ) {
		return new WP_Error( 'wpagent_beaver_bad_node', __( 'Ungültige Beaver-Builder-Knoten-ID.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$expected_hash = wpagent_beaver_templates_expected_hash( $input['expected_hash'] ?? '' );
	if ( is_wp_error( $expected_hash ) ) {
		return $expected_hash;
	}
	$source_post_id = absint( $input['source_post_id'] ?? 0 );
	$source         = wpagent_beaver_template_source_state( $source_post_id, $expected_hash, $node_id );
	if ( is_wp_error( $source ) ) {
		return $source;
	}
	$subtree = wpagent_beaver_template_subtree_data( $source['data'], $node_id );
	if ( is_wp_error( $subtree ) ) {
		return $subtree;
	}
	$lock = wpagent_beaver_templates_acquire_lock();
	if ( is_wp_error( $lock ) ) {
		return $lock;
	}
	try {
		if ( ! current_user_can( 'edit_post', $source_post_id ) ) {
			return new WP_Error( 'wpagent_beaver_forbidden', __( 'Die Berechtigung für den Beaver-Builder-Quellknoten wurde vor dem Write entzogen.', 'wp-agent-companion' ), array( 'status' => 403 ) );
		}
		$current = wpagent_beaver_template_source_state( $source_post_id, $expected_hash, $node_id );
		if ( is_wp_error( $current ) ) {
			return $current;
		}
		$response_settings = array( 'name' => $name, 'type' => 'user' );
		if ( '' !== $category ) {
			$response_settings['categories'] = $category;
		}
		$response = null;
		try {
			FLBuilderModel::set_post_id( $source_post_id );
			try {
				$response = FLBuilderModel::save_node_template( $node_id, $response_settings );
			} finally {
				FLBuilderModel::reset_post_id();
			}
		} catch ( Throwable $error ) {
			return wpagent_beaver_templates_recovery_required( 'node-template-save-provider', $source_post_id, '', array( 'source_hash' => $expected_hash ) );
		}
		$post_id = is_array( $response ) ? absint( $response['postID'] ?? 0 ) : 0;
		if ( $post_id <= 0 || ! current_user_can( 'edit_post', $source_post_id ) || ! wpagent_beaver_template_lock_owned( $lock ) ) {
			return wpagent_beaver_templates_recovery_required( 'node-template-save', $post_id > 0 ? $post_id : $source_post_id, '', array( 'source_hash' => $expected_hash ) );
		}
		if ( ! wpagent_beaver_refresh_template_cache() ) {
			return wpagent_beaver_templates_recovery_required( 'node-template-cache', $post_id, '', array( 'source_hash' => $expected_hash ) );
		}
		$target = wpagent_beaver_user_template_state( $post_id );
		if ( is_wp_error( $target ) || ! empty( $target['is_global'] ) || ! empty( $target['is_dynamic_editing'] ) || empty( $target['writable'] ) ) {
			return wpagent_beaver_templates_recovery_required( 'node-template-readback', $post_id, '', array( 'source_hash' => $expected_hash ) );
		}
		$target_data = FLBuilderModel::get_layout_data( 'published', $post_id );
		$expected_data = wpagent_beaver_snapshot( $subtree );
		if ( is_array( $expected_data ) && isset( $expected_data[ $node_id ] ) && is_object( $expected_data[ $node_id ] ) ) {
			$expected_data[ $node_id ]->parent   = '';
			$expected_data[ $node_id ]->position = 0;
			if ( 'column' === (string) ( $expected_data[ $node_id ]->type ?? '' ) ) {
				$expected_data[ $node_id ]->settings->size = 100;
			}
		}
		$source_sig = wpagent_beaver_template_data_signature( is_array( $expected_data ) ? $expected_data : array() );
		$target_sig = wpagent_beaver_template_data_signature( is_array( $target_data ) ? $target_data : array() );
		$source_after_hash = wpagent_beaver_state_hash( FLBuilderModel::get_layout_data( 'published', $source_post_id ), FLBuilderModel::get_layout_settings( 'published', $source_post_id ) );
		$type = sanitize_key( (string) FLBuilderModel::get_user_template_type( $post_id ) );
		if ( is_wp_error( $source_sig ) || is_wp_error( $target_sig ) || ! hash_equals( (string) $source_sig, (string) $target_sig ) || $source_after_hash !== $expected_hash || ! wpagent_beaver_template_cache_contains( $post_id, $type ) ) {
			return wpagent_beaver_templates_recovery_required( 'node-template-verify', $post_id, '', array( 'source_hash' => $expected_hash, 'current_source_hash' => $source_after_hash ) );
		}
		$revision_id = wpagent_beaver_template_latest_revision_id( $post_id );
		if ( $revision_id <= 0 ) {
			$revision_id = wpagent_beaver_create_revision( $post_id );
			if ( is_wp_error( $revision_id ) ) {
				return wpagent_beaver_templates_recovery_required( 'node-template-revision', $post_id, '', array( 'source_hash' => $expected_hash ) );
			}
		}
		if ( ! current_user_can( 'edit_post', $source_post_id ) || ! wpagent_beaver_template_lock_owned( $lock ) ) {
			return wpagent_beaver_templates_recovery_required( 'node-template-lock', $post_id, (string) $revision_id, array( 'source_hash' => $expected_hash ) );
		}
		return array_merge( $target, array( 'changed' => true, 'verified' => true, 'revision_id' => (int) $revision_id, 'source_hash' => $expected_hash, 'cache_refreshed' => true ) );
	} finally {
		wpagent_beaver_templates_release_lock( $lock );
	}
}

function wpagent_ability_delete_beaver_user_template(): array {
	return array(
		'label'               => __( 'Beaver-Builder-Template löschen', 'wp-agent-companion' ),
		'description'         => __( 'Entfernt ein bestätigtes statisches Beaver-Builder-User-Template über die native Lösch-API. Globale und dynamische Templates sind ausgeschlossen.', 'wp-agent-companion' ),
		'category'            => 'wp-agent',
		'input_schema'        => array(
			'type'       => 'object',
			'properties' => array(
				'post_id'       => array( 'type' => 'integer' ),
				'expected_hash' => array( 'type' => 'string', 'pattern' => '^[a-f0-9]{64}$' ),
				'confirm'       => array( 'type' => 'boolean' ),
			),
			'required' => array( 'post_id', 'expected_hash', 'confirm' ),
		),
		'output_schema'       => array(
			'type'       => 'object',
			'properties' => array(
				'post_id'         => array( 'type' => 'integer' ),
				'deleted'         => array( 'type' => 'boolean' ),
				'verified'        => array( 'type' => 'boolean' ),
				'revision_id'     => array( 'type' => 'integer' ),
				'previous_hash'   => array( 'type' => 'string', 'pattern' => '^[a-f0-9]{64}$' ),
				'cache_refreshed' => array( 'type' => 'boolean' ),
			),
			'required'             => array( 'post_id', 'deleted', 'verified', 'revision_id', 'previous_hash', 'cache_refreshed' ),
			'additionalProperties' => false,
		),
		'execute_callback'    => 'wpagent_exec_delete_beaver_user_template',
		'permission_callback' => 'wpagent_perm_edit_posts',
		'meta'                => array( 'show_in_rest' => true, 'annotations' => array( 'readonly' => false, 'destructive' => true, 'idempotent' => false ) ),
	);
}

/** @return array<string,mixed>|WP_Error */
function wpagent_exec_delete_beaver_user_template( $input ) {
	if ( ! wpagent_beaver_user_templates_available() ) {
		return wpagent_beaver_user_templates_unavailable_error();
	}
	$input = is_array( $input ) ? $input : array();
	if ( true !== ( $input['confirm'] ?? false ) ) {
		return new WP_Error( 'wpagent_beaver_delete_confirmation', __( 'Das Löschen eines Beaver-Builder-Templates erfordert eine ausdrückliche Bestätigung.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$post_id       = absint( $input['post_id'] ?? 0 );
	$expected_hash = wpagent_beaver_templates_expected_hash( $input['expected_hash'] ?? '' );
	if ( is_wp_error( $expected_hash ) ) {
		return $expected_hash;
	}
	$template_post = wpagent_beaver_user_template_post( $post_id );
	if ( is_wp_error( $template_post ) ) {
		return $template_post;
	}
	$static_guard = wpagent_beaver_template_static_guard( $post_id );
	if ( is_wp_error( $static_guard ) ) {
		return $static_guard;
	}
	$source = wpagent_beaver_template_source_state( $post_id, $expected_hash );
	if ( is_wp_error( $source ) ) {
		return $source;
	}
	if ( ! current_user_can( 'delete_post', $post_id ) ) {
		return new WP_Error( 'wpagent_beaver_forbidden', __( 'Keine Berechtigung zum Löschen dieses Beaver-Builder-Templates.', 'wp-agent-companion' ), array( 'status' => 403 ) );
	}
	$type = sanitize_key( (string) FLBuilderModel::get_user_template_type( $post_id ) );
	$lock = wpagent_beaver_templates_acquire_lock();
	if ( is_wp_error( $lock ) ) {
		return $lock;
	}
	try {
		if ( ! current_user_can( 'delete_post', $post_id ) ) {
			return new WP_Error( 'wpagent_beaver_forbidden', __( 'Die Löschberechtigung wurde vor dem Beaver-Builder-Delete entzogen.', 'wp-agent-companion' ), array( 'status' => 403 ) );
		}
		$current = wpagent_beaver_template_source_state( $post_id, $expected_hash );
		if ( is_wp_error( $current ) ) {
			return $current;
		}
		$revision_id = wpagent_beaver_create_revision( $post_id );
		if ( is_wp_error( $revision_id ) ) {
			return $revision_id;
		}
		try {
			FLBuilderModel::delete_user_template( $post_id );
		} catch ( Throwable $error ) {
			return wpagent_beaver_templates_recovery_required( 'user-template-delete-provider', $post_id, (string) $revision_id, array( 'previous_hash' => $expected_hash ) );
		}
		if ( ! current_user_can( 'delete_post', $post_id ) || ! wpagent_beaver_template_lock_owned( $lock ) ) {
			return wpagent_beaver_templates_recovery_required( 'user-template-delete-lock', $post_id, (string) $revision_id, array( 'previous_hash' => $expected_hash ) );
		}
		$post_after = get_post( $post_id );
		if ( $post_after && 'trash' !== $post_after->post_status ) {
			return wpagent_beaver_templates_recovery_required( 'user-template-delete-readback', $post_id, (string) $revision_id, array( 'previous_hash' => $expected_hash ) );
		}
		if ( ! wpagent_beaver_refresh_template_cache() || wpagent_beaver_template_cache_contains( $post_id, $type ) ) {
			return wpagent_beaver_templates_recovery_required( 'user-template-delete-cache', $post_id, (string) $revision_id, array( 'previous_hash' => $expected_hash ) );
		}
		return array( 'post_id' => $post_id, 'deleted' => true, 'verified' => true, 'revision_id' => (int) $revision_id, 'previous_hash' => $expected_hash, 'cache_refreshed' => true );
	} finally {
		wpagent_beaver_templates_release_lock( $lock );
	}
}

function wpagent_ability_save_beaver_global_settings(): array {
	$properties = array( 'expected_hash' => array( 'type' => 'string', 'pattern' => '^[a-f0-9]{64}$' ) );
	$settings_properties = array();
	foreach ( wpagent_beaver_global_settings_field_catalog() as $name => $field ) {
		$definition = 'select' === $field['type']
			? array( 'type' => 'string', 'enum' => $field['values'] )
			: array( 'type' => 'string', 'pattern' => '^(?:0|[1-9][0-9]{0,3})$' );
		$properties[ $name ] = $definition;
		$settings_properties[ $name ] = $definition;
	}
	$properties['settings'] = array( 'type' => 'object', 'properties' => $settings_properties, 'additionalProperties' => false, 'minProperties' => 1 );
	return array(
		'label'               => __( 'Beaver-Builder-Global-Settings speichern', 'wp-agent-companion' ),
		'description'         => __( 'Speichert nur primitive, reale und allowlistete Beaver-Builder-Global-Settings. CSS, JavaScript, Selektoren, Dimensionen und Shapes bleiben gesperrt.', 'wp-agent-companion' ),
		'category'            => 'wp-agent',
		'input_schema'        => array( 'type' => 'object', 'properties' => $properties, 'required' => array( 'expected_hash' ), 'additionalProperties' => false ),
		'output_schema'       => wpagent_beaver_global_settings_write_output_schema(),
		'execute_callback'    => 'wpagent_exec_save_beaver_global_settings',
		'permission_callback' => 'wpagent_perm_beaver_global_settings',
		'meta'                => array( 'show_in_rest' => true, 'annotations' => array( 'readonly' => false, 'destructive' => false, 'idempotent' => true ) ),
	);
}

/** @return array<string,mixed>|WP_Error */
function wpagent_exec_save_beaver_global_settings( $input ) {
	if ( ! wpagent_beaver_available() ) {
		return wpagent_beaver_unavailable_error();
	}
	$input         = is_array( $input ) ? $input : array();
	$expected_hash = wpagent_beaver_templates_expected_hash( $input['expected_hash'] ?? '' );
	if ( is_wp_error( $expected_hash ) ) {
		return $expected_hash;
	}
	$patch = $input;
	unset( $patch['expected_hash'] );
	$nested_patch = is_array( $patch['settings'] ?? null ) ? $patch['settings'] : array();
	unset( $patch['settings'] );
	$patch = array_merge( $nested_patch, $patch );
	$patch = wpagent_beaver_validate_global_settings_patch( $patch );
	if ( is_wp_error( $patch ) ) {
		return $patch;
	}
	if ( ! current_user_can( 'delete_others_posts' ) ) {
		return new WP_Error( 'wpagent_beaver_forbidden', __( 'Das Speichern globaler Beaver-Builder-Einstellungen erfordert delete_others_posts.', 'wp-agent-companion' ), array( 'status' => 403 ) );
	}
	$lock = wpagent_beaver_global_settings_acquire_lock();
	if ( is_wp_error( $lock ) ) {
		return $lock;
	}
	try {
		if ( ! current_user_can( 'delete_others_posts' ) || ! wpagent_beaver_global_settings_lock_owned( $lock ) ) {
			return new WP_Error( 'wpagent_beaver_forbidden', __( 'Die Berechtigung oder globale Beaver-Builder-Sperre war vor dem Write nicht mehr gültig.', 'wp-agent-companion' ), array( 'status' => 403 ) );
		}
		$current = wpagent_beaver_global_settings_state();
		if ( is_wp_error( $current ) ) {
			return $current;
		}
		if ( ! hash_equals( (string) $current['hash'], $expected_hash ) ) {
			return new WP_Error( 'wpagent_beaver_conflict', __( 'Die globalen Beaver-Builder-Einstellungen wurden seit dem Lesen verändert.', 'wp-agent-companion' ), array( 'status' => 409, 'current_hash' => $current['hash'] ) );
		}
		$planned = $current['settings'];
		foreach ( $patch as $name => $value ) {
			$planned[ $name ] = $value;
		}
		if ( wpagent_beaver_canonicalize( $planned ) === wpagent_beaver_canonicalize( $current['settings'] ) ) {
			return array_merge( $current, array( 'changed' => false, 'verified' => true, 'previous_hash' => $expected_hash, 'revision_id' => '' ) );
		}
		$revision = wpagent_beaver_global_settings_revision( $current['settings'], $expected_hash );
		if ( is_wp_error( $revision ) ) {
			return wpagent_beaver_templates_recovery_required( 'global-settings-revision', 0, '', array( 'previous_hash' => $expected_hash ) );
		}
		if ( ! current_user_can( 'delete_others_posts' ) || ! wpagent_beaver_global_settings_lock_owned( $lock ) ) {
			return wpagent_beaver_templates_recovery_required( 'global-settings-prewrite', 0, (string) $revision['revision_id'], array( 'previous_hash' => $expected_hash ) );
		}
		try {
			FLBuilderModel::save_global_settings( $patch );
		} catch ( Throwable $error ) {
			return wpagent_beaver_templates_recovery_required( 'global-settings-save-provider', 0, (string) $revision['revision_id'], array( 'previous_hash' => $expected_hash ) );
		}
		if ( ! current_user_can( 'delete_others_posts' ) || ! wpagent_beaver_global_settings_lock_owned( $lock ) ) {
			return wpagent_beaver_templates_recovery_required( 'global-settings-lock', 0, (string) $revision['revision_id'], array( 'previous_hash' => $expected_hash ) );
		}
		$fresh = wpagent_beaver_global_settings_state();
		if ( is_wp_error( $fresh ) || wpagent_beaver_canonicalize( $fresh['settings'] ?? array() ) !== wpagent_beaver_canonicalize( $planned ) ) {
			return wpagent_beaver_templates_recovery_required( 'global-settings-readback', 0, (string) $revision['revision_id'], array( 'previous_hash' => $expected_hash ) );
		}
		if ( ! current_user_can( 'delete_others_posts' ) || ! wpagent_beaver_global_settings_lock_owned( $lock ) ) {
			return wpagent_beaver_templates_recovery_required( 'global-settings-final-lock', 0, (string) $revision['revision_id'], array( 'previous_hash' => $expected_hash ) );
		}
		return array_merge( $fresh, array( 'changed' => true, 'verified' => true, 'previous_hash' => $expected_hash, 'revision_id' => (string) $revision['revision_id'] ) );
	} finally {
		wpagent_beaver_global_settings_release_lock( $lock );
	}
}
