<?php
/** Conflict-protected WPForms confirmation and notification writes. */

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

/** @return string|WP_Error */
function wpagent_wpforms_delivery_plain_text( $value, string $field, int $max_length, bool $allow_empty = false ) {
	$text = is_string( $value ) ? trim( $value ) : '';
	if ( ( ! $allow_empty && '' === $text ) || strlen( $text ) > $max_length ) {
		/* translators: 1: input field name, 2: maximum byte length. */
		return new WP_Error( 'wpagent_wpforms_delivery_text', sprintf( __( '%1$s ist leer oder länger als %2$d Byte.', 'wp-agent-companion' ), $field, $max_length ), array( 'status' => 400 ) );
	}
	if ( str_contains( $text, '<' ) || str_contains( $text, '>' ) || preg_match( '/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/', $text ) ) {
		/* translators: %s: input field name. */
		return new WP_Error( 'wpagent_wpforms_delivery_markup', sprintf( __( '%s akzeptiert nur Text und Smart-Tags, kein HTML oder Steuerzeichen.', 'wp-agent-companion' ), $field ), array( 'status' => 400 ) );
	}
	return $text;
}

/** @return string|WP_Error */
function wpagent_wpforms_notification_header( $value, string $field, int $max_length, bool $allow_empty = false ) {
	$text = is_string( $value ) ? trim( $value ) : '';
	if ( ( ! $allow_empty && '' === $text ) || strlen( $text ) > $max_length || preg_match( '/[\r\n\x00-\x1F\x7F]/', $text ) ) {
		/* translators: %s: input field name. */
		return new WP_Error( 'wpagent_wpforms_notification_header', sprintf( __( 'Das WPForms-E-Mail-Kopffeld %s ist leer, zu lang oder enthält Steuerzeichen.', 'wp-agent-companion' ), $field ), array( 'status' => 400 ) );
	}
	return $text;
}

/** @param int[] $email_field_ids */
function wpagent_wpforms_notification_smart_email( string $value, array $email_field_ids, bool $allow_field, bool $allow_user ): bool {
	if ( '{admin_email}' === $value || ( $allow_user && '{user_email}' === $value ) ) {
		return true;
	}
	if ( ! $allow_field || ! preg_match( '/^\{field_id="([1-9][0-9]*)"\}$/', $value, $matches ) ) {
		return false;
	}
	return in_array( absint( $matches[1] ), $email_field_ids, true );
}

/** @param int[] $email_field_ids */
function wpagent_wpforms_notification_valid_address( string $value, array $email_field_ids, bool $allow_field, bool $allow_user ): bool {
	if ( wpagent_wpforms_notification_smart_email( $value, $email_field_ids, $allow_field, $allow_user ) || (bool) is_email( $value ) ) {
		return true;
	}
	if ( preg_match( '/^([^<>,]{1,100})\s*<([^<>]+)>$/', $value, $matches ) ) {
		return (bool) is_email( trim( $matches[2] ) );
	}
	return false;
}

