<?php
/** Transactional management for MB Settings Page definitions. */

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

function wpagent_metabox_settings_page_available(): bool {
	return function_exists( 'mb_settings_page_load' )
		&& class_exists( 'MBB\\Extensions\\SettingsPage\\Parser' )
		&& post_type_exists( 'mb-settings-page' );
}

/** @return true|WP_Error */
function wpagent_metabox_settings_page_require_runtime() {
	if ( wpagent_metabox_settings_page_available() ) {
		return true;
	}
	return new WP_Error(
		'wpagent_metabox_settings_page_missing',
		__( 'MB Settings Page und MB Builder sind nicht vollständig aktiv.', 'wp-agent-companion' ),
		array( 'status' => 409 )
	);
}

/** @return string|WP_Error */
function wpagent_metabox_settings_page_text( $value, string $field, int $max_length = 200, bool $allow_empty = true ) {
	if ( ! is_string( $value ) ) {
		return new WP_Error( 'wpagent_metabox_settings_page_invalid', sprintf( /* translators: %s: machine-readable field name. */ __( '%s muss Text sein.', 'wp-agent-companion' ), $field ), array( 'status' => 400 ) );
	}
	$value = sanitize_text_field( $value );
	$length = function_exists( 'mb_strlen' ) ? mb_strlen( $value ) : strlen( $value );
	if ( ( ! $allow_empty && '' === $value ) || $length > $max_length ) {
		return new WP_Error( 'wpagent_metabox_settings_page_invalid', sprintf( /* translators: %s: settings field name. */ __( '%s ist leer oder zu lang.', 'wp-agent-companion' ), $field ), array( 'status' => 400 ) );
	}
	return $value;
}

/** @return string|WP_Error */
function wpagent_metabox_settings_page_icon( $value ) {
	$icon = wpagent_metabox_settings_page_text( $value, 'icon_url', 500, false );
	if ( is_wp_error( $icon ) ) {
		return $icon;
	}
	if ( preg_match( '/^dashicons-[a-z0-9-]{1,80}$/', $icon ) || preg_match( '/^fa(?:s|r|b)? fa-[a-z0-9-]{1,80}$/', $icon ) ) {
		return $icon;
	}
	if ( str_starts_with( $icon, 'https://' ) && esc_url_raw( $icon, array( 'https' ) ) === $icon ) {
		return $icon;
	}
	return new WP_Error( 'wpagent_metabox_settings_page_icon', __( 'icon_url muss ein Dashicon, eine sichere Font-Awesome-Klasse oder eine HTTPS-URL sein. Aktive SVG-Daten-URLs sind gesperrt.', 'wp-agent-companion' ), array( 'status' => 400 ) );
}

