<?php
/** Verified native Spectra administration writes. */

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

function wpagent_ability_set_spectra_block_status(): array {
	return array(
		'label' => __( 'Spectra-Blockstatus setzen', 'wp-agent-companion' ),
		'description' => __( 'Aktiviert oder deaktiviert einen sichtbaren Spectra-Block über Spectras native Einstellung, konfliktgeschützt und mit selektivem Rollback.', 'wp-agent-companion' ),
		'category' => 'wp-agent',
		'input_schema' => array(
			'type' => 'object', 'properties' => array(
				'slug' => array( 'type' => 'string', 'pattern' => '^[a-z0-9][a-z0-9-]{0,127}$' ),
				'enabled' => array( 'type' => 'boolean' ),
				'expected_hash' => array( 'type' => 'string', 'pattern' => '^[a-f0-9]{64}$' ),
			), 'required' => array( 'slug', 'enabled', 'expected_hash' ), 'additionalProperties' => false,
		),
		'output_schema' => array(
			'type' => 'object', 'properties' => array(
				'block' => wpagent_spectra_block_schema(), 'verified' => array( 'type' => 'boolean' ),
				'previous_hash' => array( 'type' => 'string', 'pattern' => '^[a-f0-9]{64}$' ),
				'hash' => array( 'type' => 'string', 'pattern' => '^[a-f0-9]{64}$' ),
			), 'required' => array( 'block', 'verified', 'previous_hash', 'hash' ), 'additionalProperties' => false,
		),
		'execute_callback' => 'wpagent_exec_set_spectra_block_status', 'permission_callback' => 'wpagent_perm_manage_options',
		'meta' => array( 'show_in_rest' => true, 'annotations' => array( 'readonly' => false, 'destructive' => false, 'idempotent' => false ) ),
	);
}

function wpagent_ability_update_spectra_popup(): array {
	return array(
		'label' => __( 'Spectra-Popup aktualisieren', 'wp-agent-companion' ),
		'description' => __( 'Ändert sichere Popup-Einstellungen konfliktgeschützt und prüft Titel, Status, Typ, Aktivierung und Wiederholung nach dem Speichern.', 'wp-agent-companion' ),
		'category' => 'wp-agent',
		'input_schema' => array(
			'type' => 'object', 'properties' => array(
				'id' => array( 'type' => 'integer', 'minimum' => 1 ), 'expected_hash' => array( 'type' => 'string', 'pattern' => '^[a-f0-9]{64}$' ),
				'title' => array( 'type' => 'string', 'minLength' => 1, 'maxLength' => 200 ),
				'status' => array( 'type' => 'string', 'enum' => array( 'draft', 'pending', 'private', 'publish' ) ),
				'type' => array( 'type' => 'string', 'enum' => array( 'unset', 'popup', 'banner' ) ),
				'enabled' => array( 'type' => 'boolean' ), 'repetition' => array( 'type' => 'integer', 'minimum' => 1, 'maximum' => 100 ),
			), 'required' => array( 'id', 'expected_hash' ), 'additionalProperties' => false,
		),
		'output_schema' => array(
			'type' => 'object', 'properties' => array(
				'popup' => wpagent_spectra_popup_schema(), 'verified' => array( 'type' => 'boolean' ),
				'previous_hash' => array( 'type' => 'string', 'pattern' => '^[a-f0-9]{64}$' ),
			), 'required' => array( 'popup', 'verified', 'previous_hash' ), 'additionalProperties' => false,
		),
		'execute_callback' => 'wpagent_exec_update_spectra_popup', 'permission_callback' => 'wpagent_perm_manage_options',
		'meta' => array( 'show_in_rest' => true, 'annotations' => array( 'readonly' => false, 'destructive' => false, 'idempotent' => false ) ),
	);
}

function wpagent_ability_delete_spectra_popup(): array {
	return array(
		'label' => __( 'Spectra-Popup löschen', 'wp-agent-companion' ),
		'description' => __( 'Verschiebt ein Spectra-Popup nach ausdrücklicher Bestätigung und aktuellem Zustands-Hash reversibel in den Papierkorb. Endgültige Löschungen bleiben im WordPress-Admin manuell, weil WordPress keine atomare Compare-and-Delete-Operation gegen parallele Editor-Änderungen anbietet.', 'wp-agent-companion' ),
		'category' => 'wp-agent',
		'input_schema' => array(
			'type' => 'object', 'properties' => array(
				'id' => array( 'type' => 'integer', 'minimum' => 1 ), 'expected_hash' => array( 'type' => 'string', 'pattern' => '^[a-f0-9]{64}$' ),
				'confirm' => array( 'type' => 'boolean' ), 'force' => array( 'type' => 'boolean', 'default' => false ),
			), 'required' => array( 'id', 'expected_hash', 'confirm' ), 'additionalProperties' => false,
		),
		'output_schema' => array(
			'type' => 'object', 'properties' => array(
				'id' => array( 'type' => 'integer' ), 'trashed' => array( 'type' => 'boolean' ), 'deleted' => array( 'type' => 'boolean' ),
			), 'required' => array( 'id', 'trashed', 'deleted' ), 'additionalProperties' => false,
		),
		'execute_callback' => 'wpagent_exec_delete_spectra_popup', 'permission_callback' => 'wpagent_perm_manage_options',
		'meta' => array( 'show_in_rest' => true, 'annotations' => array( 'readonly' => false, 'destructive' => true, 'idempotent' => false ) ),
	);
}

