<?php
/** Update verified per-post OceanWP layout overrides. */

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

function wpagent_ability_update_oceanwp_post_design(): array {
	return array(
		'label'               => __( 'OceanWP-Beitragsdesign aktualisieren', 'wp-agent-companion' ),
		'description'         => __( 'Ändert individuelle OceanWP-Layoutvorgaben mit Konfliktschutz, Laufzeitprüfung, Read-back und fail-closed Recovery bei nicht verifizierter Persistierung.', 'wp-agent-companion' ),
		'category'            => 'wp-agent',
		'input_schema'        => array(
			'type'                 => 'object',
			'properties'           => array(
				'post_id'       => array( 'type' => 'integer', 'minimum' => 1 ),
				'expected_hash' => array( 'type' => 'string', 'pattern' => '^[a-f0-9]{64}$' ),
				'settings'      => wpagent_oceanwp_post_override_schema(),
			),
			'required'             => array( 'post_id', 'expected_hash', 'settings' ),
			'additionalProperties' => false,
		),
		'output_schema'       => array(
			'type'                 => 'object',
			'properties'           => array(
				'post_id'    => array( 'type' => 'integer' ),
				'post_type'  => array( 'type' => 'string' ),
				'overrides'  => wpagent_oceanwp_post_override_schema( true ),
				'state_hash' => array( 'type' => 'string', 'pattern' => '^[a-f0-9]{64}$' ),
				'verified'   => array( 'type' => 'boolean' ),
			),
			'required'             => array( 'post_id', 'post_type', 'overrides', 'state_hash', 'verified' ),
			'additionalProperties' => false,
		),
		'execute_callback'    => 'wpagent_exec_update_oceanwp_post_design',
		'permission_callback' => 'wpagent_perm_edit_posts',
		'meta'                => array( 'show_in_rest' => true, 'annotations' => array( 'readonly' => false, 'destructive' => false, 'idempotent' => false ) ),
	);
}