/** @return array<string,string|array<string,string>>|WP_Error */
function wpagent_metabox_settings_page_tabs( $value ) {
	if ( ! is_array( $value ) || count( $value ) > 20 ) {
		return new WP_Error( 'wpagent_metabox_settings_page_tabs', __( 'tabs muss ein Objekt mit höchstens 20 Einträgen sein.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$tabs = array();
	foreach ( $value as $key => $tab ) {
		if ( ! is_string( $key ) || ! preg_match( '/^[a-z][a-z0-9_-]{0,63}$/', $key ) ) {
			return new WP_Error( 'wpagent_metabox_settings_page_tabs', __( 'Jeder Tab benötigt eine sichere kleingeschriebene ID.', 'wp-agent-companion' ), array( 'status' => 400 ) );
		}
		if ( is_string( $tab ) ) {
			$label = wpagent_metabox_settings_page_text( $tab, 'tab.label', 100, false );
			if ( is_wp_error( $label ) ) {
				return $label;
			}
			$tabs[ $key ] = $label;
			continue;
		}
		if ( ! is_array( $tab ) || array_diff( array_keys( $tab ), array( 'label', 'icon' ) ) ) {
			return new WP_Error( 'wpagent_metabox_settings_page_tabs', __( 'Tab-Objekte erlauben nur label und icon.', 'wp-agent-companion' ), array( 'status' => 400 ) );
		}
		$label = wpagent_metabox_settings_page_text( $tab['label'] ?? '', 'tab.label', 100, false );
		if ( is_wp_error( $label ) ) {
			return $label;
		}
		$normalized = array( 'label' => $label );
		if ( array_key_exists( 'icon', $tab ) ) {
			$icon = wpagent_metabox_settings_page_icon( $tab['icon'] );
			if ( is_wp_error( $icon ) ) {
				return $icon;
			}
			$normalized['icon'] = $icon;
		}
		$tabs[ $key ] = $normalized;
	}
	return $tabs;
}

/** @return array<int,array<string,int|string>>|WP_Error */
function wpagent_metabox_settings_page_help_tabs( $value ) {
	if ( ! is_array( $value ) || ! array_is_list( $value ) || count( $value ) > 20 ) {
		return new WP_Error( 'wpagent_metabox_settings_page_help', __( 'help_tabs muss eine Liste mit höchstens 20 Einträgen sein.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$tabs = array();
	foreach ( $value as $tab ) {
		if ( ! is_array( $tab ) || array_diff( array_keys( $tab ), array( 'title', 'content', 'priority' ) ) ) {
			return new WP_Error( 'wpagent_metabox_settings_page_help', __( 'Hilfeeinträge erlauben nur title, content und priority. PHP-Callbacks sind gesperrt.', 'wp-agent-companion' ), array( 'status' => 400 ) );
		}
		$title = wpagent_metabox_settings_page_text( $tab['title'] ?? '', 'help_tabs.title', 100, false );
		if ( is_wp_error( $title ) ) {
			return $title;
		}
		if ( ! is_string( $tab['content'] ?? null ) || strlen( $tab['content'] ) > 10000 ) {
			return new WP_Error( 'wpagent_metabox_settings_page_help', __( 'Jeder Hilfeeintrag benötigt höchstens 10.000 Byte HTML-Inhalt.', 'wp-agent-companion' ), array( 'status' => 400 ) );
		}
		$priority = $tab['priority'] ?? 10;
		if ( ! is_int( $priority ) || $priority < 0 || $priority > 1000 ) {
			return new WP_Error( 'wpagent_metabox_settings_page_help', __( 'help_tabs.priority muss zwischen 0 und 1.000 liegen.', 'wp-agent-companion' ), array( 'status' => 400 ) );
		}
		$tabs[] = array( 'title' => $title, 'content' => wp_kses_post( $tab['content'] ), 'priority' => $priority );
	}
	return $tabs;
}

/** @return array<string,mixed>|WP_Error */
function wpagent_metabox_validate_settings_page_settings( array $settings ) {
	$encoded = wp_json_encode( $settings );
	if ( false === $encoded || strlen( $encoded ) > 65536 ) {
		return new WP_Error( 'wpagent_metabox_settings_page_size', __( 'Die Einstellungsseiten-Definition darf höchstens 64 KiB groß sein.', 'wp-agent-companion' ), array( 'status' => 413 ) );
	}
	$allowed = array( 'id', 'option_name', 'class', 'menu_title', 'page_title', 'capability', 'icon_url', 'position', 'parent', 'submenu_title', 'help_tabs', 'style', 'columns', 'tabs', 'tab_style', 'submit_button', 'message', 'customizer', 'customizer_only', 'network' );
	if ( array_diff( array_keys( $settings ), $allowed ) ) {
		return new WP_Error( 'wpagent_metabox_settings_page_unknown', __( 'Die Definition enthält nicht unterstützte Einstellungen.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$id = is_string( $settings['id'] ?? null ) ? strtolower( $settings['id'] ) : '';
	if ( ! preg_match( '/^[a-z][a-z0-9_-]{0,63}$/', $id ) ) {
		return new WP_Error( 'wpagent_metabox_settings_page_id', __( 'Die Seiten-ID muss mit einem Kleinbuchstaben beginnen und darf höchstens 64 sichere Zeichen enthalten.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$normalized = array( 'id' => $id );
	$option_name = $settings['option_name'] ?? $id;
	if ( ! is_string( $option_name ) || ! preg_match( '/^[A-Za-z_][A-Za-z0-9_.:-]{0,190}$/', $option_name ) ) {
		return new WP_Error( 'wpagent_metabox_settings_page_option', __( 'option_name ist kein sicherer WordPress-Optionsschlüssel.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$normalized['option_name'] = $option_name;
	$text_fields = array( 'menu_title' => 200, 'page_title' => 200, 'submenu_title' => 200, 'submit_button' => 200, 'message' => 500 );
	foreach ( $text_fields as $key => $limit ) {
		if ( ! array_key_exists( $key, $settings ) ) {
			continue;
		}
		$value = wpagent_metabox_settings_page_text( $settings[ $key ], $key, $limit );
		if ( is_wp_error( $value ) ) {
			return $value;
		}
		if ( '' !== $value ) {
			$normalized[ $key ] = $value;
		}
	}
	if ( array_key_exists( 'class', $settings ) ) {
		if ( ! is_string( $settings['class'] ) ) {
			return new WP_Error( 'wpagent_metabox_settings_page_class', __( 'class muss eine Liste sicherer CSS-Klassen sein.', 'wp-agent-companion' ), array( 'status' => 400 ) );
		}
		$class_value = wpagent_metabox_settings_page_text( $settings['class'], 'class', 1000 );
		if ( is_wp_error( $class_value ) ) {
			return $class_value;
		}
		$classes = preg_split( '/\s+/', trim( $class_value ) ) ?: array();
		if ( count( $classes ) > 10 ) {
			return new WP_Error( 'wpagent_metabox_settings_page_class', __( 'Es sind höchstens zehn CSS-Klassen erlaubt.', 'wp-agent-companion' ), array( 'status' => 400 ) );
		}
		foreach ( $classes as $class ) {
			if ( '' === $class || sanitize_html_class( $class ) !== $class ) {
				return new WP_Error( 'wpagent_metabox_settings_page_class', __( 'class enthält ungültige Zeichen.', 'wp-agent-companion' ), array( 'status' => 400 ) );
			}
		}
		if ( $classes ) {
			$normalized['class'] = implode( ' ', $classes );
		}
	}
	$capability = $settings['capability'] ?? 'edit_theme_options';
	if ( ! is_string( $capability ) || ! preg_match( '/^[a-z][a-z0-9_]{0,63}$/', $capability ) ) {
		return new WP_Error( 'wpagent_metabox_settings_page_capability', __( 'capability ist kein sicherer WordPress-Capability-Schlüssel.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$non_admin_capabilities = array(
		'read', 'edit_posts', 'delete_posts', 'publish_posts', 'upload_files',
		'edit_published_posts', 'delete_published_posts', 'read_private_posts',
		'edit_others_posts', 'delete_others_posts', 'edit_pages', 'delete_pages',
		'publish_pages', 'edit_published_pages', 'delete_published_pages',
		'read_private_pages', 'edit_others_pages', 'delete_others_pages',
		'moderate_comments', 'manage_categories', 'manage_links', 'unfiltered_html',
	);
	if ( in_array( $capability, $non_admin_capabilities, true ) || preg_match( '/^level_[0-9]+$/', $capability ) ) {
		return new WP_Error( 'wpagent_metabox_settings_page_capability', __( 'Diese allgemeine Standardberechtigung würde die Einstellungsseite zu breit freigeben.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$normalized['capability'] = $capability;
	if ( array_key_exists( 'icon_url', $settings ) ) {
		$icon = wpagent_metabox_settings_page_icon( $settings['icon_url'] );
		if ( is_wp_error( $icon ) ) {
			return $icon;
		}
		$normalized['icon_url'] = $icon;
	}
	if ( array_key_exists( 'position', $settings ) ) {
		$position = $settings['position'];
		if ( ! is_int( $position ) || $position < 1 || $position > 999 ) {
			return new WP_Error( 'wpagent_metabox_settings_page_position', __( 'position muss zwischen 1 und 999 liegen.', 'wp-agent-companion' ), array( 'status' => 400 ) );
		}
		$normalized['position'] = $position;
	}
	if ( array_key_exists( 'parent', $settings ) && '' !== $settings['parent'] ) {
		$parent = wpagent_metabox_settings_page_text( $settings['parent'], 'parent', 190, false );
		if ( is_wp_error( $parent ) || ! preg_match( '/^[A-Za-z0-9_.?&=%\/-]+$/', $parent ) ) {
			return new WP_Error( 'wpagent_metabox_settings_page_parent', __( 'parent ist keine sichere WordPress-Menü-ID.', 'wp-agent-companion' ), array( 'status' => 400 ) );
		}
		$normalized['parent'] = $parent;
	}
	foreach ( array( 'style' => array( 'boxes', 'no-boxes' ), 'tab_style' => array( 'default', 'left' ) ) as $key => $values ) {
		if ( array_key_exists( $key, $settings ) ) {
			if ( ! is_string( $settings[ $key ] ) || ! in_array( $settings[ $key ], $values, true ) ) {
				return new WP_Error( 'wpagent_metabox_settings_page_style', sprintf( /* translators: %s: settings field name. */ __( '%s verwendet einen ungültigen Wert.', 'wp-agent-companion' ), $key ), array( 'status' => 400 ) );
			}
			$normalized[ $key ] = $settings[ $key ];
		}
	}
	if ( array_key_exists( 'columns', $settings ) ) {
		$columns = $settings['columns'];
		if ( ! is_int( $columns ) || ! in_array( $columns, array( 1, 2 ), true ) ) {
			return new WP_Error( 'wpagent_metabox_settings_page_columns', __( 'columns muss 1 oder 2 sein.', 'wp-agent-companion' ), array( 'status' => 400 ) );
		}
		$normalized['columns'] = $columns;
	}
	if ( array_key_exists( 'tabs', $settings ) ) {
		$tabs = wpagent_metabox_settings_page_tabs( $settings['tabs'] );
		if ( is_wp_error( $tabs ) ) {
			return $tabs;
		}
		if ( $tabs ) {
			$normalized['tabs'] = $tabs;
		}
	}
	if ( array_key_exists( 'help_tabs', $settings ) ) {
		$help_tabs = wpagent_metabox_settings_page_help_tabs( $settings['help_tabs'] );
		if ( is_wp_error( $help_tabs ) ) {
			return $help_tabs;
		}
		if ( $help_tabs ) {
			$normalized['help_tabs'] = $help_tabs;
		}
	}
	foreach ( array( 'customizer', 'customizer_only', 'network' ) as $key ) {
		if ( array_key_exists( $key, $settings ) ) {
			if ( ! is_bool( $settings[ $key ] ) ) {
					return new WP_Error( 'wpagent_metabox_settings_page_boolean', sprintf( /* translators: %s: settings field name. */ __( '%s muss ein Boolean sein.', 'wp-agent-companion' ), $key ), array( 'status' => 400 ) );
			}
			$normalized[ $key ] = $settings[ $key ];
		}
	}
	if ( ! empty( $normalized['customizer_only'] ) ) {
		$normalized['customizer'] = true;
	}
	if ( ! empty( $normalized['network'] ) && ! is_multisite() ) {
		return new WP_Error( 'wpagent_metabox_settings_page_network', __( 'Eine Netzwerk-Einstellungsseite erfordert eine WordPress-Multisite-Installation.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	if ( ! empty( $normalized['network'] ) && ! current_user_can( 'manage_network_options' ) ) {
		return new WP_Error( 'wpagent_metabox_settings_page_network_permission', __( 'Netzwerk-Einstellungsseiten dürfen nur Netzwerkadministratoren verwalten.', 'wp-agent-companion' ), array( 'status' => 403 ) );
	}
	return $normalized;
}

/** @return array{raw:array<string,mixed>,parsed:array<string,mixed>}|WP_Error */
function wpagent_metabox_prepare_settings_page( array $settings, string $title ) {
	$runtime = wpagent_metabox_settings_page_require_runtime();
	if ( is_wp_error( $runtime ) ) {
		return $runtime;
	}
	$normalized = wpagent_metabox_validate_settings_page_settings( $settings );
	if ( is_wp_error( $normalized ) ) {
		return $normalized;
	}
	$builder = $normalized;
	$builder['menu_title'] = $title;
	$builder['menu_type']  = empty( $normalized['parent'] ) ? 'top' : 'submenu';
	if ( 'top' === $builder['menu_type'] ) {
		unset( $builder['parent'] );
		if ( ! isset( $builder['icon_url'] ) ) {
			$builder['icon_url'] = 'dashicons-admin-generic';
		}
	}
	if ( isset( $builder['icon_url'] ) ) {
		$icon = (string) $builder['icon_url'];
		unset( $builder['icon_url'] );
		if ( str_starts_with( $icon, 'dashicons-' ) ) {
			$builder['icon_type']      = 'dashicons';
			$builder['icon_dashicons'] = substr( $icon, strlen( 'dashicons-' ) );
		} elseif ( preg_match( '/^fa(?:s|r|b)? fa-/', $icon ) ) {
			$builder['icon_type']         = 'font_awesome';
			$builder['icon_font_awesome'] = $icon;
		} else {
			$builder['icon_type']   = 'custom';
			$builder['icon_custom'] = $icon;
		}
	}
	if ( isset( $builder['tabs'] ) ) {
		$tabs = array();
		foreach ( $builder['tabs'] as $key => $value ) {
			$tabs[] = array( 'id' => 'wpagent_' . substr( hash( 'sha256', $key ), 0, 12 ), 'key' => $key, 'value' => $value );
		}
		$builder['tabs'] = $tabs;
	}
	if ( isset( $builder['help_tabs'] ) ) {
		$help_tabs = array();
		foreach ( $builder['help_tabs'] as $index => $tab ) {
			$help_tabs[] = array( 'id' => 'wpagent_' . $index, 'key' => $tab['title'], 'value' => $tab['content'], 'priority' => $tab['priority'] );
		}
		$builder['help_tabs'] = $help_tabs;
	}
	try {
		$parser = new MBB\Extensions\SettingsPage\Parser( $builder );
		$parser->parse_boolean_values()->parse_numeric_values();
		$raw = $parser->get_settings();
		$parser->parse();
		$parsed = $parser->get_settings();
	} catch ( Throwable $error ) {
		return new WP_Error( 'wpagent_metabox_settings_page_parse', __( 'MB Builder konnte die Einstellungsseite nicht sicher normalisieren.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	if ( ! is_array( $raw ) || ! is_array( $parsed ) || ( $parsed['id'] ?? '' ) !== $normalized['id'] ) {
		return new WP_Error( 'wpagent_metabox_settings_page_parse', __( 'MB Builder lieferte keine gültige Einstellungsseiten-Definition.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	return array( 'raw' => $raw, 'parsed' => $parsed );
}

/** @return array<int,array<string,mixed>> */
function wpagent_metabox_settings_page_runtime_pages(): array {
	$pages = apply_filters( 'mb_settings_pages', array() );
	if ( ! is_array( $pages ) ) {
		return array();
	}
	return $pages;
}

/** @param array<int,array<string,mixed>>|null $pages
 *  @return array<int,array<string,mixed>>
 */
function wpagent_metabox_settings_page_runtime_matches( string $settings_page_id, ?array $pages = null ): array {
	$pages = $pages ?? wpagent_metabox_settings_page_runtime_pages();
	return array_values(
		array_filter(
			$pages,
			static fn( $page ): bool => is_array( $page ) && is_string( $page['id'] ?? null ) && hash_equals( $settings_page_id, $page['id'] )
		)
	);
}

/** @param array<int,array<string,mixed>>|null $runtime_pages
 *  @return array<string,mixed>|WP_Error
 */
function wpagent_metabox_settings_page_state( int $post_id, ?array $runtime_pages = null ) {
	$available = wpagent_metabox_settings_page_require_runtime();
	if ( is_wp_error( $available ) ) {
		return $available;
	}
	$post = get_post( $post_id );
	if ( ! $post instanceof WP_Post || 'mb-settings-page' !== $post->post_type ) {
		return new WP_Error( 'wpagent_metabox_settings_page_not_found', __( 'Meta-Box-Einstellungsseite nicht gefunden.', 'wp-agent-companion' ), array( 'status' => 404 ) );
	}
	$raw      = get_post_meta( $post_id, 'settings', true );
	$settings = get_post_meta( $post_id, 'settings_page', true );
	if ( ! is_array( $raw ) || ! is_array( $settings ) || ! is_string( $settings['id'] ?? null ) ) {
		return new WP_Error( 'wpagent_metabox_settings_page_invalid', __( 'Die gespeicherte Meta-Box-Einstellungsseite ist unvollständig.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	try {
		$parser = new MBB\Extensions\SettingsPage\Parser( $raw );
		$parser->parse();
		$parsed_raw = $parser->get_settings();
	} catch ( Throwable $error ) {
		$parsed_raw = null;
	}
	if ( ! is_array( $parsed_raw ) || wpagent_metabox_canonicalize( $parsed_raw ) !== wpagent_metabox_canonicalize( $settings ) ) {
		return new WP_Error( 'wpagent_metabox_settings_page_storage_conflict', __( 'Builder-Quelle und abgeleitete Einstellungsseiten-Definition stimmen nicht überein.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	$public_settings = wpagent_metabox_validate_settings_page_settings( $settings );
	$title           = wpagent_metabox_settings_page_text( $post->post_title, 'title', 200, false );
	$expected_slug = (string) $settings['id'];
	$valid_slug    = 'trash' === $post->post_status
		? 1 === preg_match( '/^' . preg_quote( $expected_slug, '/' ) . '__trashed(?:-[1-9][0-9]{0,3})?$/', $post->post_name )
		: hash_equals( $expected_slug, $post->post_name );
	if (
		is_wp_error( $public_settings ) ||
		is_wp_error( $title ) ||
		! preg_match( '/^[a-z][a-z0-9_-]{0,63}(?:__trashed(?:-[1-9][0-9]{0,3})?)?$/', $post->post_name ) ||
		! $valid_slug ||
		! in_array( $post->post_status, array( 'publish', 'draft', 'trash' ), true )
	) {
		return new WP_Error( 'wpagent_metabox_settings_page_invalid', __( 'Die gespeicherte Meta-Box-Einstellungsseite liegt außerhalb des begrenzten öffentlichen Zustandsmodells.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	$runtime = null;
	if ( 'publish' === $post->post_status ) {
		$matches = wpagent_metabox_settings_page_runtime_matches( $settings['id'], $runtime_pages );
		if ( 1 !== count( $matches ) ) {
			return new WP_Error( 'wpagent_metabox_settings_page_runtime_conflict', __( 'Die aktive Meta-Box-Einstellungsseite fehlt oder ist mehrfach registriert.', 'wp-agent-companion' ), array( 'status' => 409 ) );
		}
		$runtime = $matches[0];
		if ( wpagent_metabox_canonicalize( $settings ) !== wpagent_metabox_canonicalize( $runtime ) ) {
			return new WP_Error( 'wpagent_metabox_settings_page_runtime_conflict', __( 'Die aktive Meta-Box-Einstellungsseite weicht von der persistierten Definition ab.', 'wp-agent-companion' ), array( 'status' => 409 ) );
		}
	}
	$state = array(
		'id' => $post_id,
		'title' => (string) $post->post_title,
		'slug' => (string) $post->post_name,
		'status' => (string) $post->post_status,
		'settings' => $settings,
		'runtime' => $runtime,
	);
	$state['hash'] = wpagent_metabox_hash( array_merge( $state, array( 'runtime' => null ) ) );
	return $state;
}

/** @return array<string,mixed> */
function wpagent_metabox_settings_page_create_candidate_state( int $post_id, string $title, array $prepared, string $status ): array {
	$state = array(
		'id'       => $post_id,
		'title'    => $title,
		'slug'     => (string) $prepared['parsed']['id'],
		'status'   => $status,
		'settings' => $prepared['parsed'],
		'runtime'  => null,
	);
	$state['hash'] = wpagent_metabox_hash( $state );
	return $state;
}

/** @param array<string,mixed>|WP_Error $fresh @param array<string,mixed> $candidate */
function wpagent_metabox_settings_page_owned_candidate( $fresh, array $candidate ): bool {
	if ( ! is_array( $fresh ) || ! is_string( $fresh['hash'] ?? null ) || ! is_string( $candidate['hash'] ?? null ) ) {
		return false;
	}
	$candidate_id = absint( $candidate['id'] ?? 0 );
	$settings_id  = (string) ( $candidate['settings']['id'] ?? '' );
	return $candidate_id > 0
		&& $candidate_id === absint( $fresh['id'] ?? 0 )
		&& '' !== $settings_id
		&& hash_equals( $settings_id, (string) ( $fresh['slug'] ?? '' ) )
		&& hash_equals( $settings_id, (string) ( $fresh['settings']['id'] ?? '' ) )
		&& hash_equals( $candidate['hash'], $fresh['hash'] );
}

/** @param array<string,mixed>|WP_Error $fresh */
function wpagent_metabox_settings_page_create_recovery_required( int $post_id, $fresh ): WP_Error {
	$data = array( 'status' => 409, 'recovery_required' => true, 'created_id' => $post_id );
	if ( is_array( $fresh ) && is_string( $fresh['hash'] ?? null ) ) {
		$data['current_hash'] = $fresh['hash'];
	}
	return new WP_Error(
		'wpagent_metabox_settings_page_create_recovery_required',
		__( 'Die neu angelegte Meta-Box-Einstellungsseite konnte nicht exakt verifiziert werden. Sie bleibt unverändert erhalten. Wiederhole den Vorgang nicht automatisch und prüfe sie manuell.', 'wp-agent-companion' ),
		$data
	);
}

function wpagent_metabox_settings_page_lock_name( string $settings_page_id ): string {
	return 'wp_agent_metabox_settings_page_lock_' . hash( 'sha256', $settings_page_id );
}

/** @return string|WP_Error */
function wpagent_metabox_settings_page_acquire_lock( string $settings_page_id ) {
	$option = wpagent_metabox_settings_page_lock_name( $settings_page_id );
	$token  = wpagent_companion_acquire_option_lock( $option, 300 );
	if ( is_string( $token ) ) {
		return $token;
	}
	return new WP_Error( 'wpagent_metabox_settings_page_busy', __( 'Diese Meta-Box-Einstellungsseite wird gerade geändert. Versuche es gleich erneut.', 'wp-agent-companion' ), array( 'status' => 409 ) );
}

function wpagent_metabox_settings_page_release_lock( string $settings_page_id, string $token ): void {
	wpagent_companion_release_option_lock( wpagent_metabox_settings_page_lock_name( $settings_page_id ), $token );
}

/** @return array<string,mixed>|WP_Error */
function wpagent_metabox_save_settings_page( WP_Post $post, string $title, array $prepared, string $status ) {
	$settings_page_id = (string) $prepared['parsed']['id'];
	$result = wp_update_post( array( 'ID' => $post->ID, 'post_title' => $title, 'post_name' => $settings_page_id, 'post_status' => $status ), true );
	if ( is_wp_error( $result ) ) {
		return $result;
	}
	update_post_meta( $post->ID, 'settings', $prepared['raw'] );
	update_post_meta( $post->ID, 'settings_page', $prepared['parsed'] );
	$fresh = wpagent_metabox_settings_page_state( $post->ID );
	$expected_runtime = 'publish' === $status ? apply_filters( 'mbb_settings_page', $prepared['parsed'], get_post( $post->ID ) ) : null;
	$mismatches = array();
	if ( is_wp_error( $fresh ) ) {
		$mismatches[] = $fresh->get_error_code();
	} else {
		if ( $fresh['title'] !== $title ) {
			$mismatches[] = 'title';
		}
		if ( $fresh['slug'] !== $settings_page_id ) {
			$mismatches[] = 'slug';
		}
		if ( $fresh['status'] !== $status ) {
			$mismatches[] = 'status';
		}
		if ( wpagent_metabox_canonicalize( $fresh['settings'] ) !== wpagent_metabox_canonicalize( $prepared['parsed'] ) ) {
			$mismatches[] = 'settings';
		}
		if ( wpagent_metabox_canonicalize( $fresh['runtime'] ) !== wpagent_metabox_canonicalize( $expected_runtime ) ) {
			$mismatches[] = 'runtime';
		}
	}
	if ( $mismatches ) {
		return new WP_Error(
			'wpagent_metabox_settings_page_readback_failed',
				sprintf( /* translators: %s: comma-separated read-back mismatch fields. */ __( 'Die Meta-Box-Einstellungsseite weicht nach dem Speichern in folgenden Bereichen ab: %s.', 'wp-agent-companion' ), implode( ', ', $mismatches ) ),
			array( 'status' => 500, 'mismatches' => $mismatches )
		);
	}
	return $fresh;
}

function wpagent_metabox_settings_page_post_exists( int $post_id ): bool {
	global $wpdb;
	return (bool) $wpdb->get_var( $wpdb->prepare( "SELECT 1 FROM {$wpdb->posts} WHERE `ID` = %d LIMIT 1", $post_id ) );
}

/** @return WP_Post|null */
function wpagent_metabox_settings_page_post_by_slug( string $slug ): ?WP_Post {
	$query = new WP_Query( array( 'post_type' => 'mb-settings-page', 'post_status' => array( 'publish', 'draft', 'trash' ), 'name' => $slug, 'posts_per_page' => 1, 'no_found_rows' => true ) );
	return isset( $query->posts[0] ) && $query->posts[0] instanceof WP_Post ? $query->posts[0] : null;
}

/** @return array<string,mixed>|WP_Error */
function wpagent_metabox_list_settings_pages( $input = array() ) {
	$input = is_array( $input ) ? $input : array();
	$runtime = wpagent_metabox_settings_page_require_runtime();
	if ( is_wp_error( $runtime ) ) {
		return $runtime;
	}
	$limit  = min( 100, max( 1, absint( $input['limit'] ?? 50 ) ) );
	$offset = min( 10000, absint( $input['offset'] ?? 0 ) );
	$args = array( 'post_type' => 'mb-settings-page', 'post_status' => array( 'publish', 'draft', 'trash' ), 'posts_per_page' => $limit, 'offset' => $offset, 'orderby' => 'ID', 'order' => 'ASC', 'no_found_rows' => false );
	$search = sanitize_text_field( (string) ( $input['search'] ?? '' ) );
	if ( '' !== $search ) {
		$args['s'] = $search;
	}
	$query  = new WP_Query( $args );
	$states = array();
	$runtime_pages = wpagent_metabox_settings_page_runtime_pages();
	foreach ( $query->posts as $post ) {
		$state = wpagent_metabox_settings_page_state( $post->ID, $runtime_pages );
		if ( is_wp_error( $state ) ) {
			return $state;
		}
		$states[] = $state;
	}
	return array( 'settings_pages' => $states, 'total' => (int) $query->found_posts );
}

/** @return array<string,mixed>|WP_Error */
function wpagent_metabox_get_settings_page( array $input ) {
	$runtime = wpagent_metabox_settings_page_require_runtime();
	return is_wp_error( $runtime ) ? $runtime : wpagent_metabox_settings_page_state( absint( $input['id'] ?? 0 ) );
}

/** @return array<string,mixed>|WP_Error */
function wpagent_metabox_create_settings_page( array $input ) {
	$title = wpagent_metabox_settings_page_text( $input['title'] ?? '', 'title', 200, false );
	if ( is_wp_error( $title ) ) {
		return $title;
	}
	$status = is_string( $input['status'] ?? null ) ? $input['status'] : 'publish';
	if ( ! in_array( $status, array( 'publish', 'draft' ), true ) ) {
		return new WP_Error( 'wpagent_metabox_settings_page_status', __( 'status muss publish oder draft sein.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$prepared = wpagent_metabox_prepare_settings_page( is_array( $input['settings'] ?? null ) ? $input['settings'] : array(), $title );
	if ( is_wp_error( $prepared ) ) {
		return $prepared;
	}
	$settings_page_id = (string) $prepared['parsed']['id'];
	$lock = wpagent_metabox_settings_page_acquire_lock( $settings_page_id );
	if ( is_wp_error( $lock ) ) {
		return $lock;
	}
	try {
		if ( wpagent_metabox_settings_page_post_by_slug( $settings_page_id ) ) {
			return new WP_Error( 'wpagent_metabox_settings_page_exists', __( 'Eine persistente Meta-Box-Einstellungsseite mit dieser ID existiert bereits.', 'wp-agent-companion' ), array( 'status' => 409 ) );
		}
		if ( wpagent_metabox_settings_page_runtime_matches( $settings_page_id ) ) {
			return new WP_Error( 'wpagent_metabox_settings_page_runtime_collision', __( 'Eine per PHP registrierte Meta-Box-Einstellungsseite verwendet diese ID bereits. Sie wurde nicht überschrieben.', 'wp-agent-companion' ), array( 'status' => 409 ) );
		}
		$post_id = wp_insert_post( array( 'post_type' => 'mb-settings-page', 'post_title' => $title, 'post_name' => $settings_page_id, 'post_status' => 'auto-draft' ), true );
		if ( is_wp_error( $post_id ) ) {
			return $post_id;
		}
		$post = get_post( $post_id );
		$saved = $post instanceof WP_Post ? wpagent_metabox_save_settings_page( $post, $title, $prepared, $status ) : new WP_Error( 'wpagent_metabox_settings_page_save_failed', __( 'Die neue Einstellungsseite ist vor der Verifikation verschwunden.', 'wp-agent-companion' ), array( 'status' => 500 ) );
		if ( ! is_wp_error( $saved ) ) {
			return $saved;
		}
		$candidate = wpagent_metabox_settings_page_create_candidate_state( $post_id, $title, $prepared, $status );
		$fresh     = wpagent_metabox_settings_page_state( $post_id );
		if ( ! wpagent_metabox_settings_page_owned_candidate( $fresh, $candidate ) ) {
			return wpagent_metabox_settings_page_create_recovery_required( $post_id, $fresh );
		}
		$deleted = wp_delete_post( $post_id, true );
		if ( ! $deleted || wpagent_metabox_settings_page_post_exists( $post_id ) ) {
			return wpagent_metabox_settings_page_create_recovery_required( $post_id, wpagent_metabox_settings_page_state( $post_id ) );
		}
		return new WP_Error( 'wpagent_metabox_settings_page_save_failed', $saved->get_error_message(), array( 'status' => 500 ) );
	} finally {
		wpagent_metabox_settings_page_release_lock( $settings_page_id, $lock );
	}
}

/** @return WP_Error */
function wpagent_metabox_settings_page_manual_write_only() {
	return new WP_Error(
		'wpagent_metabox_settings_page_mutation_manual_only',
		__( 'Meta Box stellt für Einstellungsseiten keine speicheratomare Compare-and-Set- oder Compare-and-Delete-Operation bereit. WPAgently ändert oder verschiebt diese Definition deshalb nicht. Nimm die Änderung manuell in WordPress vor und lies sie anschließend neu.', 'wp-agent-companion' ),
		array( 'status' => 409, 'manual_action_required' => true )
	);
}

/** @return array<string,mixed>|WP_Error */
function wpagent_metabox_update_settings_page( array $input ) {
	return wpagent_metabox_settings_page_manual_write_only();
}

/** @return array<string,mixed>|WP_Error */
function wpagent_metabox_delete_settings_page( array $input ) {
	return wpagent_metabox_settings_page_manual_write_only();
}
