<?php
/** Shared provider, target, field and value contracts for Pods meta values. */

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

if ( ! defined( 'WPAGENT_PODS_META_VALUES_MAX_FIELDS' ) ) {
	define( 'WPAGENT_PODS_META_VALUES_MAX_FIELDS', 20 );
}
if ( ! defined( 'WPAGENT_PODS_META_VALUES_MAX_TEXT' ) ) {
	define( 'WPAGENT_PODS_META_VALUES_MAX_TEXT', 5000 );
}
if ( ! defined( 'WPAGENT_PODS_META_VALUES_MAX_NUMBER_DIGITS' ) ) {
	define( 'WPAGENT_PODS_META_VALUES_MAX_NUMBER_DIGITS', 15 );
}
if ( ! defined( 'WPAGENT_PODS_META_VALUES_LOCK_TTL' ) ) {
	define( 'WPAGENT_PODS_META_VALUES_LOCK_TTL', 300 );
}

/** @return true|WP_Error */
function wpagent_pods_meta_values_provider() {
	$available = wpagent_pods_require_api();
	if ( is_wp_error( $available ) ) {
		return $available;
	}
	$version = defined( 'PODS_VERSION' ) ? (string) PODS_VERSION : '';
	if ( '' === $version || version_compare( $version, '3.3.9', '<' ) || version_compare( $version, '4.0.0', '>=' ) ) {
		return new WP_Error( 'wpagent_pods_meta_values_version', __( 'Dieser Pods-Wertepfad ist nur für Pods 3.3.9 bis zur nächsten Hauptversion freigegeben.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	if ( ! function_exists( 'pods' ) ) {
		return new WP_Error( 'wpagent_pods_meta_values_api', __( 'Die native Pods-Objekt-API ist nicht verfügbar.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	return true;
}

/** @return string|WP_Error */
function wpagent_pods_meta_values_model_name( $value ) {
	$name = wpagent_pods_name( $value );
	if ( is_wp_error( $name ) ) {
		return $name;
	}
	return $name;
}

/** @return string|WP_Error */
function wpagent_pods_meta_values_object_type( $value ) {
	if ( ! is_string( $value ) || ! in_array( $value, array( 'post', 'term' ), true ) ) {
		return new WP_Error( 'wpagent_pods_meta_values_object_type', __( 'object_type muss post oder term sein.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	return $value;
}

/** @return int|WP_Error */
function wpagent_pods_meta_values_object_id( $value ) {
	$id = filter_var( $value, FILTER_VALIDATE_INT, array( 'options' => array( 'min_range' => 1 ) ) );
	if ( false === $id ) {
		return new WP_Error( 'wpagent_pods_meta_values_object_id', __( 'object_id muss eine positive Ganzzahl sein.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	return (int) $id;
}

/** @return string[] */
function wpagent_pods_meta_values_supported_types(): array {
	return array( 'text', 'email', 'date', 'number', 'boolean' );
}

/** @return bool */
function wpagent_pods_meta_values_field_is_supported( array $state ): bool {
	return in_array( (string) ( $state['type'] ?? '' ), wpagent_pods_meta_values_supported_types(), true )
		&& empty( $state['repeatable'] )
		&& empty( $state['multiple'] )
		&& '' === (string) ( $state['relationship_object'] ?? '' )
		&& '' === (string) ( $state['relationship_target'] ?? '' )
		&& 0 === (int) ( $state['relationship_count'] ?? 0 );
}

/** @return array<string,mixed>|WP_Error */
function wpagent_pods_meta_values_fields( object $pod, array $model_state ) {
	try {
		$raw_fields = wpagent_pods_model_fields( $pod );
	} catch ( Throwable $error ) {
		return new WP_Error( 'wpagent_pods_meta_values_fields', __( 'Die Pods-Felder konnten nicht vollständig gelesen werden.', 'wp-agent-companion' ), array( 'status' => 500 ) );
	}
	if ( count( $raw_fields ) > WPAGENT_PODS_META_VALUES_MAX_FIELDS || count( $raw_fields ) !== (int) ( $model_state['field_count'] ?? -1 ) ) {
		return new WP_Error( 'wpagent_pods_meta_values_field_limit', __( 'Dieses Pods-Modell überschreitet die Obergrenze für den sicheren Wertepfad.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	$state_by_name = array();
	foreach ( $model_state['fields'] ?? array() as $state ) {
		if ( ! is_array( $state ) || ! is_string( $state['name'] ?? null ) || '' === $state['name'] || isset( $state_by_name[ $state['name'] ] ) ) {
			return new WP_Error( 'wpagent_pods_meta_values_schema', __( 'Pods lieferte eine unvollständige oder doppelte Felddefinition.', 'wp-agent-companion' ), array( 'status' => 409 ) );
		}
		$state_by_name[ $state['name'] ] = $state;
	}
	$entries = array();
	$field_material = array();
	foreach ( $raw_fields as $field ) {
		$args = $field->get_args();
		$name = is_array( $args ) ? (string) ( $args['name'] ?? '' ) : '';
		if ( '' === $name || ! isset( $state_by_name[ $name ] ) || isset( $entries[ $name ] ) || ! is_array( $args ) ) {
			return new WP_Error( 'wpagent_pods_meta_values_schema', __( 'Pods lieferte eine unvollständige oder doppelte Felddefinition.', 'wp-agent-companion' ), array( 'status' => 409 ) );
		}
		$state = $state_by_name[ $name ];
		if ( ! hash_equals( (string) ( $state['hash'] ?? '' ), wpagent_pods_hash( $args ) ) ) {
			return new WP_Error( 'wpagent_pods_meta_values_schema', __( 'Die Pods-Felddefinition änderte sich während des Lesens.', 'wp-agent-companion' ), array( 'status' => 409 ) );
		}
		$field_material[ $name ] = $args;
		$entries[ $name ] = array( 'name' => $name, 'state' => $state, 'args' => $args, 'supported' => wpagent_pods_meta_values_field_is_supported( $state ) );
	}
	ksort( $entries, SORT_STRING );
	ksort( $field_material, SORT_STRING );
	return array( 'entries' => $entries, 'field_hash' => wpagent_pods_hash( $field_material ) );
}

/** @return array<string,mixed>|WP_Error */
function wpagent_pods_meta_values_context( $model_name, $object_type, $object_id ) {
	$provider = wpagent_pods_meta_values_provider();
	if ( is_wp_error( $provider ) ) {
		return $provider;
	}
	$name = wpagent_pods_meta_values_model_name( $model_name );
	$type = wpagent_pods_meta_values_object_type( $object_type );
	$id   = wpagent_pods_meta_values_object_id( $object_id );
	if ( is_wp_error( $name ) || is_wp_error( $type ) || is_wp_error( $id ) ) {
		return is_wp_error( $name ) ? $name : ( is_wp_error( $type ) ? $type : $id );
	}
	$pod = wpagent_pods_get_model( $name );
	if ( is_wp_error( $pod ) ) {
		return $pod;
	}
	try {
		$model_state = wpagent_pods_model_state( $pod );
	} catch ( Throwable $error ) {
		return new WP_Error( 'wpagent_pods_meta_values_model', __( 'Das Pods-Modell konnte nicht vollständig gelesen werden.', 'wp-agent-companion' ), array( 'status' => 500 ) );
	}
	$kind = (string) ( $model_state['kind'] ?? '' );
	if ( ( 'post' === $type && 'post_type' !== $kind ) || ( 'term' === $type && 'taxonomy' !== $kind ) ) {
		return new WP_Error( 'wpagent_pods_meta_values_target', __( 'Das Ziel passt nicht zum Pods-Modell.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	if ( empty( $model_state['runtime_registered'] ) ) {
		return new WP_Error( 'wpagent_pods_meta_values_not_registered', __( 'Das Pods-Modell ist in diesem Request nicht als native WordPress-Struktur registriert.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	if ( 'post' === $type ) {
		$post = get_post( $id );
		if ( ! $post || (string) $post->post_type !== $name ) {
			return new WP_Error( 'wpagent_pods_meta_values_target', __( 'Der Beitrag gehört nicht zum angegebenen Pods-Modell.', 'wp-agent-companion' ), array( 'status' => 404 ) );
		}
	} else {
		$term = get_term( $id );
		if ( ! $term instanceof WP_Term || (string) $term->taxonomy !== $name ) {
			return new WP_Error( 'wpagent_pods_meta_values_target', __( 'Der Begriff gehört nicht zur angegebenen Pods-Taxonomie.', 'wp-agent-companion' ), array( 'status' => 404 ) );
		}
	}
	$fields = wpagent_pods_meta_values_fields( $pod, $model_state );
	if ( is_wp_error( $fields ) ) {
		return $fields;
	}
	try {
		$native = pods( $name, $id, true );
	} catch ( Throwable $error ) {
		return new WP_Error( 'wpagent_pods_meta_values_native', __( 'Das native Pods-Objekt konnte nicht geladen werden.', 'wp-agent-companion' ), array( 'status' => 500 ) );
	}
	if ( ! is_object( $native ) || ! is_callable( array( $native, 'raw' ) ) || ! is_callable( array( $native, 'save' ) ) ) {
		return new WP_Error( 'wpagent_pods_meta_values_native', __( 'Das native Pods-Objekt unterstützt den sicheren Wertepfad nicht.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	return array(
		'model_name' => $name,
		'object_type' => $type,
		'object_id' => $id,
		'pod' => $pod,
		'native' => $native,
		'model_state' => $model_state,
		'entries' => $fields['entries'],
		'field_hash' => $fields['field_hash'],
		'provider_version' => defined( 'PODS_VERSION' ) ? (string) PODS_VERSION : '',
	);
}

function wpagent_pods_meta_values_can_edit( array $context ): bool {
	if ( 'post' === $context['object_type'] ) {
		return current_user_can( 'edit_post', (int) $context['object_id'] );
	}
	return current_user_can( 'edit_term', (int) $context['object_id'] );
}

function wpagent_perm_pods_meta_values( $input = null ): bool {
	if ( ! is_array( $input ) ) {
		return current_user_can( 'read' );
	}
	$context = wpagent_pods_meta_values_context( $input['model_name'] ?? null, $input['object_type'] ?? null, $input['object_id'] ?? null );
	return ! is_wp_error( $context ) && wpagent_pods_meta_values_can_edit( $context );
}

/** @return string|WP_Error */
function wpagent_pods_meta_values_validate_text( $value, string $label, int $max, bool $required = false ) {
	if ( null === $value ) {
		$value = '';
	}
	if ( ! is_string( $value ) ) {
		return new WP_Error( 'wpagent_pods_meta_values_value', sprintf( __( '%s muss Text sein.', 'wp-agent-companion' ), $label ), array( 'status' => 400 ) );
	}
	$value = trim( $value );
	if ( ( $required && '' === $value ) || wpagent_pods_text_length( $value ) > $max || sanitize_text_field( $value ) !== $value ) {
		/* translators: %s: Pods field label. */
		return new WP_Error( 'wpagent_pods_meta_values_value', sprintf( __( '%s ist leer, zu lang oder enthält nicht erlaubte Zeichen.', 'wp-agent-companion' ), $label ), array( 'status' => 400 ) );
	}
	return $value;
}

/** @return string|WP_Error */
function wpagent_pods_meta_values_validate_date( $value, string $label, bool $required = false ) {
	$value = wpagent_pods_meta_values_validate_text( $value, $label, 10, $required );
	if ( is_wp_error( $value ) || '' === $value ) {
		return $value;
	}
	$date = DateTimeImmutable::createFromFormat( '!Y-m-d', $value );
	$errors = DateTimeImmutable::getLastErrors();
	if ( ! $date || ( is_array( $errors ) && ( $errors['warning_count'] > 0 || $errors['error_count'] > 0 ) ) || $date->format( 'Y-m-d' ) !== $value ) {
		/* translators: %s: Pods field label. */
		return new WP_Error( 'wpagent_pods_meta_values_date', sprintf( __( '%s muss ein gültiges Datum im Format JJJJ-MM-TT sein.', 'wp-agent-companion' ), $label ), array( 'status' => 400 ) );
	}
	return $value;
}

/** @return string|WP_Error */
function wpagent_pods_meta_values_validate_number( $value, string $label, array $args, bool $required = false ) {
	if ( null === $value || '' === $value ) {
		if ( $required ) {
			return new WP_Error( 'wpagent_pods_meta_values_number', sprintf( __( '%s darf nicht leer sein.', 'wp-agent-companion' ), $label ), array( 'status' => 400 ) );
		}
		return null;
	}
	if ( is_bool( $value ) || ( ! is_int( $value ) && ! is_float( $value ) && ! is_string( $value ) ) ) {
		/* translators: %s: Pods field label. */
		return new WP_Error( 'wpagent_pods_meta_values_number', sprintf( __( '%s muss eine endliche Dezimalzahl sein.', 'wp-agent-companion' ), $label ), array( 'status' => 400 ) );
	}
	if ( is_float( $value ) && ! is_finite( $value ) ) {
		/* translators: %s: Pods field label. */
		return new WP_Error( 'wpagent_pods_meta_values_number', sprintf( __( '%s muss eine endliche Dezimalzahl sein.', 'wp-agent-companion' ), $label ), array( 'status' => 400 ) );
	}
	$text = trim( (string) $value );
	if ( ! preg_match( '/^-?(?:0|[1-9][0-9]*)(?:\.[0-9]+)?$/D', $text ) ) {
		/* translators: %s: Pods field label. */
		return new WP_Error( 'wpagent_pods_meta_values_number', sprintf( __( '%s muss eine Dezimalzahl ohne Exponent sein.', 'wp-agent-companion' ), $label ), array( 'status' => 400 ) );
	}
	$negative = str_starts_with( $text, '-' );
	$text = ltrim( $text, '+-' );
	$parts = explode( '.', $text, 2 );
	$integer = ltrim( $parts[0], '0' );
	$integer = '' === $integer ? '0' : $integer;
	$fraction = $parts[1] ?? '';
	$decimals = max( 0, min( 30, (int) ( $args['number_decimals'] ?? 0 ) ) );
	if ( strlen( $fraction ) > $decimals && trim( $fraction, '0' ) !== '' ) {
		/* translators: %s: Pods field label. */
		return new WP_Error( 'wpagent_pods_meta_values_number', sprintf( __( '%s überschreitet die Dezimalpräzision des Pods-Feldes.', 'wp-agent-companion' ), $label ), array( 'status' => 400 ) );
	}
	$fraction = rtrim( $fraction, '0' );
	$digits = strlen( ltrim( $integer . $fraction, '0' ) );
	if ( 0 === $digits ) {
		return '0';
	}
	$max_digits = (int) ( $args['number_max_length'] ?? WPAGENT_PODS_META_VALUES_MAX_NUMBER_DIGITS );
	$max_digits = $max_digits < 1 ? WPAGENT_PODS_META_VALUES_MAX_NUMBER_DIGITS : min( $max_digits, WPAGENT_PODS_META_VALUES_MAX_NUMBER_DIGITS );
	if ( $digits > $max_digits ) {
		/* translators: %s: Pods field label. */
		return new WP_Error( 'wpagent_pods_meta_values_number', sprintf( __( '%s überschreitet die sichere Ziffernobergrenze.', 'wp-agent-companion' ), $label ), array( 'status' => 400 ) );
	}
	if ( '' === $fraction ) {
		return ( $negative ? '-' : '' ) . $integer;
	}
	return ( $negative ? '-' : '' ) . $integer . '.' . $fraction;
}

/** @return string|WP_Error */
function wpagent_pods_meta_values_validate_value( array $entry, $value ) {
	$state = $entry['state'];
	$type = (string) $state['type'];
	$label = (string) ( $state['label'] ?? $entry['name'] );
	$required = ! empty( $state['required'] );
	if ( 'text' === $type ) {
		$max = (int) ( $entry['args']['text_max_length'] ?? WPAGENT_PODS_META_VALUES_MAX_TEXT );
		$max = $max < 1 ? WPAGENT_PODS_META_VALUES_MAX_TEXT : min( $max, WPAGENT_PODS_META_VALUES_MAX_TEXT );
		return wpagent_pods_meta_values_validate_text( $value, $label, $max, $required );
	}
	if ( 'email' === $type ) {
		$value = wpagent_pods_meta_values_validate_text( $value, $label, min( 255, WPAGENT_PODS_META_VALUES_MAX_TEXT ), $required );
		if ( is_wp_error( $value ) || '' === $value ) {
			return $value;
		}
		if ( ! is_email( $value ) ) {
			/* translators: %s: Pods field label. */
			return new WP_Error( 'wpagent_pods_meta_values_email', sprintf( __( '%s muss eine gültige E-Mail-Adresse sein.', 'wp-agent-companion' ), $label ), array( 'status' => 400 ) );
		}
		$max = (int) ( $entry['args']['email_max_length'] ?? 255 );
		$max = $max < 1 ? 255 : min( $max, WPAGENT_PODS_META_VALUES_MAX_TEXT );
		if ( wpagent_pods_text_length( $value ) > $max ) {
			/* translators: %s: Pods field label. */
			return new WP_Error( 'wpagent_pods_meta_values_email', sprintf( __( '%s überschreitet die Feldlänge.', 'wp-agent-companion' ), $label ), array( 'status' => 400 ) );
		}
		return $value;
	}
	if ( 'date' === $type ) {
		return wpagent_pods_meta_values_validate_date( $value, $label, $required );
	}
	if ( 'number' === $type ) {
		return wpagent_pods_meta_values_validate_number( $value, $label, $entry['args'], $required );
	}
	if ( 'boolean' === $type ) {
		if ( null === $value ) {
			$value = false;
		}
		return wpagent_pods_boolean( $value, $label );
	}
	return new WP_Error( 'wpagent_pods_meta_values_field', __( 'Das Pods-Feld ist für diesen Wertepfad nicht freigegeben.', 'wp-agent-companion' ), array( 'status' => 400 ) );
}

/** @return mixed|WP_Error */
function wpagent_pods_meta_values_normalize_raw( array $entry, $raw ) {
	$type = (string) $entry['state']['type'];
	if ( 'text' === $type || 'email' === $type ) {
		return ( false === $raw || null === $raw ) ? '' : ( is_scalar( $raw ) ? (string) $raw : new WP_Error( 'wpagent_pods_meta_values_readback', __( 'Pods lieferte einen nichtskalaren Wert zurück.', 'wp-agent-companion' ), array( 'status' => 500 ) ) );
	}
	if ( 'date' === $type ) {
		$value = ( false === $raw || null === $raw || '0000-00-00' === (string) $raw ) ? '' : ( is_scalar( $raw ) ? (string) $raw : '' );
		if ( '' === $value ) {
			return '';
		}
		return wpagent_pods_meta_values_validate_date( $value, $entry['name'] );
	}
	if ( 'number' === $type ) {
		if ( false === $raw || null === $raw || '' === $raw ) {
			return null;
		}
		$value = wpagent_pods_meta_values_validate_number( $raw, $entry['name'], $entry['args'] );
		if ( is_wp_error( $value ) || null === $value ) {
			return $value;
		}
		return false !== strpos( (string) $value, '.' ) ? (float) $value : (int) $value;
	}
	if ( 'boolean' === $type ) {
		if ( in_array( $raw, array( false, null, 0, '0', '' ), true ) ) {
			return false;
		}
		if ( in_array( $raw, array( true, 1, '1', 'true' ), true ) ) {
			return true;
		}
		return new WP_Error( 'wpagent_pods_meta_values_readback', __( 'Pods lieferte keinen gültigen booleschen Wert zurück.', 'wp-agent-companion' ), array( 'status' => 500 ) );
	}
	return new WP_Error( 'wpagent_pods_meta_values_readback', __( 'Pods lieferte einen nicht unterstützten Feldtyp zurück.', 'wp-agent-companion' ), array( 'status' => 500 ) );
}

function wpagent_pods_meta_values_number_token( $value ): string {
	if ( null === $value || '' === $value ) {
		return '';
	}
	$text = trim( (string) $value );
	$negative = str_starts_with( $text, '-' );
	$text = ltrim( $text, '+-' );
	$parts = explode( '.', $text, 2 );
	$integer = ltrim( $parts[0], '0' );
	$integer = '' === $integer ? '0' : $integer;
	$fraction = rtrim( $parts[1] ?? '', '0' );
	if ( '0' === $integer && '' === $fraction ) {
		return '0';
	}
	return ( $negative ? '-' : '' ) . $integer . ( '' === $fraction ? '' : '.' . $fraction );
}

function wpagent_pods_meta_values_equal( array $entry, $left, $right ): bool {
	if ( 'number' === (string) $entry['state']['type'] ) {
		return wpagent_pods_meta_values_number_token( $left ) === wpagent_pods_meta_values_number_token( $right );
	}
	return $left === $right;
}

/** @return array<string,mixed>|WP_Error */
function wpagent_pods_meta_values_state( array $context ) {
	$values = array();
	foreach ( $context['entries'] as $name => $entry ) {
		if ( ! $entry['supported'] ) {
			continue;
		}
		try {
			$raw = $context['native']->raw( $name );
		} catch ( Throwable $error ) {
			return new WP_Error( 'wpagent_pods_meta_values_readback', __( 'Ein Pods-Feld konnte nicht vollständig gelesen werden.', 'wp-agent-companion' ), array( 'status' => 500 ) );
		}
		$value = wpagent_pods_meta_values_normalize_raw( $entry, $raw );
		if ( is_wp_error( $value ) ) {
			return $value;
		}
		$values[ $name ] = $value;
	}
	ksort( $values, SORT_STRING );
	$fields = array();
	foreach ( $context['entries'] as $name => $entry ) {
		if ( ! $entry['supported'] ) {
			continue;
		}
		$state = $entry['state'];
		$fields[ $name ] = array(
			'name' => $name,
			'label' => (string) ( $state['label'] ?? $name ),
			'type' => (string) $state['type'],
			'required' => (bool) $state['required'],
			'repeatable' => false,
			'hash' => (string) $state['hash'],
		);
	}
	ksort( $fields, SORT_STRING );
	$state = array(
		'model_name' => $context['model_name'],
		'object_type' => $context['object_type'],
		'object_id' => (int) $context['object_id'],
		'provider_version' => $context['provider_version'],
		'fields' => array_values( $fields ),
		'values' => $values,
		'model_hash' => (string) $context['model_state']['hash'],
		'field_hash' => (string) $context['field_hash'],
	);
	$state['object_hash'] = wpagent_pods_hash( array(
		'blog_id' => get_current_blog_id(),
		'model_name' => $state['model_name'],
		'object_type' => $state['object_type'],
		'object_id' => $state['object_id'],
		'model_hash' => $state['model_hash'],
		'field_hash' => $state['field_hash'],
		'values' => $state['values'],
	) );
	return $state;
}

function wpagent_pods_meta_values_hash_matches( array $state, array $input ): bool {
	foreach ( array( 'model_hash', 'field_hash', 'object_hash' ) as $key ) {
		$expected = $input[ 'expected_' . $key ] ?? '';
		if ( ! is_string( $expected ) || ! preg_match( '/^[a-f0-9]{64}$/D', $expected ) || ! hash_equals( $state[ $key ], $expected ) ) {
			return false;
		}
	}
	return true;
}

function wpagent_pods_meta_values_lock_name( string $model_name, string $object_type, int $object_id ): string {
	return 'wp_agent_pods_meta_values_lock_' . hash( 'sha256', get_current_blog_id() . ':' . $model_name . ':' . $object_type . ':' . $object_id );
}

/** @return string|WP_Error */
function wpagent_pods_meta_values_acquire_lock( string $model_name, string $object_type, int $object_id ) {
	$option = wpagent_pods_meta_values_lock_name( $model_name, $object_type, $object_id );
	$token = wpagent_companion_acquire_option_lock( $option, WPAGENT_PODS_META_VALUES_LOCK_TTL );
	if ( is_string( $token ) ) {
		return $token;
	}
	return new WP_Error( 'wpagent_pods_meta_values_locked', __( 'Dieses Pods-Objekt wird gerade geändert. Versuche es gleich erneut.', 'wp-agent-companion' ), array( 'status' => 409 ) );
}

function wpagent_pods_meta_values_release_lock( string $model_name, string $object_type, int $object_id, string $token ): void {
	wpagent_companion_release_option_lock( wpagent_pods_meta_values_lock_name( $model_name, $object_type, $object_id ), $token );
}

/** @return WP_Error */
function wpagent_pods_meta_values_recovery_error( array $context, string $message, array $current = array() ): WP_Error {
	$data = array(
		'status' => 500,
		'recovery_required' => true,
		'model_name' => $context['model_name'],
		'object_type' => $context['object_type'],
		'object_id' => (int) $context['object_id'],
		'automatic_rollback' => false,
	);
	if ( array() !== $current ) {
		$data['current'] = $current;
	}
	return new WP_Error( 'wpagent_pods_meta_values_recovery_required', $message, $data );
}

/** @return array<string,mixed> */
function wpagent_pods_meta_values_state_schema(): array {
	return array(
		'type' => 'object',
		'properties' => array(
			'model_name' => array( 'type' => 'string' ),
			'object_type' => array( 'type' => 'string', 'enum' => array( 'post', 'term' ) ),
			'object_id' => array( 'type' => 'integer', 'minimum' => 1 ),
			'provider_version' => array( 'type' => 'string' ),
			'fields' => array( 'type' => 'array', 'maxItems' => WPAGENT_PODS_META_VALUES_MAX_FIELDS, 'items' => array(
				'type' => 'object',
				'properties' => array(
					'name' => array( 'type' => 'string' ), 'label' => array( 'type' => 'string' ),
					'type' => array( 'type' => 'string', 'enum' => wpagent_pods_meta_values_supported_types() ),
					'required' => array( 'type' => 'boolean' ), 'repeatable' => array( 'type' => 'boolean' ),
					'hash' => array( 'type' => 'string', 'pattern' => '^[a-f0-9]{64}$' ),
				),
				'required' => array( 'name', 'label', 'type', 'required', 'repeatable', 'hash' ), 'additionalProperties' => false,
			) ),
			'values' => array( 'type' => 'object', 'maxProperties' => WPAGENT_PODS_META_VALUES_MAX_FIELDS, 'additionalProperties' => array( 'type' => array( 'string', 'number', 'boolean', 'null' ) ) ),
			'model_hash' => array( 'type' => 'string', 'pattern' => '^[a-f0-9]{64}$' ),
			'field_hash' => array( 'type' => 'string', 'pattern' => '^[a-f0-9]{64}$' ),
			'object_hash' => array( 'type' => 'string', 'pattern' => '^[a-f0-9]{64}$' ),
		),
		'required' => array( 'model_name', 'object_type', 'object_id', 'provider_version', 'fields', 'values', 'model_hash', 'field_hash', 'object_hash' ),
		'additionalProperties' => false,
	);
}