/** @param int[] $email_field_ids @return string|WP_Error */
function wpagent_wpforms_notification_addresses( $value, string $field, bool $multiple, bool $allow_empty, array $email_field_ids, bool $allow_field, bool $allow_user ) {
	$text = wpagent_wpforms_notification_header( $value, $field, 2000, $allow_empty );
	if ( is_wp_error( $text ) || '' === $text ) {
		return $text;
	}
	$parts = $multiple ? array_map( 'trim', explode( ',', $text ) ) : array( $text );
	if ( count( $parts ) > 20 || in_array( '', $parts, true ) ) {
		return new WP_Error( 'wpagent_wpforms_notification_email', __( 'Ein WPForms-E-Mail-Feld enthält zu viele oder leere Empfänger.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	foreach ( $parts as $part ) {
		if ( ! wpagent_wpforms_notification_valid_address( $part, $email_field_ids, $allow_field, $allow_user ) ) {
			return new WP_Error( 'wpagent_wpforms_notification_email', __( 'Ein WPForms-E-Mail-Feld enthält eine ungültige Adresse oder einen nicht freigegebenen Smart-Tag.', 'wp-agent-companion' ), array( 'status' => 400 ) );
		}
	}
	return implode( ', ', $parts );
}

/** @param array<string,mixed> $form_data @return int[] */
function wpagent_wpforms_notification_email_field_ids( array $form_data ): array {
	$ids = array();
	foreach ( is_array( $form_data['fields'] ?? null ) ? $form_data['fields'] : array() as $key => $field ) {
		if ( ! is_array( $field ) || 'email' !== ( $field['type'] ?? '' ) ) {
			continue;
		}
		$id = absint( $field['id'] ?? $key );
		if ( $id > 0 ) {
			$ids[] = $id;
		}
	}
	return array_values( array_unique( $ids ) );
}

/** @param array<string,mixed> $current @param array<string,mixed> $patch @return array<string,mixed>|WP_Error */
function wpagent_wpforms_prepare_confirmation( array $current, array $patch ) {
	$allowed = array( 'name', 'type', 'message', 'message_scroll', 'page_id', 'page_url_parameters', 'redirect', 'redirect_new_tab' );
	if ( ! $patch || array_diff( array_keys( $patch ), $allowed ) ) {
		return new WP_Error( 'wpagent_wpforms_confirmation_fields', __( 'Übergebe mindestens ein unterstütztes WPForms-Bestätigungsfeld.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$result = $current;
	if ( array_key_exists( 'name', $patch ) ) {
		$name = wpagent_wpforms_notification_header( $patch['name'], 'name', 255 );
		if ( is_wp_error( $name ) ) {
			return $name;
		}
		$result['name'] = $name;
	}
	if ( array_key_exists( 'type', $patch ) ) {
		$type = is_string( $patch['type'] ) ? $patch['type'] : '';
		if ( ! in_array( $type, array( 'message', 'page', 'redirect' ), true ) ) {
			return new WP_Error( 'wpagent_wpforms_confirmation_type', __( 'type muss message, page oder redirect sein.', 'wp-agent-companion' ), array( 'status' => 400 ) );
		}
		$result['type'] = $type;
	}
	if ( array_key_exists( 'message', $patch ) ) {
		$message = wpagent_wpforms_delivery_plain_text( $patch['message'], 'message', 100000 );
		if ( is_wp_error( $message ) ) {
			return $message;
		}
		$result['message'] = $message;
	}
	if ( array_key_exists( 'message_scroll', $patch ) ) {
		$result['message_scroll'] = rest_sanitize_boolean( $patch['message_scroll'] ) ? '1' : '0';
	}
	if ( array_key_exists( 'page_id', $patch ) ) {
		$page_id = absint( $patch['page_id'] );
		if ( $page_id > 0 ) {
			$page = get_post( $page_id );
			if ( ! $page instanceof WP_Post || 'page' !== $page->post_type || 'trash' === $page->post_status || ! current_user_can( 'read_post', $page_id ) ) {
				return new WP_Error( 'wpagent_wpforms_confirmation_page', __( 'page_id muss auf eine lesbare Seite außerhalb des Papierkorbs zeigen.', 'wp-agent-companion' ), array( 'status' => 400 ) );
			}
		}
		$result['page'] = $page_id > 0 ? (string) $page_id : '';
	}
	if ( array_key_exists( 'page_url_parameters', $patch ) ) {
		$query = is_string( $patch['page_url_parameters'] ) ? ltrim( trim( $patch['page_url_parameters'] ), '?' ) : '';
		if ( strlen( $query ) > 4096 || preg_match( '/[\x00-\x20\x7F#]/', $query ) ) {
			return new WP_Error( 'wpagent_wpforms_confirmation_query', __( 'page_url_parameters darf höchstens 4.096 Byte lang sein und keine Leer-, Steuer- oder Fragmentzeichen enthalten.', 'wp-agent-companion' ), array( 'status' => 400 ) );
		}
		$result['page_url_parameters'] = $query;
	}
	if ( array_key_exists( 'redirect', $patch ) ) {
		$url = is_string( $patch['redirect'] ) ? trim( $patch['redirect'] ) : '';
		if ( '' !== $url ) {
			$parsed = wp_parse_url( $url );
			if ( strlen( $url ) > 4096 || ! is_array( $parsed ) || ! in_array( strtolower( (string) ( $parsed['scheme'] ?? '' ) ), array( 'http', 'https' ), true ) || empty( $parsed['host'] ) || isset( $parsed['user'] ) || isset( $parsed['pass'] ) ) {
				return new WP_Error( 'wpagent_wpforms_confirmation_url', __( 'redirect muss eine vollständige HTTP- oder HTTPS-URL ohne Zugangsdaten sein.', 'wp-agent-companion' ), array( 'status' => 400 ) );
			}
		}
		$result['redirect'] = '' === $url ? '' : esc_url_raw( $url );
	}
	if ( array_key_exists( 'redirect_new_tab', $patch ) ) {
		$result['redirect_new_tab'] = rest_sanitize_boolean( $patch['redirect_new_tab'] ) ? '1' : '0';
	}
	$type = (string) ( $result['type'] ?? 'message' );
	if ( 'message' === $type && '' === trim( (string) ( $result['message'] ?? '' ) ) ) {
		return new WP_Error( 'wpagent_wpforms_confirmation_message', __( 'Eine Nachrichtenbestätigung benötigt message.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	if ( 'page' === $type && absint( $result['page'] ?? 0 ) <= 0 ) {
		return new WP_Error( 'wpagent_wpforms_confirmation_page', __( 'Eine Seitenbestätigung benötigt page_id.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	if ( 'redirect' === $type && '' === trim( (string) ( $result['redirect'] ?? '' ) ) ) {
		return new WP_Error( 'wpagent_wpforms_confirmation_url', __( 'Eine Weiterleitungsbestätigung benötigt redirect.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	return $result;
}

/** @param array<string,mixed> $current @param array<string,mixed> $patch @param array<string,mixed> $form_data @return array<string,mixed>|WP_Error */
function wpagent_wpforms_prepare_notification( array $current, array $patch, array $form_data ) {
	$map = array(
		'name' => 'notification_name', 'email' => 'email', 'subject' => 'subject', 'sender_name' => 'sender_name',
		'sender_address' => 'sender_address', 'reply_to' => 'replyto', 'carbon_copy' => 'carboncopy', 'message' => 'message',
	);
	if ( array_diff( array_keys( $patch ), array_keys( $map ) ) ) {
		return new WP_Error( 'wpagent_wpforms_notification_fields', __( 'Die WPForms-Benachrichtigung enthält ein nicht unterstütztes Feld.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$result          = $current;
	$email_field_ids = wpagent_wpforms_notification_email_field_ids( $form_data );
	foreach ( $patch as $public => $value ) {
		$native = $map[ $public ];
		if ( 'email' === $public || 'carbon_copy' === $public ) {
			$value = wpagent_wpforms_notification_addresses( $value, $public, true, 'carbon_copy' === $public, $email_field_ids, true, true );
		} elseif ( 'sender_address' === $public ) {
			$value = wpagent_wpforms_notification_addresses( $value, $public, false, false, $email_field_ids, false, false );
		} elseif ( 'reply_to' === $public ) {
			$value = wpagent_wpforms_notification_addresses( $value, $public, false, true, $email_field_ids, true, true );
		} elseif ( 'message' === $public ) {
			$value = wpagent_wpforms_delivery_plain_text( $value, $public, 100000 );
		} else {
			$value = wpagent_wpforms_notification_header( $value, $public, 'subject' === $public ? 998 : 255 );
		}
		if ( is_wp_error( $value ) ) {
			return $value;
		}
		$result[ $native ] = $value;
	}
	if ( '' === trim( (string) ( $result['email'] ?? '' ) ) || '' === trim( (string) ( $result['message'] ?? '' ) ) ) {
		return new WP_Error( 'wpagent_wpforms_notification_required', __( 'Eine WPForms-Benachrichtigung benötigt mindestens Empfänger und Nachricht.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	return $result;
}

/** @param array<string,mixed> $before @param array<string,mixed> $target @return true|WP_Error */
function wpagent_wpforms_delivery_save( array $before, array $target ) {
	$conflict = false;
	$guard    = static function ( $post_data ) use ( $before, &$conflict ) {
		$current_raw = wpagent_wpforms_delivery_stored_raw( $before['form_id'] );
		if ( ! is_string( $current_raw ) || ! hash_equals( (string) $before['raw'], $current_raw ) ) {
			$conflict = true;
			throw new RuntimeException( 'WPAgently WPForms concurrent delivery change' );
		}
		return $post_data;
	};
	add_filter( 'wpforms_save_form_args', $guard, PHP_INT_MAX, 1 );
	try {
		$result = $before['provider']->update( $before['form_id'], $target, array( 'cap' => 'edit_form_single' ) );
	} catch ( Throwable $error ) {
		if ( $conflict ) {
			$current = wpagent_wpforms_delivery_state( $before['form_id'] );
			return new WP_Error(
				'wpagent_wpforms_delivery_conflict',
				__( 'Das WPForms-Formular wurde während des Schreibens verändert.', 'wp-agent-companion' ),
				array(
					'status'        => 409,
					'current_hash'  => is_wp_error( $current ) ? '' : $current['state_hash'],
					'current_error' => is_wp_error( $current ) ? $current->get_error_code() : '',
				)
			);
		}
		return wpagent_wpforms_delivery_recovery_required( $before['form_id'] );
	} finally {
		remove_filter( 'wpforms_save_form_args', $guard, PHP_INT_MAX );
	}
	if ( $before['form_id'] !== absint( $result ) ) {
		return wpagent_wpforms_delivery_recovery_required( $before['form_id'] );
	}
	return true;
}

function wpagent_wpforms_delivery_recovery_required( int $form_id ): WP_Error {
	return new WP_Error( 'wpagent_wpforms_delivery_recovery_required', __( 'Der WPForms-Schreibversuch könnte teilweise gespeichert worden sein. Prüfe den aktuellen Formularzustand manuell, bevor du erneut schreibst.', 'wp-agent-companion' ), array( 'status' => 409, 'recovery_required' => true, 'form_id' => $form_id ) );
}

/** @param mixed $input @param callable(array<string,mixed>):(array<string,mixed>|WP_Error) $mutator @return array<string,mixed>|WP_Error */
function wpagent_wpforms_delivery_mutate( $input, callable $mutator ) {
	$input         = is_array( $input ) ? $input : array();
	$form_id       = absint( $input['form_id'] ?? 0 );
	$expected_hash = wpagent_wpforms_delivery_expected_hash( $input['expected_hash'] ?? '' );
	if ( is_wp_error( $expected_hash ) ) {
		return $expected_hash;
	}
	$lock = wpagent_wpforms_delivery_acquire_lock( $form_id );
	if ( is_wp_error( $lock ) ) {
		return $lock;
	}
	try {
		if ( ! wpagent_wpforms_delivery_lock_is_owned( $form_id, $lock ) ) {
			return new WP_Error( 'wpagent_wpforms_delivery_lock_lost', __( 'Die Sperre für die WPForms-Zustellung ging verloren. Lies den Zustand erneut.', 'wp-agent-companion' ), array( 'status' => 409 ) );
		}
		$before = wpagent_wpforms_delivery_state( $form_id );
		if ( is_wp_error( $before ) ) {
			return $before;
		}
		if ( ! hash_equals( $before['state_hash'], $expected_hash ) ) {
			return new WP_Error( 'wpagent_wpforms_delivery_conflict', __( 'Das WPForms-Formular wurde seit dem Lesen verändert.', 'wp-agent-companion' ), array( 'status' => 409, 'current_hash' => $before['state_hash'] ) );
		}
		$target = $mutator( $before );
		if ( is_wp_error( $target ) ) {
			return $target;
		}
		$encoded = wp_json_encode( $target, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE );
		if ( false === $encoded || strlen( $encoded ) > WPAGENT_WPFORMS_DELIVERY_MAX_BYTES ) {
			return new WP_Error( 'wpagent_wpforms_delivery_too_large', __( 'Die resultierenden WPForms-Daten sind ungültig oder größer als 1 MiB.', 'wp-agent-companion' ), array( 'status' => 409 ) );
		}
		if ( ! wpagent_wpforms_delivery_lock_is_owned( $form_id, $lock ) ) {
			return new WP_Error( 'wpagent_wpforms_delivery_lock_lost', __( 'Die Sperre für die WPForms-Zustellung ging vor dem Speichern verloren. Lies den Zustand erneut.', 'wp-agent-companion' ), array( 'status' => 409 ) );
		}
		$target_delivery_hash = wpagent_wpforms_delivery_hash( wpagent_wpforms_delivery_material( $target ) );
		$saved = wpagent_wpforms_delivery_save( $before, $target );
		if ( is_wp_error( $saved ) ) {
			return $saved;
		}
		$fresh = wpagent_wpforms_delivery_state( $form_id );
		if ( ! is_wp_error( $fresh ) && hash_equals( $target_delivery_hash, $fresh['delivery_hash'] ) && hash_equals( $before['preserved_hash'], $fresh['preserved_hash'] ) ) {
			$result = wpagent_wpforms_delivery_public( $fresh, false );
			$result['verified'] = true;
			return $result;
		}
		return wpagent_wpforms_delivery_recovery_required( $form_id );
	} finally {
		wpagent_wpforms_delivery_release_lock( $form_id, $lock );
	}
}

/**
 * WPForms exposes no provider-side compare-and-update primitive. Existing
 * delivery resources remain registered for discoverability, but this shared
 * preflight deliberately stops before the mutable provider call.
 *
 * @param mixed $input
 * @param callable(array<string,mixed>):(array<string,mixed>|WP_Error) $preflight
 * @return array<string,mixed>|WP_Error
 */
function wpagent_wpforms_delivery_manual_only_update( $input, callable $preflight ) {
	$input         = is_array( $input ) ? $input : array();
	$form_id       = absint( $input['form_id'] ?? 0 );
	$expected_hash = wpagent_wpforms_delivery_expected_hash( $input['expected_hash'] ?? '' );
	if ( is_wp_error( $expected_hash ) ) {
		return $expected_hash;
	}
	$lock = wpagent_wpforms_delivery_acquire_lock( $form_id );
	if ( is_wp_error( $lock ) ) {
		return $lock;
	}
	try {
		if ( ! wpagent_wpforms_delivery_lock_is_owned( $form_id, $lock ) ) {
			return new WP_Error( 'wpagent_wpforms_delivery_lock_lost', __( 'Die Sperre für die WPForms-Zustellung ging verloren. Lies den Zustand erneut.', 'wp-agent-companion' ), array( 'status' => 409 ) );
		}
		$before = wpagent_wpforms_delivery_state( $form_id );
		if ( is_wp_error( $before ) ) {
			return $before;
		}
		if ( ! hash_equals( $before['state_hash'], $expected_hash ) ) {
			return new WP_Error( 'wpagent_wpforms_delivery_conflict', __( 'Das WPForms-Formular wurde seit dem Lesen verändert.', 'wp-agent-companion' ), array( 'status' => 409, 'current_hash' => $before['state_hash'] ) );
		}
		$target = $preflight( $before );
		if ( is_wp_error( $target ) ) {
			return $target;
		}
		if ( ! wpagent_wpforms_delivery_lock_is_owned( $form_id, $lock ) ) {
			return new WP_Error( 'wpagent_wpforms_delivery_lock_lost', __( 'Die Sperre für die WPForms-Zustellung ging verloren. Lies den Zustand erneut.', 'wp-agent-companion' ), array( 'status' => 409 ) );
		}
		return new WP_Error( 'wpagent_wpforms_delivery_update_manual_only', __( 'WPForms bietet keine atomare Compare-and-Update-Operation für bestehende Zustellungsregeln. Nimm die Änderung in WordPress manuell vor, damit parallele Editor-Änderungen erhalten bleiben.', 'wp-agent-companion' ), array( 'status' => 409, 'form_id' => $form_id, 'current_hash' => $before['state_hash'] ) );
	} finally {
		wpagent_wpforms_delivery_release_lock( $form_id, $lock );
	}
}

function wpagent_ability_update_wpforms_confirmation(): array {
	$properties = wpagent_wpforms_confirmation_schema()['properties'];
	unset( $properties['id'], $properties['hash'] );
	$properties['page_id']['minimum'] = 0;
	$properties['message']['maxLength'] = 100000;
	$properties['page_url_parameters']['maxLength'] = 4096;
	$properties['redirect']['maxLength'] = 4096;
	return array(
		'label' => __( 'WPForms-Bestätigung aktualisieren', 'wp-agent-companion' ),
		'description' => __( 'Prüft eine vorhandene WPForms-Bestätigungsänderung gegen den vollständigen Formular-Hash. Das Speichern bleibt ohne atomare Provider-Compare-and-Update-Operation manuell.', 'wp-agent-companion' ),
		'category' => 'wp-agent',
		'input_schema' => array(
			'type' => 'object', 'additionalProperties' => false,
			'properties' => array(
				'form_id' => array( 'type' => 'integer', 'minimum' => 1 ), 'confirmation_id' => array( 'type' => 'integer', 'minimum' => 1 ),
				'expected_hash' => array( 'type' => 'string', 'pattern' => '^[a-f0-9]{64}$' ),
				'confirmation' => array( 'type' => 'object', 'additionalProperties' => false, 'minProperties' => 1, 'properties' => $properties ),
			),
			'required' => array( 'form_id', 'confirmation_id', 'expected_hash', 'confirmation' ),
		),
		'output_schema' => array( 'type' => 'object', 'properties' => array_merge( wpagent_wpforms_delivery_output_schema()['properties'], array( 'verified' => array( 'type' => 'boolean' ) ) ) ),
		'execute_callback' => 'wpagent_exec_update_wpforms_confirmation', 'permission_callback' => 'wpagent_perm_wpforms_delivery',
		'meta' => array( 'show_in_rest' => true, 'annotations' => array( 'readonly' => false, 'destructive' => false, 'idempotent' => false, 'manual_only' => true ) ),
	);
}

/** @param mixed $input @return array<string,mixed>|WP_Error */
function wpagent_exec_update_wpforms_confirmation( $input ) {
	$input = is_array( $input ) ? $input : array();
	$id    = absint( $input['confirmation_id'] ?? 0 );
	$patch = is_array( $input['confirmation'] ?? null ) ? $input['confirmation'] : array();
	return wpagent_wpforms_delivery_manual_only_update(
		$input,
		static function ( array $before ) use ( $id, $patch ) {
			if ( ! isset( $before['confirmations'][ $id ] ) ) {
				return new WP_Error( 'wpagent_wpforms_confirmation_not_found', __( 'Die WPForms-Bestätigung wurde nicht gefunden.', 'wp-agent-companion' ), array( 'status' => 404 ) );
			}
			$prepared = wpagent_wpforms_prepare_confirmation( $before['confirmations'][ $id ], $patch );
			if ( is_wp_error( $prepared ) ) {
				return $prepared;
			}
			$target = $before['data'];
			$target['settings']['confirmations'][ (string) $id ] = $prepared;
			return $target;
		}
	);
}

function wpagent_ability_update_wpforms_notification(): array {
	$properties = wpagent_wpforms_notification_schema()['properties'];
	unset( $properties['id'], $properties['hash'] );
	$properties['message']['maxLength'] = 100000;
	foreach ( array( 'email', 'sender_address', 'reply_to', 'carbon_copy' ) as $field ) {
		$properties[ $field ]['maxLength'] = 2000;
	}
	return array(
		'label' => __( 'WPForms-Benachrichtigung aktualisieren', 'wp-agent-companion' ),
		'description' => __( 'Prüft eine vorhandene WPForms-E-Mail-Benachrichtigungsänderung gegen den vollständigen Formular-Hash. Kopfzeilen, Empfänger und Text werden begrenzt. Das Speichern bleibt ohne atomare Provider-Compare-and-Update-Operation manuell.', 'wp-agent-companion' ),
		'category' => 'wp-agent',
		'input_schema' => array(
			'type' => 'object', 'additionalProperties' => false,
			'properties' => array(
				'form_id' => array( 'type' => 'integer', 'minimum' => 1 ), 'notification_id' => array( 'type' => 'integer', 'minimum' => 1 ),
				'expected_hash' => array( 'type' => 'string', 'pattern' => '^[a-f0-9]{64}$' ), 'notifications_enabled' => array( 'type' => 'boolean' ),
				'notification' => array( 'type' => 'object', 'additionalProperties' => false, 'properties' => $properties ),
			),
			'required' => array( 'form_id', 'notification_id', 'expected_hash' ),
		),
		'output_schema' => array( 'type' => 'object', 'properties' => array_merge( wpagent_wpforms_delivery_output_schema()['properties'], array( 'verified' => array( 'type' => 'boolean' ) ) ) ),
		'execute_callback' => 'wpagent_exec_update_wpforms_notification', 'permission_callback' => 'wpagent_perm_wpforms_delivery',
		'meta' => array( 'show_in_rest' => true, 'annotations' => array( 'readonly' => false, 'destructive' => false, 'idempotent' => false, 'manual_only' => true ) ),
	);
}

/** @param mixed $input @return array<string,mixed>|WP_Error */
function wpagent_exec_update_wpforms_notification( $input ) {
	$input       = is_array( $input ) ? $input : array();
	$id          = absint( $input['notification_id'] ?? 0 );
	$patch       = is_array( $input['notification'] ?? null ) ? $input['notification'] : array();
	$has_enabled = array_key_exists( 'notifications_enabled', $input );
	if ( ! $patch && ! $has_enabled ) {
		return new WP_Error( 'wpagent_wpforms_notification_fields', __( 'Übergebe eine Benachrichtigungsänderung oder notifications_enabled.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	return wpagent_wpforms_delivery_manual_only_update(
		$input,
		static function ( array $before ) use ( $id, $patch, $has_enabled, $input ) {
			if ( ! isset( $before['notifications'][ $id ] ) ) {
				return new WP_Error( 'wpagent_wpforms_notification_not_found', __( 'Die WPForms-Benachrichtigung wurde nicht gefunden.', 'wp-agent-companion' ), array( 'status' => 404 ) );
			}
			$prepared = $patch ? wpagent_wpforms_prepare_notification( $before['notifications'][ $id ], $patch, $before['data'] ) : $before['notifications'][ $id ];
			if ( is_wp_error( $prepared ) ) {
				return $prepared;
			}
			$target = $before['data'];
			$target['settings']['notifications'][ (string) $id ] = $prepared;
			if ( $has_enabled ) {
				$target['settings']['notification_enable'] = rest_sanitize_boolean( $input['notifications_enabled'] ) ? '1' : '0';
			}
			return $target;
		}
	);
}