/** @return string|WP_Error */
function wpagent_spectra_expected_hash( $value ) {
	if ( ! is_string( $value ) || ! preg_match( '/^[a-f0-9]{64}$/', $value ) ) {
		return new WP_Error( 'wpagent_spectra_hash', __( 'expected_hash muss ein SHA-256-Hash sein.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	return $value;
}

/** @param array{raw:string,autoload:string}|null $left @param array{raw:string,autoload:string}|null $right */
function wpagent_spectra_block_rows_equal( ?array $left, ?array $right ): bool {
	return null === $left || null === $right
		? null === $left && null === $right
		: $left['raw'] === $right['raw'] && $left['autoload'] === $right['autoload'];
}

/** @return array{raw:string,autoload:string}|WP_Error */
function wpagent_spectra_block_desired_option_row( array $value, ?array $before ) {
	$old = is_array( $before ) ? maybe_unserialize( $before['raw'] ) : false;
	try {
		$prepared = sanitize_option( '_uagb_blocks', $value );
		$prepared = apply_filters( 'pre_update_option__uagb_blocks', $prepared, $old, '_uagb_blocks' );
		$prepared = apply_filters( 'pre_update_option', $prepared, '_uagb_blocks', $old );
	} catch ( Throwable $error ) {
		return new WP_Error( 'wpagent_spectra_block_write', __( 'Spectras Blockstatus konnte nicht sicher vorbereitet werden.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	if ( ! is_array( $prepared ) || maybe_serialize( $prepared ) !== maybe_serialize( $value ) ) {
		return new WP_Error( 'wpagent_spectra_block_conflict', __( 'Ein Filter hat den geprüften Spectra-Blockstatus verändert.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	$raw = maybe_serialize( $prepared );
	return array(
		'raw'      => $raw,
		'autoload' => is_array( $before ) ? $before['autoload'] : wp_determine_option_autoload_value( '_uagb_blocks', $prepared, $raw, null ),
	);
}

/** @return true|WP_Error */
function wpagent_spectra_block_cas_option( array $value, ?array $before ) {
	global $wpdb;
	$next = wpagent_spectra_block_desired_option_row( $value, $before );
	if ( is_wp_error( $next ) ) return $next;
	if ( null === $before ) {
		try {
			$created = wpagent_companion_add_option_create_only( '_uagb_blocks', $value, '', null );
		} catch ( Throwable $error ) {
			return new WP_Error( 'wpagent_spectra_block_write', __( 'Der Spectra-Blockstatus konnte nicht atomar angelegt werden.', 'wp-agent-companion' ), array( 'status' => 502, 'mutation_started' => false ) );
		}
		if ( ! $created ) {
			return new WP_Error( 'wpagent_spectra_conflict', __( 'Der Spectra-Blockstatus wurde gleichzeitig angelegt.', 'wp-agent-companion' ), array( 'status' => 409, 'mutation_started' => false ) );
		}
		$row = wpagent_companion_read_option_row_direct( '_uagb_blocks' );
		return wpagent_spectra_block_rows_equal( $row, $next )
			? true
			: new WP_Error( 'wpagent_spectra_block_recovery_required', __( 'Der angelegte Spectra-Blockstatus konnte nicht exakt bestätigt werden.', 'wp-agent-companion' ), array( 'status' => 500, 'mutation_started' => true, 'recovery_required' => true ) );
	}
	try {
		do_action( 'update_option__uagb_blocks', maybe_unserialize( $before['raw'] ), $value, '_uagb_blocks' );
	} catch ( Throwable $error ) {
		return new WP_Error( 'wpagent_spectra_block_write', __( 'Der Spectra-Blockstatus konnte vor dem Speichern nicht bestätigt werden.', 'wp-agent-companion' ), array( 'status' => 502, 'mutation_started' => false ) );
	}
	$changed = $wpdb->query( $wpdb->prepare(
		"UPDATE {$wpdb->options} SET option_value = %s, autoload = %s WHERE option_name = %s AND HEX(option_value) = HEX(%s) AND HEX(autoload) = HEX(%s)",
		$next['raw'], $next['autoload'], '_uagb_blocks', $before['raw'], $before['autoload']
	) );
	wpagent_companion_forget_option_cache( '_uagb_blocks', in_array( $before['autoload'], wp_autoload_values_to_autoload(), true ) || in_array( $next['autoload'], wp_autoload_values_to_autoload(), true ) );
	if ( 1 !== $changed ) {
		return new WP_Error( false === $changed ? 'wpagent_spectra_block_write' : 'wpagent_spectra_conflict', __( 'Der Spectra-Blockstatus konnte nicht atomar gespeichert werden.', 'wp-agent-companion' ), array( 'status' => false === $changed ? 502 : 409, 'mutation_started' => false ) );
	}
	try {
		do_action( 'updated_option', '_uagb_blocks', maybe_unserialize( $before['raw'] ), $value );
	} catch ( Throwable $error ) {
		return new WP_Error( 'wpagent_spectra_block_recovery_required', __( 'Der Spectra-Blockstatus wurde gespeichert, aber nicht vollständig bestätigt.', 'wp-agent-companion' ), array( 'status' => 500, 'mutation_started' => true, 'recovery_required' => true ) );
	}
	$row = wpagent_companion_read_option_row_direct( '_uagb_blocks' );
	return wpagent_spectra_block_rows_equal( $row, $next )
		? true
		: new WP_Error( 'wpagent_spectra_block_recovery_required', __( 'Der Spectra-Blockstatus wurde verändert, aber nicht exakt bestätigt.', 'wp-agent-companion' ), array( 'status' => 500, 'mutation_started' => true, 'recovery_required' => true ) );
}

/** @return WP_Error */
function wpagent_spectra_block_recovery_required(): WP_Error {
	return new WP_Error( 'wpagent_spectra_block_recovery_required', __( 'Die Spectra-Blockänderung wurde begonnen, aber nicht vollständig verifiziert. Eine fremde oder unklare Änderung wurde nicht überschrieben. Lies den aktuellen Zustand neu und prüfe ihn im WordPress-Admin.', 'wp-agent-companion' ), array( 'status' => 500, 'recovery_required' => true ) );
}

/** @return array<string,mixed>|WP_Error */
function wpagent_exec_set_spectra_block_status( $input ) {
	$input = is_array( $input ) ? $input : array();
	$registry = wpagent_spectra_block_registry();
	if ( is_wp_error( $registry ) ) return $registry;
	$slug = is_string( $input['slug'] ?? null ) ? $input['slug'] : '';
	if ( ! preg_match( '/^[a-z0-9][a-z0-9-]{0,127}$/', $slug ) || ! isset( $registry[ $slug ] ) ) {
		return new WP_Error( 'wpagent_spectra_block', __( 'Der Spectra-Block ist unbekannt oder nicht einzeln schaltbar.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	if ( ! is_bool( $input['enabled'] ?? null ) ) {
		return new WP_Error( 'wpagent_spectra_enabled', __( 'enabled muss ein boolescher Wert sein.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$expected_hash = wpagent_spectra_expected_hash( $input['expected_hash'] ?? null );
	if ( is_wp_error( $expected_hash ) ) return $expected_hash;
	$lock = wpagent_site_editor_acquire_lock( 'spectra', 'blocks' );
	if ( is_wp_error( $lock ) ) return $lock;
	try {
		$blog_id = (int) get_current_blog_id();
		$before  = wpagent_spectra_block_option_snapshot();
		$row     = wpagent_companion_read_option_row_direct( '_uagb_blocks' );
		if ( is_wp_error( $before ) || '' !== $GLOBALS['wpdb']->last_error ) return is_wp_error( $before ) ? $before : new WP_Error( 'wpagent_spectra_block_storage', __( 'Der Spectra-Blockstatus konnte nicht direkt gelesen werden.', 'wp-agent-companion' ), array( 'status' => 500 ) );
		if ( ! hash_equals( $before['hash'], $expected_hash ) ) {
			return new WP_Error( 'wpagent_spectra_conflict', __( 'Spectras Blockstatus wurde seit dem Lesen verändert.', 'wp-agent-companion' ), array( 'status' => 409, 'current_hash' => $before['hash'] ) );
		}
		if ( ( $before['exists'] && ( ! is_array( $row ) || maybe_unserialize( $row['raw'] ) !== $before['value'] ) ) || ( ! $before['exists'] && null !== $row ) ) {
			return new WP_Error( 'wpagent_spectra_conflict', __( 'Der rohe Spectra-Blockstatus änderte sich während der Vorbereitung.', 'wp-agent-companion' ), array( 'status' => 409 ) );
		}
		$candidate          = $before['value'];
		$candidate[ $slug ] = $input['enabled'] ? $slug : 'disabled';
		if ( $candidate === $before['value'] ) {
			$fresh = wpagent_spectra_block_option_snapshot();
			$gate  = get_current_blog_id() === $blog_id && current_user_can( 'manage_options' ) && wpagent_site_editor_refresh_lock( 'spectra', 'blocks', $lock ) && wpagent_site_editor_lock_is_owned( 'spectra', 'blocks', $lock );
			if ( ! $gate || is_wp_error( $fresh ) || ! hash_equals( $before['hash'], $fresh['hash'] ) || ! wpagent_spectra_block_rows_equal( $row, wpagent_companion_read_option_row_direct( '_uagb_blocks' ) ) ) {
				return new WP_Error( 'wpagent_spectra_conflict', __( 'Der Spectra-Blockstatus oder die Berechtigung änderte sich vor der No-op-Bestätigung.', 'wp-agent-companion' ), array( 'status' => 409 ) );
			}
			return array( 'block' => wpagent_spectra_block_state( $registry[ $slug ], $before['value'] ), 'verified' => true, 'previous_hash' => $before['hash'], 'hash' => $before['hash'] );
		}
		$expected_row = wpagent_spectra_block_desired_option_row( $candidate, $row );
		if ( is_wp_error( $expected_row ) ) return $expected_row;
		$gate = get_current_blog_id() === $blog_id && current_user_can( 'manage_options' ) && wpagent_site_editor_refresh_lock( 'spectra', 'blocks', $lock ) && wpagent_site_editor_lock_is_owned( 'spectra', 'blocks', $lock );
		$current = $gate ? wpagent_companion_read_option_row_direct( '_uagb_blocks' ) : null;
		if ( ! $gate || ! wpagent_spectra_block_rows_equal( $row, $current ) ) {
			return new WP_Error( 'wpagent_spectra_conflict', __( 'Der Spectra-Blockstatus oder die Berechtigung änderten sich vor dem Speichern.', 'wp-agent-companion' ), array( 'status' => 409 ) );
		}
		$write = wpagent_spectra_block_cas_option( $candidate, $row );
		if ( is_wp_error( $write ) ) {
			$data = $write->get_error_data();
			return is_array( $data ) && ! empty( $data['mutation_started'] ) ? wpagent_spectra_block_recovery_required() : $write;
		}
		$after_row = wpagent_companion_read_option_row_direct( '_uagb_blocks' );
		$after = wpagent_spectra_block_option_snapshot();
		if ( get_current_blog_id() !== $blog_id || ! current_user_can( 'manage_options' ) || ! wpagent_site_editor_refresh_lock( 'spectra', 'blocks', $lock ) || ! wpagent_site_editor_lock_is_owned( 'spectra', 'blocks', $lock ) || ! is_array( $after ) || ! wpagent_spectra_block_rows_equal( $after_row, $expected_row ) || $after['value'] !== $candidate ) {
			return wpagent_spectra_block_recovery_required();
		}
		return array( 'block' => wpagent_spectra_block_state( $registry[ $slug ], $after['value'] ), 'verified' => true, 'previous_hash' => $before['hash'], 'hash' => $after['hash'] );
	} finally {
		wpagent_site_editor_release_lock( 'spectra', 'blocks', $lock );
	}
}

/** @return array<string,mixed>|WP_Error */
function wpagent_spectra_validate_popup_update( array $input, array $before ) {
	$fields = array( 'title', 'status', 'type', 'enabled', 'repetition' );
	if ( ! array_intersect( $fields, array_keys( $input ) ) ) {
		return new WP_Error( 'wpagent_spectra_no_fields', __( 'Mindestens ein Popup-Feld muss geändert werden.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$title = $before['title'];
	if ( array_key_exists( 'title', $input ) ) {
		$title = is_string( $input['title'] ) ? trim( $input['title'] ) : '';
		$length = function_exists( 'mb_strlen' ) ? mb_strlen( $title, 'UTF-8' ) : strlen( $title );
		if ( '' === $title || $length > 200 || sanitize_text_field( $title ) !== $title ) {
			return new WP_Error( 'wpagent_spectra_title', __( 'title muss reiner Text mit 1-200 Zeichen sein.', 'wp-agent-companion' ), array( 'status' => 400 ) );
		}
	}
	$status = $input['status'] ?? $before['status'];
	if ( ! in_array( $status, array( 'draft', 'pending', 'private', 'publish' ), true ) ) {
		return new WP_Error( 'wpagent_spectra_status', __( 'Ungültiger Popup-Status.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$type = $input['type'] ?? $before['type'];
	if ( ! in_array( $type, array( 'unset', 'popup', 'banner' ), true ) ) {
		return new WP_Error( 'wpagent_spectra_type', __( 'Ungültiger Popup-Typ.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$enabled = $input['enabled'] ?? $before['enabled'];
	if ( ! is_bool( $enabled ) ) {
		return new WP_Error( 'wpagent_spectra_enabled', __( 'enabled muss ein boolescher Wert sein.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$repetition = $input['repetition'] ?? $before['repetition'];
	if ( ! is_int( $repetition ) || $repetition < 1 || $repetition > 100 ) {
		return new WP_Error( 'wpagent_spectra_repetition', __( 'repetition muss eine ganze Zahl zwischen 1 und 100 sein.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	if ( $enabled && ( 'publish' !== $status || 'unset' === $type || empty( $before['has_popup_wrapper'] ) ) ) {
		return new WP_Error( 'wpagent_spectra_popup_incomplete', __( 'Nur ein veröffentlichtes Popup oder Banner mit Spectras Popup-Builder-Block darf aktiviert werden.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	return compact( 'title', 'status', 'type', 'enabled', 'repetition' );
}

/** @return array<int,string> */
function wpagent_spectra_popup_post_columns(): array {
	return array(
		'ID', 'post_author', 'post_date', 'post_date_gmt', 'post_content', 'post_title', 'post_excerpt', 'post_status',
		'comment_status', 'ping_status', 'post_password', 'post_name', 'to_ping', 'pinged', 'post_modified',
		'post_modified_gmt', 'post_content_filtered', 'post_parent', 'guid', 'menu_order', 'post_type', 'post_mime_type', 'comment_count',
	);
}

/** @return array{exists:bool,meta_id:int,raw:string}|WP_Error */
function wpagent_spectra_popup_raw_meta_snapshot( int $post_id, string $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, $key
	), ARRAY_A );
	if ( '' !== $wpdb->last_error ) {
		return new WP_Error( 'wpagent_spectra_popup_storage', __( 'Die Spectra-Popup-Metadaten konnten nicht direkt gelesen werden.', 'wp-agent-companion' ), array( 'status' => 500 ) );
	}
	if ( ! is_array( $rows ) || count( $rows ) > 1 ) {
		return new WP_Error( 'wpagent_spectra_conflict', __( 'Die Spectra-Popup-Metadaten sind nicht eindeutig und werden nicht verändert.', '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_spectra_popup_storage', __( 'Die Spectra-Popup-Metadaten konnten nicht vollständig gelesen werden.', 'wp-agent-companion' ), array( 'status' => 500 ) );
	}
	return array( 'exists' => true, 'meta_id' => (int) $row['meta_id'], 'raw' => $row['meta_value'] );
}

/** @return array{post:array<string,string>,meta:array<string,array{exists:bool,meta_id:int,raw:string}>}|WP_Error */
function wpagent_spectra_popup_raw_snapshot( int $post_id ) {
	global $wpdb;
	$columns = wpagent_spectra_popup_post_columns();
	$row = $wpdb->get_row( $wpdb->prepare(
		"SELECT " . implode( ', ', $columns ) . " FROM {$wpdb->posts} WHERE ID = %d",
		$post_id
	), ARRAY_A );
	if ( '' !== $wpdb->last_error ) {
		return new WP_Error( 'wpagent_spectra_popup_storage', __( 'Das Spectra-Popup konnte nicht direkt gelesen werden.', 'wp-agent-companion' ), array( 'status' => 500 ) );
	}
	if ( ! is_array( $row ) || 'spectra-popup' !== ( $row['post_type'] ?? null ) ) {
		return new WP_Error( 'wpagent_spectra_popup_not_found', __( 'Spectra-Popup nicht gefunden.', 'wp-agent-companion' ), array( 'status' => 404 ) );
	}
	$raw = array();
	foreach ( $columns as $column ) {
		if ( ! is_scalar( $row[ $column ] ?? null ) ) {
			return new WP_Error( 'wpagent_spectra_popup_storage', __( 'Das Spectra-Popup konnte nicht vollständig gelesen werden.', 'wp-agent-companion' ), array( 'status' => 500 ) );
		}
		$raw[ $column ] = (string) $row[ $column ];
	}
	$meta = array();
	foreach ( array( 'spectra-popup-type', 'spectra-popup-enabled', 'spectra-popup-repetition' ) as $key ) {
		$snapshot = wpagent_spectra_popup_raw_meta_snapshot( $post_id, $key );
		if ( is_wp_error( $snapshot ) ) return $snapshot;
		$meta[ $key ] = $snapshot;
	}
	return array( 'post' => $raw, 'meta' => $meta );
}

/** @param array{post:array<string,string>,meta:array<string,array{exists:bool,meta_id:int,raw:string}>} $left @param array{post:array<string,string>,meta:array<string,array{exists:bool,meta_id:int,raw:string}>} $right */
function wpagent_spectra_popup_raw_snapshots_equal( array $left, array $right ): bool {
	return $left['post'] === $right['post'] && $left['meta'] === $right['meta'];
}

/** @return bool */
function wpagent_spectra_popup_update_gate( int $post_id, string $token, int $blog_id ): bool {
	return get_current_blog_id() === $blog_id
		&& current_user_can( 'manage_options' )
		&& current_user_can( 'edit_post', $post_id )
		&& wpagent_site_editor_refresh_lock( 'spectra-popup', (string) $post_id, $token )
		&& wpagent_site_editor_lock_is_owned( 'spectra-popup', (string) $post_id, $token )
		&& ! is_wp_error( wpagent_spectra_require_available() );
}

/** @param array<string,string> $before @param array<string,string> $after @return true|WP_Error */
function wpagent_spectra_popup_cas_post( int $post_id, array $before, array $after ) {
	global $wpdb;
	$changed = array();
	foreach ( array( 'post_title', 'post_status', 'post_content', 'post_modified', 'post_modified_gmt' ) as $column ) {
		if ( $before[ $column ] !== $after[ $column ] ) $changed[ $column ] = $after[ $column ];
	}
	if ( array() === $changed ) return true;
	try {
		do_action( 'pre_post_update', $post_id, $after );
	} catch ( Throwable $error ) {
		return new WP_Error( 'wpagent_spectra_popup_write', __( 'Das Spectra-Popup konnte vor dem Speichern nicht bestätigt werden.', 'wp-agent-companion' ), array( 'status' => 502, 'mutation_started' => false ) );
	}
	$set  = array();
	$args = array();
	foreach ( $changed as $column => $value ) {
		$set[]  = "{$column} = %s";
		$args[] = $value;
	}
	$where    = array( 'ID = %d' );
	$args[]   = $post_id;
	foreach ( wpagent_spectra_popup_post_columns() as $column ) {
		if ( 'ID' === $column ) continue;
		$where[] = "HEX({$column}) = HEX(%s)";
		$args[]  = $before[ $column ];
	}
	$result = $wpdb->query( $wpdb->prepare( "UPDATE {$wpdb->posts} SET " . implode( ', ', $set ) . ' WHERE ' . implode( ' AND ', $where ), ...$args ) );
	clean_post_cache( $post_id );
	if ( 1 !== $result ) {
		return new WP_Error( false === $result ? 'wpagent_spectra_popup_write' : 'wpagent_spectra_conflict', __( 'Das Spectra-Popup wurde gleichzeitig verändert und nicht überschrieben.', 'wp-agent-companion' ), array( 'status' => false === $result ? 502 : 409, 'mutation_started' => false ) );
	}
	return true;
}

/** @return string */
function wpagent_spectra_popup_meta_raw_value( $value ): string {
	return (string) maybe_serialize( $value );
}

/** @param array{exists:bool,meta_id:int,raw:string} $before @return true|WP_Error */
function wpagent_spectra_popup_cas_meta( int $post_id, string $key, array $before, string $desired_raw ) {
	global $wpdb;
	if ( $before['exists'] && $before['raw'] === $desired_raw ) return true;
	if ( ! $before['exists'] ) {
		try {
			$created = add_post_meta( $post_id, $key, $desired_raw, true );
		} catch ( Throwable $error ) {
			return new WP_Error( 'wpagent_spectra_popup_write', __( 'Die Spectra-Popup-Metadaten konnten nicht atomar angelegt werden.', 'wp-agent-companion' ), array( 'status' => 502, 'mutation_started' => false ) );
		}
		wp_cache_delete( $post_id, 'post_meta' );
		$after = wpagent_spectra_popup_raw_meta_snapshot( $post_id, $key );
		if ( ! $created ) {
			return new WP_Error( 'wpagent_spectra_conflict', __( 'Die Spectra-Popup-Metadaten wurden gleichzeitig angelegt.', 'wp-agent-companion' ), array( 'status' => 409, 'mutation_started' => false ) );
		}
		return is_array( $after ) && $after['exists'] && $after['raw'] === $desired_raw
			? true
			: new WP_Error( 'wpagent_spectra_popup_recovery_required', __( 'Die angelegten Spectra-Popup-Metadaten konnten nicht exakt bestätigt werden.', 'wp-agent-companion' ), array( 'status' => 500, 'mutation_started' => true, 'recovery_required' => true ) );
	}
	try {
		do_action( 'update_post_meta', $before['meta_id'], $post_id, $key, $desired_raw );
	} catch ( Throwable $error ) {
		return new WP_Error( 'wpagent_spectra_popup_write', __( 'Die Spectra-Popup-Metadaten konnten vor dem Speichern nicht bestätigt werden.', 'wp-agent-companion' ), array( 'status' => 502, 'mutation_started' => false ) );
	}
	$result = $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)",
		$desired_raw, $before['meta_id'], $post_id, $key, $before['raw']
	) );
	wp_cache_delete( $post_id, 'post_meta' );
	if ( 1 !== $result ) {
		return new WP_Error( false === $result ? 'wpagent_spectra_popup_write' : 'wpagent_spectra_conflict', __( 'Die Spectra-Popup-Metadaten wurden gleichzeitig verändert und nicht überschrieben.', 'wp-agent-companion' ), array( 'status' => false === $result ? 502 : 409, 'mutation_started' => false ) );
	}
	try {
		do_action( 'updated_post_meta', $before['meta_id'], $post_id, $key, $desired_raw );
	} catch ( Throwable $error ) {
		return new WP_Error( 'wpagent_spectra_popup_recovery_required', __( 'Die Spectra-Popup-Metadaten wurden gespeichert, aber nicht vollständig bestätigt.', 'wp-agent-companion' ), array( 'status' => 500, 'mutation_started' => true, 'recovery_required' => true ) );
	}
	$after = wpagent_spectra_popup_raw_meta_snapshot( $post_id, $key );
	return is_array( $after ) && $after['exists'] && $after['meta_id'] === $before['meta_id'] && $after['raw'] === $desired_raw
		? true
		: new WP_Error( 'wpagent_spectra_popup_recovery_required', __( 'Die Spectra-Popup-Metadaten wurden verändert, aber nicht exakt bestätigt.', 'wp-agent-companion' ), array( 'status' => 500, 'mutation_started' => true, 'recovery_required' => true ) );
}

/** @return WP_Error */
function wpagent_spectra_popup_recovery_required(): WP_Error {
	return new WP_Error( 'wpagent_spectra_popup_recovery_required', __( 'Die Spectra-Popup-Änderung wurde begonnen, aber nicht vollständig verifiziert. Eine fremde oder unklare Änderung wurde nicht überschrieben. Lies den aktuellen Zustand neu und prüfe ihn im WordPress-Admin.', 'wp-agent-companion' ), array( 'status' => 500, 'recovery_required' => true ) );
}

/** @param array<string,mixed> $before @param array<string,mixed> $after */
function wpagent_spectra_popup_native_trash_slug_matches( WP_Post $before_post, WP_Post $after_post ): bool {
	if ( $before_post->post_name === $after_post->post_name ) return true;
	$trash_slug = str_ends_with( $before_post->post_name, '__trashed' )
		? $before_post->post_name
		: _truncate_post_slug( $before_post->post_name, 191 ) . '__trashed';
	$expected_slug = wp_unique_post_slug( $trash_slug, $before_post->ID, 'trash', $before_post->post_type, (int) $before_post->post_parent );
	return $after_post->post_name === $expected_slug
		&& get_post_meta( $after_post->ID, '_wp_desired_post_slug', true ) === $before_post->post_name;
}

/** @param array<string,mixed> $before @param array<string,mixed> $after */
function wpagent_spectra_popup_trash_readback_matches( WP_Post $before_post, array $before, WP_Post $after_post, array $after ): bool {
	return $before_post->ID === $after_post->ID
		&& 'spectra-popup' === $after_post->post_type
		&& 'trash' === $after_post->post_status
		&& $before_post->post_title === $after_post->post_title
		&& wpagent_spectra_popup_native_trash_slug_matches( $before_post, $after_post )
		&& $before_post->post_content === $after_post->post_content
		&& $before['type'] === $after['type']
		&& $before['enabled'] === $after['enabled']
		&& $before['repetition'] === $after['repetition'];
}

/**
 * Revalidates every mutable deletion precondition immediately before trashing.
 *
 * @return array{post:WP_Post,state:array<string,mixed>}|WP_Error
 */
function wpagent_spectra_popup_pretrash_gate( int $post_id, string $expected_hash, string $token ) {
	$available = wpagent_spectra_require_available();
	if ( is_wp_error( $available ) ) return $available;
	if ( ! current_user_can( 'manage_options' ) || ! current_user_can( 'delete_post', $post_id ) ) {
		return new WP_Error( 'wpagent_spectra_popup_forbidden', __( 'Keine Berechtigung, dieses Spectra-Popup zu löschen.', 'wp-agent-companion' ), array( 'status' => 403 ) );
	}
	if ( ! wpagent_site_editor_refresh_lock( 'spectra-popup', (string) $post_id, $token ) || ! wpagent_site_editor_lock_is_owned( 'spectra-popup', (string) $post_id, $token ) ) {
		return new WP_Error( 'wpagent_spectra_conflict', __( 'Die WPAgently-Sperre für dieses Spectra-Popup ging vor dem Papierkorbvorgang verloren.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	clean_post_cache( $post_id );
	wp_cache_delete( $post_id, 'post_meta' );
	$fresh_post = wpagent_spectra_get_popup( $post_id );
	if ( is_wp_error( $fresh_post ) ) return $fresh_post;
	$fresh_state = wpagent_spectra_popup_state( $fresh_post, false );
	if ( is_wp_error( $fresh_state ) ) return $fresh_state;
	if ( ! hash_equals( $expected_hash, $fresh_state['hash'] ) ) {
		return new WP_Error( 'wpagent_spectra_conflict', __( 'Das Spectra-Popup wurde unmittelbar vor dem Papierkorbvorgang verändert.', 'wp-agent-companion' ), array( 'status' => 409, 'current_hash' => $fresh_state['hash'] ) );
	}
	if ( ! current_user_can( 'manage_options' ) || ! current_user_can( 'delete_post', $post_id ) ) {
		return new WP_Error( 'wpagent_spectra_popup_forbidden', __( 'Die Berechtigung für dieses Spectra-Popup änderte sich vor dem Papierkorbvorgang.', 'wp-agent-companion' ), array( 'status' => 403 ) );
	}
	if ( ! wpagent_site_editor_lock_is_owned( 'spectra-popup', (string) $post_id, $token ) ) {
		return new WP_Error( 'wpagent_spectra_conflict', __( 'Die WPAgently-Sperre für dieses Spectra-Popup ging vor dem Papierkorbvorgang verloren.', 'wp-agent-companion' ), array( 'status' => 409, 'current_hash' => $fresh_state['hash'] ) );
	}
	return array( 'post' => $fresh_post, 'state' => $fresh_state );
}

/** @return array<string,mixed>|WP_Error */
function wpagent_exec_update_spectra_popup( $input ) {
	$available = wpagent_spectra_require_available();
	if ( is_wp_error( $available ) ) return $available;
	$input = is_array( $input ) ? $input : array();
	$post_id = absint( $input['id'] ?? 0 );
	$expected_hash = wpagent_spectra_expected_hash( $input['expected_hash'] ?? null );
	if ( is_wp_error( $expected_hash ) ) return $expected_hash;
	if ( ! current_user_can( 'edit_post', $post_id ) ) {
		return new WP_Error( 'wpagent_spectra_popup_forbidden', __( 'Keine Berechtigung, dieses Spectra-Popup zu aktualisieren.', 'wp-agent-companion' ), array( 'status' => 403 ) );
	}
	$lock = wpagent_site_editor_acquire_lock( 'spectra-popup', (string) $post_id );
	if ( is_wp_error( $lock ) ) return $lock;
	try {
		$blog_id = (int) get_current_blog_id();
		clean_post_cache( $post_id );
		wp_cache_delete( $post_id, 'post_meta' );
		$post = wpagent_spectra_get_popup( $post_id );
		if ( is_wp_error( $post ) ) {
			return new WP_Error( 'wpagent_spectra_popup_forbidden', __( 'Keine Berechtigung, dieses Spectra-Popup zu aktualisieren.', 'wp-agent-companion' ), array( 'status' => 403 ) );
		}
		if ( 'trash' === $post->post_status ) return new WP_Error( 'wpagent_spectra_popup_trashed', __( 'Ein Popup im Papierkorb kann nicht aktualisiert werden.', 'wp-agent-companion' ), array( 'status' => 409 ) );
		$before = wpagent_spectra_popup_state( $post, true );
		if ( is_wp_error( $before ) ) return $before;
		if ( ! hash_equals( $before['hash'], $expected_hash ) ) return new WP_Error( 'wpagent_spectra_conflict', __( 'Das Spectra-Popup wurde seit dem Lesen verändert.', 'wp-agent-companion' ), array( 'status' => 409, 'current_hash' => $before['hash'] ) );
		$raw_before = wpagent_spectra_popup_raw_snapshot( $post_id );
		if ( is_wp_error( $raw_before ) ) return $raw_before;
		$desired = wpagent_spectra_validate_popup_update( $input, $before );
		if ( is_wp_error( $desired ) ) return $desired;
		$desired_content = $before['content'];
		if ( array_key_exists( 'type', $input ) && 'unset' !== $desired['type'] && $desired['type'] !== $before['type'] ) {
			$desired_content = wpagent_spectra_retarget_popup_content( $before['content'], $desired['type'] );
			if ( is_wp_error( $desired_content ) ) return $desired_content;
		}
		$expected_raw = $raw_before;
		$post_target  = $raw_before['post'];
		$post_target['post_title']   = $desired['title'];
		$post_target['post_status']  = $desired['status'];
		$post_target['post_content'] = $desired_content;
		if ( $post_target['post_title'] !== $raw_before['post']['post_title'] || $post_target['post_status'] !== $raw_before['post']['post_status'] || $post_target['post_content'] !== $raw_before['post']['post_content'] ) {
			$post_target['post_modified']     = current_time( 'mysql' );
			$post_target['post_modified_gmt'] = current_time( 'mysql', true );
		}
		$operations = array();
		if ( array_key_exists( 'enabled', $input ) && ! $desired['enabled'] ) $operations[] = array( 'meta' => 'spectra-popup-enabled', 'value' => wpagent_spectra_popup_meta_raw_value( false ) );
		if ( $post_target !== $raw_before['post'] ) $operations[] = array( 'post' => $post_target );
		if ( array_key_exists( 'type', $input ) ) $operations[] = array( 'meta' => 'spectra-popup-type', 'value' => wpagent_spectra_popup_meta_raw_value( $desired['type'] ) );
		if ( array_key_exists( 'repetition', $input ) ) $operations[] = array( 'meta' => 'spectra-popup-repetition', 'value' => wpagent_spectra_popup_meta_raw_value( $desired['repetition'] ) );
		if ( array_key_exists( 'enabled', $input ) && $desired['enabled'] ) $operations[] = array( 'meta' => 'spectra-popup-enabled', 'value' => wpagent_spectra_popup_meta_raw_value( true ) );
		if ( array() === $operations ) {
			$current_raw = wpagent_spectra_popup_raw_snapshot( $post_id );
			clean_post_cache( $post_id );
			wp_cache_delete( $post_id, 'post_meta' );
			$fresh_post = wpagent_spectra_get_popup( $post_id );
			$fresh_state = is_wp_error( $fresh_post ) ? $fresh_post : wpagent_spectra_popup_state( $fresh_post, true );
			if ( ! wpagent_spectra_popup_update_gate( $post_id, $lock, $blog_id ) || is_wp_error( $current_raw ) || is_wp_error( $fresh_state ) || ! wpagent_spectra_popup_raw_snapshots_equal( $raw_before, $current_raw ) || ! hash_equals( $before['hash'], $fresh_state['hash'] ) ) {
				return new WP_Error( 'wpagent_spectra_conflict', __( 'Das Spectra-Popup oder die Berechtigung änderte sich vor der No-op-Bestätigung.', 'wp-agent-companion' ), array( 'status' => 409 ) );
			}
			return array( 'popup' => $fresh_state, 'verified' => true, 'previous_hash' => $before['hash'] );
		}
		$mutation_started = false;
		foreach ( $operations as $operation ) {
			$current_raw = wpagent_spectra_popup_raw_snapshot( $post_id );
			if ( ! wpagent_spectra_popup_update_gate( $post_id, $lock, $blog_id ) || is_wp_error( $current_raw ) || ! wpagent_spectra_popup_raw_snapshots_equal( $expected_raw, $current_raw ) ) {
				return $mutation_started ? wpagent_spectra_popup_recovery_required() : new WP_Error( 'wpagent_spectra_conflict', __( 'Das Spectra-Popup oder die Berechtigung änderte sich vor dem Speichern.', 'wp-agent-companion' ), array( 'status' => 409 ) );
			}
			if ( isset( $operation['post'] ) ) {
				$result = wpagent_spectra_popup_cas_post( $post_id, $expected_raw['post'], $operation['post'] );
				if ( ! is_wp_error( $result ) ) $expected_raw['post'] = $operation['post'];
			} else {
				$key    = $operation['meta'];
				$result = wpagent_spectra_popup_cas_meta( $post_id, $key, $expected_raw['meta'][ $key ], $operation['value'] );
				if ( ! is_wp_error( $result ) ) {
					$after_meta = wpagent_spectra_popup_raw_meta_snapshot( $post_id, $key );
					if ( is_wp_error( $after_meta ) ) return wpagent_spectra_popup_recovery_required();
					$expected_raw['meta'][ $key ] = $after_meta;
				}
			}
			if ( is_wp_error( $result ) ) {
				$data = $result->get_error_data();
				return $mutation_started || ( is_array( $data ) && ! empty( $data['mutation_started'] ) ) ? wpagent_spectra_popup_recovery_required() : $result;
			}
			$mutation_started = true;
		}
		$current_raw = wpagent_spectra_popup_raw_snapshot( $post_id );
		clean_post_cache( $post_id );
		wp_cache_delete( $post_id, 'post_meta' );
		$fresh = wpagent_spectra_get_popup( $post_id );
		$after = is_wp_error( $fresh ) ? $fresh : wpagent_spectra_popup_state( $fresh, true );
		$wrapper = is_array( $after ) && 'unset' !== $desired['type'] ? wpagent_spectra_popup_native_contract( $after['content'] ) : null;
		$verified = wpagent_spectra_popup_update_gate( $post_id, $lock, $blog_id ) && is_array( $current_raw ) && wpagent_spectra_popup_raw_snapshots_equal( $expected_raw, $current_raw ) && is_array( $after ) && $after['title'] === $desired['title'] && $after['status'] === $desired['status']
			&& $after['type'] === $desired['type'] && $after['enabled'] === $desired['enabled'] && $after['repetition'] === $desired['repetition']
			&& $after['content'] === $desired_content && $after['has_popup_wrapper'] === $before['has_popup_wrapper']
			&& ( 'unset' === $desired['type'] || ( is_array( $wrapper ) && $wrapper['type'] === $desired['type'] ) );
		if ( ! $verified ) {
			return wpagent_spectra_popup_recovery_required();
		}
		return array( 'popup' => $after, 'verified' => true, 'previous_hash' => $before['hash'] );
	} finally {
		wpagent_site_editor_release_lock( 'spectra-popup', (string) $post_id, $lock );
	}
}

/** @return array<string,mixed>|WP_Error */
function wpagent_exec_delete_spectra_popup( $input ) {
	$available = wpagent_spectra_require_available();
	if ( is_wp_error( $available ) ) return $available;
	$input = is_array( $input ) ? $input : array();
	$confirm = wpagent_spectra_boolean( $input['confirm'] ?? null, 'confirm' );
	if ( is_wp_error( $confirm ) ) return $confirm;
	if ( ! $confirm ) return new WP_Error( 'wpagent_spectra_confirmation', __( 'confirm=true ist zum Löschen erforderlich.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	$force = array_key_exists( 'force', $input ) ? wpagent_spectra_boolean( $input['force'], 'force' ) : false;
	if ( is_wp_error( $force ) ) return $force;
	$post_id = absint( $input['id'] ?? 0 );
	$expected_hash = wpagent_spectra_expected_hash( $input['expected_hash'] ?? null );
	if ( is_wp_error( $expected_hash ) ) return $expected_hash;
	if ( ! current_user_can( 'delete_post', $post_id ) ) {
		return new WP_Error( 'wpagent_spectra_popup_forbidden', __( 'Keine Berechtigung, dieses Spectra-Popup zu löschen.', 'wp-agent-companion' ), array( 'status' => 403 ) );
	}
	$lock = wpagent_site_editor_acquire_lock( 'spectra-popup', (string) $post_id );
	if ( is_wp_error( $lock ) ) return $lock;
	try {
		$post = wpagent_spectra_get_popup( $post_id );
		if ( is_wp_error( $post ) ) {
			return new WP_Error( 'wpagent_spectra_popup_forbidden', __( 'Keine Berechtigung, dieses Spectra-Popup zu löschen.', 'wp-agent-companion' ), array( 'status' => 403 ) );
		}
		$before = wpagent_spectra_popup_state( $post, false );
		if ( is_wp_error( $before ) ) return $before;
		if ( ! hash_equals( $before['hash'], $expected_hash ) ) return new WP_Error( 'wpagent_spectra_conflict', __( 'Das Spectra-Popup wurde seit dem Lesen verändert.', 'wp-agent-companion' ), array( 'status' => 409, 'current_hash' => $before['hash'] ) );
		if ( $force ) {
			return new WP_Error( 'wpagent_spectra_permanent_delete_unavailable', __( 'Endgültige Spectra-Popup-Löschungen bleiben im WordPress-Admin manuell, weil WordPress keine atomare Compare-and-Delete-Operation gegen parallele Editor-Änderungen anbietet.', 'wp-agent-companion' ), array( 'status' => 409, 'manual_action_required' => true, 'current_hash' => $before['hash'] ) );
		}
		if ( defined( 'EMPTY_TRASH_DAYS' ) && 0 === (int) EMPTY_TRASH_DAYS ) {
			return new WP_Error( 'wpagent_spectra_trash_disabled', __( 'Der WordPress-Papierkorb ist deaktiviert. WPAgently führt deshalb keine potenziell endgültige Popup-Löschung aus.', 'wp-agent-companion' ), array( 'status' => 409, 'manual_action_required' => true ) );
		}
		if ( 'trash' !== $post->post_status ) {
			$pretrash = wpagent_spectra_popup_pretrash_gate( $post_id, $expected_hash, $lock );
			if ( is_wp_error( $pretrash ) ) return $pretrash;
			$post   = $pretrash['post'];
			$before = $pretrash['state'];
			if ( ! wp_trash_post( $post_id ) ) return new WP_Error( 'wpagent_spectra_trash_failed', __( 'Das Spectra-Popup konnte nicht in den Papierkorb verschoben werden.', 'wp-agent-companion' ), array( 'status' => 500 ) );
		}
		if ( ! current_user_can( 'delete_post', $post_id ) || ! wpagent_site_editor_lock_is_owned( 'spectra-popup', (string) $post_id, $lock ) ) {
			return new WP_Error( 'wpagent_spectra_trash_recovery_required', __( 'Die Berechtigung oder die WPAgently-Sperre änderte sich während des Papierkorbvorgangs. Das Popup wurde nicht zurückgerollt. Prüfe den aktuellen Zustand im WordPress-Admin.', 'wp-agent-companion' ), array( 'status' => 500, 'recovery_required' => true ) );
		}
		$fresh = get_post( $post_id );
		$after = $fresh instanceof WP_Post ? wpagent_spectra_popup_state( $fresh, false ) : new WP_Error( 'wpagent_spectra_popup_not_found' );
		if ( ! $fresh instanceof WP_Post || is_wp_error( $after ) || ! wpagent_spectra_popup_trash_readback_matches( $post, $before, $fresh, $after ) ) {
			return new WP_Error( 'wpagent_spectra_trash_recovery_required', __( 'Der Papierkorbstatus des Spectra-Popups konnte nicht exakt bestätigt werden. Das Popup wurde nicht zurückgerollt. Prüfe den aktuellen Zustand im WordPress-Admin.', 'wp-agent-companion' ), array( 'status' => 500, 'recovery_required' => true, 'current_hash' => is_array( $after ) ? $after['hash'] : '' ) );
		}
		return array( 'id' => $post_id, 'trashed' => true, 'deleted' => false );
	} finally {
		wpagent_site_editor_release_lock( 'spectra-popup', (string) $post_id, $lock );
	}
}
