<?php
/** Conflict-safe native writes for scalar Pods meta values. */

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

/** @return array<string,mixed> */
function wpagent_pods_meta_values_input_schema(): array {
	return array(
		'type' => 'object',
		'minProperties' => 1,
		'maxProperties' => WPAGENT_PODS_META_VALUES_MAX_FIELDS,
		'additionalProperties' => array( 'type' => array( 'string', 'number', 'boolean', 'null' ) ),
	);
}

/** @return array<string,mixed> */
function wpagent_pods_meta_values_write_schema(): array {
	$schema = wpagent_pods_meta_values_state_schema();
	$schema['properties']['verified_persistence'] = array( 'type' => 'boolean' );
	$schema['properties']['changed'] = array( 'type' => 'boolean' );
	$schema['required'][] = 'verified_persistence';
	$schema['required'][] = 'changed';
	return $schema;
}

function wpagent_ability_update_pods_field_values(): array {
	return array(
		'label' => __( 'Pods-Feldwerte aktualisieren', 'wp-agent-companion' ),
		'description' => __( 'Aktualisiert nur freigegebene, nicht wiederholbare Pods-Metafelder eines Beitrags oder Begriffs nativ über Pods save(). Modell-, Feld- und Objekt-Hash, Berechtigung, create-only Sperre und vollständiger Readback schützen den Write. Ein unklarer gestarteter Write verlangt Wiederherstellung und wird nicht automatisch zurückgerollt.', 'wp-agent-companion' ),
		'category' => 'wp-agent',
		'input_schema' => array(
			'type' => 'object',
			'properties' => array(
				'model_name' => array( 'type' => 'string', 'pattern' => '^[a-z][a-z0-9_]{0,63}$' ),
				'object_type' => array( 'type' => 'string', 'enum' => array( 'post', 'term' ) ),
				'object_id' => array( 'type' => 'integer', 'minimum' => 1 ),
				'expected_model_hash' => array( 'type' => 'string', 'pattern' => '^[a-f0-9]{64}$' ),
				'expected_field_hash' => array( 'type' => 'string', 'pattern' => '^[a-f0-9]{64}$' ),
				'expected_object_hash' => array( 'type' => 'string', 'pattern' => '^[a-f0-9]{64}$' ),
				'values' => wpagent_pods_meta_values_input_schema(),
			),
			'required' => array( 'model_name', 'object_type', 'object_id', 'expected_model_hash', 'expected_field_hash', 'expected_object_hash', 'values' ),
			'additionalProperties' => false,
		),
		'output_schema' => wpagent_pods_meta_values_write_schema(),
		'execute_callback' => 'wpagent_exec_update_pods_field_values',
		'permission_callback' => 'wpagent_perm_pods_meta_values',
		'meta' => array( 'show_in_rest' => true, 'annotations' => array( 'readonly' => false, 'destructive' => false, 'idempotent' => true ) ),
	);
}