/** @return array{exists:bool,meta_id:int,raw:string}|WP_Error */
function wpagent_oceanwp_post_raw_meta_row( int $post_id, string $meta_key ) {
	global $wpdb;
	$rows = $wpdb->get_results( $wpdb->prepare(
		"SELECT meta_id, meta_value FROM {$wpdb->postmeta} WHERE post_id = %d AND meta_key = %s ORDER BY meta_id ASC",
		$post_id, $meta_key
	), ARRAY_A );
	if ( '' !== $wpdb->last_error || ! is_array( $rows ) || count( $rows ) > 1 ) {
		return new WP_Error( 'wpagent_oceanwp_post_conflict', __( 'Die OceanWP-Beitragsmetadaten sind nicht eindeutig oder nicht lesbar.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	if ( array() === $rows ) return array( 'exists' => false, 'meta_id' => 0, 'raw' => '' );
	$row = $rows[0];
	if ( ! is_numeric( $row['meta_id'] ?? null ) || ! is_string( $row['meta_value'] ?? null ) ) {
		return new WP_Error( 'wpagent_oceanwp_post_storage', __( 'Die OceanWP-Beitragsmetadaten sind nicht sicher lesbar.', 'wp-agent-companion' ), array( 'status' => 502 ) );
	}
	return array( 'exists' => true, 'meta_id' => (int) $row['meta_id'], 'raw' => $row['meta_value'] );
}

/** @return true|WP_Error */
function wpagent_oceanwp_post_write_checkpoint( int $post_id, string $lock ) {
	$target = wpagent_oceanwp_post_target( $post_id );
	if ( is_wp_error( $target ) ) return $target;
	if ( ! wpagent_oceanwp_runtime_ready() ) {
		return new WP_Error( 'wpagent_oceanwp_runtime_missing', __( 'Die aktive OceanWP-Version stellt den geprüften Beitragslayout-Weg nicht bereit.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	if ( ! wpagent_oceanwp_post_refresh_lock( $post_id, $lock ) || ! wpagent_companion_option_lock_is_owned( WPAGENT_OCEANWP_POST_LOCK_PREFIX . $post_id, $lock ) ) {
		return wpagent_oceanwp_post_lock_lost( false );
	}
	return true;
}

/** @param array{exists:bool,meta_id:int,raw:string} $before @return array{exists:bool,meta_id:int,raw:string}|WP_Error */
function wpagent_oceanwp_post_cas_meta( int $post_id, string $meta_key, array $before, string $value ) {
	global $wpdb;
	$remove = 'inherit' === $value;
	if ( ( $remove && ! $before['exists'] ) || ( ! $remove && $before['exists'] && $before['raw'] === $value ) ) return $before;
	if ( ! $before['exists'] ) {
		try {
			$meta_id = add_post_meta( $post_id, $meta_key, $value, true );
		} catch ( Throwable $error ) {
			return new WP_Error( 'wpagent_oceanwp_post_write_failed', __( 'Die OceanWP-Beitragsmetadaten konnten nicht atomar angelegt werden.', 'wp-agent-companion' ), array( 'status' => 500, 'write_started' => true ) );
		}
		wp_cache_delete( $post_id, 'post_meta' );
		$after = wpagent_oceanwp_post_raw_meta_row( $post_id, $meta_key );
		if ( ! is_int( $meta_id ) || $meta_id < 1 ) return new WP_Error( 'wpagent_oceanwp_post_conflict', __( 'Die OceanWP-Beitragsmetadaten wurden gleichzeitig angelegt.', 'wp-agent-companion' ), array( 'status' => 409, 'write_started' => false ) );
		return is_array( $after ) && $after['exists'] && $after['meta_id'] === $meta_id && $after['raw'] === $value
			? $after
			: new WP_Error( 'wpagent_oceanwp_post_write_failed', __( 'Die angelegten OceanWP-Beitragsmetadaten konnten nicht exakt bestätigt werden.', 'wp-agent-companion' ), array( 'status' => 500, 'write_started' => true ) );
	}
	try {
		if ( $remove ) {
			do_action( 'delete_post_meta', array( $before['meta_id'] ), $post_id, $meta_key, $before['raw'] );
			do_action( 'delete_postmeta', array( $before['meta_id'] ) );
			$changed = $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->postmeta} WHERE meta_id = %d AND post_id = %d AND meta_key = %s AND HEX(meta_value) = HEX(%s)", $before['meta_id'], $post_id, $meta_key, $before['raw'] ) );
		} else {
			do_action( 'update_post_meta', $before['meta_id'], $post_id, $meta_key, $value );
			do_action( 'update_postmeta', $before['meta_id'], $post_id, $meta_key, $value );
			$changed = $wpdb->query( $wpdb->prepare( "UPDATE {$wpdb->postmeta} SET meta_value = %s WHERE meta_id = %d AND post_id = %d AND meta_key = %s AND HEX(meta_value) = HEX(%s)", $value, $before['meta_id'], $post_id, $meta_key, $before['raw'] ) );
		}
	} catch ( Throwable $error ) {
		return new WP_Error( 'wpagent_oceanwp_post_write_failed', __( 'Die OceanWP-Beitragsmetadaten konnten nicht sicher vorbereitet werden.', 'wp-agent-companion' ), array( 'status' => 502, 'write_started' => false ) );
	}
	wp_cache_delete( $post_id, 'post_meta' );
	if ( 1 !== $changed ) return new WP_Error( false === $changed ? 'wpagent_oceanwp_post_write_failed' : 'wpagent_oceanwp_post_conflict', __( 'Die OceanWP-Beitragsmetadaten wurden gleichzeitig verändert und nicht überschrieben.', 'wp-agent-companion' ), array( 'status' => false === $changed ? 502 : 409, 'write_started' => false ) );
	try {
		if ( $remove ) {
			do_action( 'deleted_post_meta', array( $before['meta_id'] ), $post_id, $meta_key, $before['raw'] );
			do_action( 'deleted_postmeta', array( $before['meta_id'] ) );
		} else {
			do_action( 'updated_post_meta', $before['meta_id'], $post_id, $meta_key, $value );
			do_action( 'updated_postmeta', $before['meta_id'], $post_id, $meta_key, $value );
		}
	} catch ( Throwable $error ) {
		return new WP_Error( 'wpagent_oceanwp_post_write_failed', __( 'Die OceanWP-Beitragsmetadaten wurden gespeichert, aber nicht vollständig bestätigt.', 'wp-agent-companion' ), array( 'status' => 500, 'write_started' => true ) );
	}
	$after = wpagent_oceanwp_post_raw_meta_row( $post_id, $meta_key );
	if ( $remove ) return is_array( $after ) && ! $after['exists'] ? $after : new WP_Error( 'wpagent_oceanwp_post_write_failed', __( 'Die entfernten OceanWP-Beitragsmetadaten konnten nicht exakt bestätigt werden.', 'wp-agent-companion' ), array( 'status' => 500, 'write_started' => true ) );
	return is_array( $after ) && $after['exists'] && $after['meta_id'] === $before['meta_id'] && $after['raw'] === $value
		? $after
		: new WP_Error( 'wpagent_oceanwp_post_write_failed', __( 'Die OceanWP-Beitragsmetadaten konnten nicht exakt bestätigt werden.', 'wp-agent-companion' ), array( 'status' => 500, 'write_started' => true ) );
}

/** @return array<string,mixed>|WP_Error */
function wpagent_exec_update_oceanwp_post_design( $input ) {
	if ( ! wpagent_oceanwp_is_active() ) {
		return new WP_Error( 'wpagent_oceanwp_inactive', __( 'OceanWP oder ein OceanWP-Child-Theme ist nicht aktiv.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	if ( ! wpagent_oceanwp_runtime_ready() ) {
		return new WP_Error( 'wpagent_oceanwp_runtime_missing', __( 'Die aktive OceanWP-Version stellt den geprüften Beitragslayout-Weg nicht bereit. Unterstützt wird OceanWP ab Version 4.1.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	$input = is_array( $input ) ? $input : array();
	$post  = wpagent_oceanwp_post_target( absint( $input['post_id'] ?? 0 ) );
	if ( is_wp_error( $post ) ) {
		return $post;
	}
	$schema = wpagent_oceanwp_post_override_schema();
	$valid  = rest_validate_value_from_schema( $input['settings'] ?? null, $schema, 'settings' );
	if ( is_wp_error( $valid ) ) {
		return new WP_Error( 'wpagent_oceanwp_post_invalid_settings', __( 'Die OceanWP-Beitragseinstellungen sind ungültig.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$settings = rest_sanitize_value_from_schema( $input['settings'] ?? null, $schema, 'settings' );
	if ( is_wp_error( $settings ) || ! is_array( $settings ) || ! $settings ) {
		return new WP_Error( 'wpagent_oceanwp_post_invalid_settings', __( 'Die OceanWP-Beitragseinstellungen sind ungültig.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}

	$post_id = $post->ID;
	$lock    = wpagent_oceanwp_post_acquire_lock( $post_id );
	if ( is_wp_error( $lock ) ) {
		return $lock;
	}
	try {
		$post = wpagent_oceanwp_post_target( $post_id );
		if ( is_wp_error( $post ) ) {
			return $post;
		}
		if ( ! wpagent_oceanwp_runtime_ready() ) {
			return new WP_Error( 'wpagent_oceanwp_runtime_missing', __( 'Die aktive OceanWP-Version stellt den geprüften Beitragslayout-Weg nicht bereit. Unterstützt wird OceanWP ab Version 4.1.', 'wp-agent-companion' ), array( 'status' => 409 ) );
		}
		$previous = wpagent_oceanwp_post_snapshot( $post );
		if ( is_wp_error( $previous ) ) {
			return $previous;
		}
		$previous_hash = wpagent_oceanwp_post_state_hash( $previous );
		$expected_hash = strtolower( (string) ( $input['expected_hash'] ?? '' ) );
		if ( ! preg_match( '/^[a-f0-9]{64}$/', $expected_hash ) || ! hash_equals( $previous_hash, $expected_hash ) ) {
			return new WP_Error( 'wpagent_oceanwp_post_conflict', __( 'Die OceanWP-Beitragseinstellungen haben sich seit dem Lesen geändert. Lies sie neu und wiederhole den Vorgang.', 'wp-agent-companion' ), array( 'status' => 409, 'current_hash' => $previous_hash ) );
		}
		$expected = wpagent_oceanwp_post_expected_snapshot( $previous, $settings );
		$catalog  = wpagent_oceanwp_post_field_catalog();
		$raw_previous = array();
		foreach ( $catalog as $definition ) {
			$key = $definition['meta'];
			$row = wpagent_oceanwp_post_raw_meta_row( $post_id, $key );
			if ( is_wp_error( $row ) ) return $row;
			if ( $row['exists'] !== $previous['meta'][ $key ]['exists'] || ( $row['exists'] && $row['raw'] !== $previous['meta'][ $key ]['value'] ) ) {
				return new WP_Error( 'wpagent_oceanwp_post_conflict', __( 'Die rohe OceanWP-Beitragsmetadatenzeile änderte sich während der Vorbereitung.', 'wp-agent-companion' ), array( 'status' => 409 ) );
			}
			$raw_previous[ $key ] = $row;
		}
		if ( ! wpagent_oceanwp_post_refresh_lock( $post_id, $lock ) ) {
			return new WP_Error( 'wpagent_oceanwp_post_lock_lost', __( 'Die OceanWP-Beitragsänderung hat ihre exklusive Sperre verloren.', 'wp-agent-companion' ), array( 'status' => 409 ) );
		}
		$write_started = false;
		foreach ( $settings as $field => $value ) {
			$checkpoint = wpagent_oceanwp_post_write_checkpoint( $post_id, $lock );
			if ( is_wp_error( $checkpoint ) ) return $write_started ? wpagent_oceanwp_post_recovery_required( $post_id ) : $checkpoint;
			$key     = $catalog[ $field ]['meta'];
			$current = wpagent_oceanwp_post_raw_meta_row( $post_id, $key );
			if ( is_wp_error( $current ) || $current !== $raw_previous[ $key ] ) {
				return $write_started ? wpagent_oceanwp_post_recovery_required( $post_id ) : new WP_Error( 'wpagent_oceanwp_post_conflict', __( 'Die OceanWP-Beitragsmetadaten wurden gleichzeitig verändert und nicht überschrieben.', 'wp-agent-companion' ), array( 'status' => 409 ) );
			}
			$result = wpagent_oceanwp_post_cas_meta( $post_id, $key, $raw_previous[ $key ], $value );
			if ( is_wp_error( $result ) ) {
				$data = $result->get_error_data();
				return $write_started || ( is_array( $data ) && ! empty( $data['write_started'] ) ) ? wpagent_oceanwp_post_recovery_required( $post_id ) : $result;
			}
			$write_started = $write_started || $result !== $raw_previous[ $key ];
			$raw_previous[ $key ] = $result;
			$checkpoint = wpagent_oceanwp_post_write_checkpoint( $post_id, $lock );
			if ( is_wp_error( $checkpoint ) ) return $write_started ? wpagent_oceanwp_post_recovery_required( $post_id ) : $checkpoint;
		}

		$fresh = wpagent_oceanwp_post_snapshot( $post );
		if ( is_wp_error( $fresh ) || ! hash_equals( wpagent_oceanwp_post_state_hash( $expected ), wpagent_oceanwp_post_state_hash( $fresh ) ) ) {
			return wpagent_oceanwp_post_recovery_required( $post->ID );
		}
		if ( ! wpagent_oceanwp_post_refresh_lock( $post_id, $lock ) ) {
			return wpagent_oceanwp_post_recovery_required( $post->ID );
		}
		$overrides = wpagent_oceanwp_post_normalize( $fresh );
		$runtime   = wpagent_oceanwp_post_runtime_state( $post->ID );
		if ( is_wp_error( $runtime ) ) {
			return wpagent_oceanwp_post_recovery_required( $post->ID );
		}
		foreach ( $settings as $field => $value ) {
			if ( ! isset( $overrides[ $field ] ) || $overrides[ $field ] !== $value || ( 'inherit' !== $value && ( $runtime[ $field ] ?? null ) !== $value ) ) {
				return wpagent_oceanwp_post_recovery_required( $post->ID );
			}
		}
		if ( ! wpagent_oceanwp_post_refresh_lock( $post_id, $lock ) ) {
			return wpagent_oceanwp_post_recovery_required( $post_id );
		}
		$verified_post = wpagent_oceanwp_post_target( $post_id );
		if ( is_wp_error( $verified_post ) ) {
			return wpagent_oceanwp_post_recovery_required( $post_id );
		}
		return array(
			'post_id'    => (int) $verified_post->ID,
			'post_type'  => $verified_post->post_type,
			'overrides'  => $overrides,
			'state_hash' => wpagent_oceanwp_post_state_hash( $fresh ),
			'verified'   => true,
		);
	} finally {
		wpagent_oceanwp_post_release_lock( $post_id, $lock );
	}
}