/** @return array<string,mixed>|WP_Error */
function wpagent_pods_meta_values_validate_input_values( $values, array $context ) {
	if ( ! is_array( $values ) || array() === $values || array_is_list( $values ) || count( $values ) > WPAGENT_PODS_META_VALUES_MAX_FIELDS ) {
		return new WP_Error( 'wpagent_pods_meta_values_values', __( 'values muss 1 bis 20 benannte Feldwerte enthalten.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$validated = array();
	foreach ( $values as $name => $value ) {
		if ( ! is_string( $name ) || ! isset( $context['entries'][ $name ] ) || ! $context['entries'][ $name ]['supported'] ) {
			return new WP_Error( 'wpagent_pods_meta_values_field_unknown', __( 'values enthält ein nicht freigegebenes Pods-Feld.', 'wp-agent-companion' ), array( 'status' => 400 ) );
		}
		$valid = wpagent_pods_meta_values_validate_value( $context['entries'][ $name ], $value );
		if ( is_wp_error( $valid ) ) {
			return $valid;
		}
		$validated[ $name ] = $valid;
	}
	ksort( $validated, SORT_STRING );
	return $validated;
}

/** @return WP_Error */
function wpagent_pods_meta_values_hash_conflict( array $state ): WP_Error {
	return new WP_Error( 'wpagent_pods_meta_values_conflict', __( 'Die Pods-Modell-, Feld- oder Objektwerte wurden seit dem Lesen verändert.', 'wp-agent-companion' ), array(
		'status' => 409,
		'current_model_hash' => $state['model_hash'],
		'current_field_hash' => $state['field_hash'],
		'current_object_hash' => $state['object_hash'],
		'current' => $state,
	) );
}

/** @return array<string,mixed>|WP_Error */
function wpagent_exec_update_pods_field_values( $input ) {
	$input = is_array( $input ) ? $input : array();
	$context = wpagent_pods_meta_values_context( $input['model_name'] ?? null, $input['object_type'] ?? null, $input['object_id'] ?? null );
	if ( is_wp_error( $context ) ) {
		return $context;
	}
	if ( ! wpagent_pods_meta_values_can_edit( $context ) ) {
		return new WP_Error( 'wpagent_pods_meta_values_forbidden', __( 'Du darfst die Pods-Werte dieses Objekts nicht ändern.', 'wp-agent-companion' ), array( 'status' => 403 ) );
	}
	foreach ( array( 'expected_model_hash', 'expected_field_hash', 'expected_object_hash' ) as $key ) {
		if ( ! is_string( $input[ $key ] ?? null ) || ! preg_match( '/^[a-f0-9]{64}$/D', $input[ $key ] ) ) {
			return new WP_Error( 'wpagent_pods_meta_values_hash', __( 'Die erwarteten Pods-Hashes sind ungültig.', 'wp-agent-companion' ), array( 'status' => 400 ) );
		}
	}
	$validated = wpagent_pods_meta_values_validate_input_values( $input['values'] ?? null, $context );
	if ( is_wp_error( $validated ) ) {
		return $validated;
	}
	$current = wpagent_pods_meta_values_state( $context );
	if ( is_wp_error( $current ) ) {
		return $current;
	}
	if ( ! wpagent_pods_meta_values_hash_matches( $current, $input ) ) {
		return wpagent_pods_meta_values_hash_conflict( $current );
	}
	$lock = wpagent_pods_meta_values_acquire_lock( $context['model_name'], $context['object_type'], (int) $context['object_id'] );
	if ( is_wp_error( $lock ) ) {
		return $lock;
	}
	$option = wpagent_pods_meta_values_lock_name( $context['model_name'], $context['object_type'], (int) $context['object_id'] );
	$started = false;
	try {
		$locked_context = wpagent_pods_meta_values_context( $context['model_name'], $context['object_type'], $context['object_id'] );
		if ( is_wp_error( $locked_context ) ) {
			return $locked_context;
		}
		if ( ! wpagent_pods_meta_values_can_edit( $locked_context ) ) {
			return new WP_Error( 'wpagent_pods_meta_values_forbidden', __( 'Die Berechtigung für dieses Pods-Objekt ist vor dem Schreiben entfallen.', 'wp-agent-companion' ), array( 'status' => 403 ) );
		}
		$locked_state = wpagent_pods_meta_values_state( $locked_context );
		if ( is_wp_error( $locked_state ) ) {
			return $locked_state;
		}
		if ( ! wpagent_pods_meta_values_hash_matches( $locked_state, $input ) ) {
			return wpagent_pods_meta_values_hash_conflict( $locked_state );
		}
		$validated = wpagent_pods_meta_values_validate_input_values( $input['values'] ?? null, $locked_context );
		if ( is_wp_error( $validated ) ) {
			return $validated;
		}
		$changed = array();
		foreach ( $validated as $name => $value ) {
			if ( ! wpagent_pods_meta_values_equal( $locked_context['entries'][ $name ], $locked_state['values'][ $name ], $value ) ) {
				$changed[ $name ] = $value;
			}
		}
		if ( array() === $changed ) {
			return $locked_state + array( 'verified_persistence' => true, 'changed' => false );
		}
		if ( ! wpagent_companion_refresh_option_lock( $option, $lock, WPAGENT_PODS_META_VALUES_LOCK_TTL ) || ! wpagent_companion_option_lock_is_owned( $option, $lock ) ) {
			return new WP_Error( 'wpagent_pods_meta_values_lock', __( 'Die Pods-Sperre ging vor dem nativen Schreiben verloren.', 'wp-agent-companion' ), array( 'status' => 409 ) );
		}
		$started = true;
		try {
			$saved = $locked_context['native']->save( $changed, null, (int) $locked_context['object_id'] );
		} catch ( Throwable $error ) {
			return wpagent_pods_meta_values_recovery_error( $locked_context, __( 'Der native Pods-Write wurde begonnen, aber nicht bestätigt. Es gibt keinen automatischen Rollback.', 'wp-agent-companion' ) );
		}
		if ( is_wp_error( $saved ) || ! is_numeric( $saved ) || (int) $saved !== (int) $locked_context['object_id'] ) {
			return wpagent_pods_meta_values_recovery_error( $locked_context, __( 'Der native Pods-Write wurde begonnen, lieferte aber keine bestätigte Objekt-ID. Manuelle Wiederherstellung ist erforderlich.', 'wp-agent-companion' ) );
		}
		if ( ! wpagent_companion_refresh_option_lock( $option, $lock, WPAGENT_PODS_META_VALUES_LOCK_TTL ) || ! wpagent_companion_option_lock_is_owned( $option, $lock ) ) {
			return wpagent_pods_meta_values_recovery_error( $locked_context, __( 'Der native Pods-Write wurde begonnen, aber die Sperre ging danach verloren. Es gibt keinen automatischen Rollback.', 'wp-agent-companion' ) );
		}
		$fresh_context = wpagent_pods_meta_values_context( $locked_context['model_name'], $locked_context['object_type'], $locked_context['object_id'] );
		if ( is_wp_error( $fresh_context ) ) {
			return wpagent_pods_meta_values_recovery_error( $locked_context, __( 'Der native Pods-Write wurde begonnen, aber das Ziel konnte nicht erneut gelesen werden. Manuelle Wiederherstellung ist erforderlich.', 'wp-agent-companion' ) );
		}
		if ( ! wpagent_pods_meta_values_can_edit( $fresh_context ) ) {
			return wpagent_pods_meta_values_recovery_error( $locked_context, __( 'Der native Pods-Write wurde begonnen, aber die Objektberechtigung konnte beim finalen Readback nicht bestätigt werden. Es gibt keinen automatischen Rollback.', 'wp-agent-companion' ) );
		}
		$after = wpagent_pods_meta_values_state( $fresh_context );
		if ( is_wp_error( $after ) || $after['model_hash'] !== $locked_state['model_hash'] || $after['field_hash'] !== $locked_state['field_hash'] ) {
			return wpagent_pods_meta_values_recovery_error( $locked_context, __( 'Der native Pods-Write wurde begonnen, aber Modell- oder Feld-Readback ist nicht stabil. Es gibt keinen automatischen Rollback.', 'wp-agent-companion' ), is_wp_error( $after ) ? array() : $after );
		}
		foreach ( $locked_state['values'] as $name => $before_value ) {
			$expected = array_key_exists( $name, $changed ) ? $changed[ $name ] : $before_value;
			if ( ! wpagent_pods_meta_values_equal( $fresh_context['entries'][ $name ], $after['values'][ $name ], $expected ) ) {
				return wpagent_pods_meta_values_recovery_error( $locked_context, __( 'Der native Pods-Write wurde begonnen, aber der vollständige Werte-Readback stimmt nicht überein. Es gibt keinen automatischen Rollback.', 'wp-agent-companion' ), $after );
			}
		}
		if ( ! wpagent_companion_refresh_option_lock( $option, $lock, WPAGENT_PODS_META_VALUES_LOCK_TTL ) || ! wpagent_companion_option_lock_is_owned( $option, $lock ) ) {
			return wpagent_pods_meta_values_recovery_error( $locked_context, __( 'Der native Pods-Write wurde begonnen, aber die Sperre ging vor dem Erfolg verloren. Es gibt keinen automatischen Rollback.', 'wp-agent-companion' ), $after );
		}
		return $after + array( 'verified_persistence' => true, 'changed' => true );
	} catch ( Throwable $error ) {
		if ( $started ) {
			return wpagent_pods_meta_values_recovery_error( $context, __( 'Der native Pods-Write wurde begonnen, aber nicht vollständig bestätigt. Manuelle Wiederherstellung ist erforderlich.', 'wp-agent-companion' ) );
		}
		return new WP_Error( 'wpagent_pods_meta_values_write', __( 'Die Pods-Werte konnten nicht geschrieben werden.', 'wp-agent-companion' ), array( 'status' => 500 ) );
	} finally {
		wpagent_pods_meta_values_release_lock( $context['model_name'], $context['object_type'], (int) $context['object_id'], $lock );
	}
}
