<?php
/** Conflict-safe writes for native ACPT Lite content-model definitions. */

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

/** @return array<string,mixed> */
function wpagent_acpt_write_properties( string $kind, bool $create ): array {
	$properties = array(
		'slug' => array( 'type' => 'string', 'pattern' => '^[a-z0-9][a-z0-9_-]*$', 'maxLength' => 'post_type' === $kind ? 20 : 32 ),
		'singular_label' => array( 'type' => 'string', 'minLength' => 1, 'maxLength' => 100 ),
		'plural_label' => array( 'type' => 'string', 'minLength' => 1, 'maxLength' => 100 ),
		'description' => array( 'type' => 'string', 'maxLength' => 1000 ),
		'public' => array( 'type' => 'boolean' ), 'hierarchical' => array( 'type' => 'boolean' ),
		'show_ui' => array( 'type' => 'boolean' ), 'show_in_rest' => array( 'type' => 'boolean' ),
		'rewrite_slug' => array( 'type' => 'string', 'maxLength' => 200 ),
	);
	if ( 'post_type' === $kind ) {
		$properties['icon'] = array( 'type' => 'string', 'pattern' => '^[a-z0-9-]+$', 'maxLength' => 50 );
		$properties['supports'] = array( 'type' => 'array', 'maxItems' => 11, 'uniqueItems' => true, 'items' => array( 'type' => 'string', 'enum' => wpagent_acpt_supported_post_supports() ) );
		$properties['taxonomies'] = array( 'type' => 'array', 'maxItems' => 20, 'uniqueItems' => true, 'items' => array( 'type' => 'string', 'pattern' => '^[a-z0-9][a-z0-9_-]*$', 'maxLength' => 32 ) );
		$properties['has_archive'] = array( 'type' => 'boolean' );
	} else {
		$properties['object_types'] = array( 'type' => 'array', 'minItems' => 1, 'maxItems' => 20, 'uniqueItems' => true, 'items' => array( 'type' => 'string', 'pattern' => '^[a-z0-9][a-z0-9_-]*$', 'maxLength' => 20 ) );
		$properties['show_admin_column'] = array( 'type' => 'boolean' );
	}
	if ( ! $create ) {
		$properties['expected_hash'] = array( 'type' => 'string', 'pattern' => '^[a-f0-9]{64}$' );
	}
	return $properties;
}

/** @return array<string,mixed> */
function wpagent_acpt_mutation_output_schema( string $kind ): array {
	return array(
		'type' => 'object',
		'properties' => array(
			'model' => wpagent_acpt_output_schema( $kind ), 'verified_persistence' => array( 'type' => 'boolean' ),
			'reload_required' => array( 'type' => 'boolean' ),
		),
		'required' => array( 'model', 'verified_persistence', 'reload_required' ), 'additionalProperties' => false,
	);
}

/** @return array<string,mixed> */
function wpagent_acpt_create_ability( string $kind ): array {
	$is_post_type = 'post_type' === $kind;
	return array(
		'label' => $is_post_type ? __( 'ACPT-Lite-Inhaltstyp erstellen', 'wp-agent-companion' ) : __( 'ACPT-Lite-Taxonomie erstellen', 'wp-agent-companion' ),
		'description' => __( 'Erstellt über die native ACPT-Lite-Repository-API eine begrenzte Definition und prüft den gespeicherten Providerzustand vollständig zurück.', 'wp-agent-companion' ),
		'category' => 'wp-agent',
		'input_schema' => array(
			'type' => 'object', 'properties' => wpagent_acpt_write_properties( $kind, true ),
			'required' => array( 'slug', 'singular_label', 'plural_label', $is_post_type ? 'supports' : 'object_types' ), 'additionalProperties' => false,
		),
		'output_schema' => wpagent_acpt_mutation_output_schema( $kind ),
		'execute_callback' => $is_post_type ? 'wpagent_exec_create_acpt_post_type' : 'wpagent_exec_create_acpt_taxonomy',
		'permission_callback' => 'wpagent_perm_manage_options',
		'meta' => array( 'show_in_rest' => true, 'annotations' => array( 'readonly' => false, 'destructive' => false, 'idempotent' => false ) ),
	);
}

/** @return array<string,mixed> */
function wpagent_acpt_update_ability( string $kind ): array {
	$is_post_type = 'post_type' === $kind;
	return array(
		'label' => $is_post_type ? __( 'ACPT-Lite-Inhaltstyp aktualisieren', 'wp-agent-companion' ) : __( 'ACPT-Lite-Taxonomie aktualisieren', 'wp-agent-companion' ),
		'description' => __( 'Aktualisiert freigegebene ACPT-Lite-Felder mit Konflikthash, vollständigem Read-back und verifiziertem Rollback.', 'wp-agent-companion' ),
		'category' => 'wp-agent',
		'input_schema' => array(
			'type' => 'object', 'properties' => wpagent_acpt_write_properties( $kind, false ),
			'required' => array( 'slug', 'expected_hash' ), 'minProperties' => 3, 'additionalProperties' => false,
		),
		'output_schema' => wpagent_acpt_mutation_output_schema( $kind ),
		'execute_callback' => $is_post_type ? 'wpagent_exec_update_acpt_post_type' : 'wpagent_exec_update_acpt_taxonomy',
		'permission_callback' => 'wpagent_perm_manage_options',
		'meta' => array( 'show_in_rest' => true, 'annotations' => array( 'readonly' => false, 'destructive' => false, 'idempotent' => true ) ),
	);
}

/** @return array<string,mixed> */
function wpagent_acpt_delete_ability( string $kind ): array {
	$is_post_type = 'post_type' === $kind;
	return array(
		'label' => $is_post_type ? __( 'ACPT-Lite-Inhaltstypdefinition löschen', 'wp-agent-companion' ) : __( 'ACPT-Lite-Taxonomiedefinition löschen', 'wp-agent-companion' ),
		'description' => __( 'Löscht nur eine ACPT-Lite-Definition. Inhalte bleiben erhalten. Verknüpfte ACPT-Metafelder sperren den Vorgang.', 'wp-agent-companion' ),
		'category' => 'wp-agent',
		'input_schema' => array(
			'type' => 'object',
			'properties' => array(
				'slug' => array( 'type' => 'string', 'pattern' => '^[a-z0-9][a-z0-9_-]*$', 'maxLength' => $is_post_type ? 20 : 32 ),
				'expected_hash' => array( 'type' => 'string', 'pattern' => '^[a-f0-9]{64}$' ),
				'confirm' => array( 'type' => 'boolean' ), 'confirm_content' => array( 'type' => 'boolean', 'default' => false ),
			),
			'required' => array( 'slug', 'expected_hash', 'confirm' ), 'additionalProperties' => false,
		),
		'output_schema' => array(
			'type' => 'object',
			'properties' => array(
				'deleted' => array( 'type' => 'boolean' ), 'slug' => array( 'type' => 'string' ), 'retained_content' => array( 'type' => 'integer' ),
				'verified_persistence' => array( 'type' => 'boolean' ), 'reload_required' => array( 'type' => 'boolean' ),
			),
			'required' => array( 'deleted', 'slug', 'retained_content', 'verified_persistence', 'reload_required' ), 'additionalProperties' => false,
		),
		'execute_callback' => $is_post_type ? 'wpagent_exec_delete_acpt_post_type' : 'wpagent_exec_delete_acpt_taxonomy',
		'permission_callback' => 'wpagent_perm_manage_options',
		'meta' => array( 'show_in_rest' => true, 'annotations' => array( 'readonly' => false, 'destructive' => true, 'idempotent' => true ) ),
	);
}

function wpagent_ability_create_acpt_post_type(): array {
	return wpagent_acpt_create_ability( 'post_type' );
}
function wpagent_ability_update_acpt_post_type(): array {
	return wpagent_acpt_update_ability( 'post_type' );
}
function wpagent_ability_delete_acpt_post_type(): array {
	return wpagent_acpt_delete_ability( 'post_type' );
}
function wpagent_ability_create_acpt_taxonomy(): array {
	return wpagent_acpt_create_ability( 'taxonomy' );
}
function wpagent_ability_update_acpt_taxonomy(): array {
	return wpagent_acpt_update_ability( 'taxonomy' );
}
function wpagent_ability_delete_acpt_taxonomy(): array {
	return wpagent_acpt_delete_ability( 'taxonomy' );
}

/** @return string[]|WP_Error */
function wpagent_acpt_names( $value, string $kind, bool $allow_empty ) {
	if ( ! is_array( $value ) || ( ! $allow_empty && array() === $value ) || count( $value ) > 20 ) {
		return new WP_Error( 'wpagent_acpt_names', __( 'Die ACPT-Lite-Zuordnung enthält eine ungültige Anzahl von Bezeichnern.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$names = array();
	foreach ( $value as $item ) {
		$name = wpagent_acpt_slug( $item, $kind );
		if ( is_wp_error( $name ) ) {
			return $name;
		}
		$names[] = $name;
	}
	$names = array_values( array_unique( $names ) );
	if ( count( $names ) !== count( $value ) ) {
		return new WP_Error( 'wpagent_acpt_names', __( 'ACPT-Lite-Zuordnungen dürfen keine doppelten Bezeichner enthalten.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	sort( $names, SORT_STRING );
	return $names;
}

/** @return array<string,mixed>|WP_Error */
function wpagent_acpt_validate_changes( string $kind, array $input, bool $create ) {
	$changes = array();
	if ( $create ) {
		$slug = wpagent_acpt_slug( $input['slug'] ?? '', $kind );
		if ( is_wp_error( $slug ) ) {
			return $slug;
		}
		$changes['slug'] = $slug;
	}
	foreach ( array( 'singular_label' => 100, 'plural_label' => 100 ) as $field => $max ) {
		if ( $create || array_key_exists( $field, $input ) ) {
			$value = wpagent_acpt_text( $input[ $field ] ?? '', $field, $max );
			if ( is_wp_error( $value ) ) {
				return $value;
			}
			$changes[ $field ] = $value;
		}
	}
	if ( array_key_exists( 'description', $input ) ) {
		$value = wpagent_acpt_text( $input['description'], 'description', 1000, true );
		if ( is_wp_error( $value ) ) {
			return $value;
		}
		$changes['description'] = $value;
	}
	foreach ( array( 'public', 'hierarchical', 'show_ui', 'show_in_rest' ) as $field ) {
		if ( array_key_exists( $field, $input ) ) {
			if ( ! is_bool( $input[ $field ] ) ) {
				return new WP_Error( 'wpagent_acpt_boolean', __( 'Boolesche ACPT-Lite-Felder akzeptieren nur true oder false.', 'wp-agent-companion' ), array( 'status' => 400 ) );
			}
			$changes[ $field ] = $input[ $field ];
		}
	}
	if ( array_key_exists( 'rewrite_slug', $input ) ) {
		$value = wpagent_acpt_rewrite_slug( $input['rewrite_slug'] );
		if ( is_wp_error( $value ) ) {
			return $value;
		}
		$changes['rewrite_slug'] = $value;
	}
	if ( 'post_type' === $kind ) {
		if ( array_key_exists( 'icon', $input ) ) {
			$icon = is_string( $input['icon'] ) ? $input['icon'] : '';
			if ( '' === $icon || strlen( $icon ) > 50 || ! preg_match( '/^[a-z0-9-]+$/', $icon ) ) {
				return new WP_Error( 'wpagent_acpt_icon', __( 'icon muss ein lokaler ACPT- oder Dashicon-Bezeichner sein.', 'wp-agent-companion' ), array( 'status' => 400 ) );
			}
			$changes['icon'] = $icon;
		}
		if ( $create || array_key_exists( 'supports', $input ) ) {
			if ( ! is_array( $input['supports'] ?? null ) || count( $input['supports'] ) > 11 ) {
				return new WP_Error( 'wpagent_acpt_supports', __( 'supports enthält eine ungültige Anzahl von Einträgen.', 'wp-agent-companion' ), array( 'status' => 400 ) );
			}
			foreach ( $input['supports'] as $support ) {
				if ( ! is_string( $support ) ) {
					return new WP_Error( 'wpagent_acpt_supports', __( 'supports enthält nicht freigegebene oder doppelte Einträge.', 'wp-agent-companion' ), array( 'status' => 400 ) );
				}
			}
			$supports = array_values( array_unique( $input['supports'] ) );
			if ( count( $supports ) !== count( $input['supports'] ) || array() !== array_diff( $supports, wpagent_acpt_supported_post_supports() ) ) {
				return new WP_Error( 'wpagent_acpt_supports', __( 'supports enthält nicht freigegebene oder doppelte Einträge.', 'wp-agent-companion' ), array( 'status' => 400 ) );
			}
			sort( $supports, SORT_STRING );
			$changes['supports'] = $supports;
		}
		if ( array_key_exists( 'taxonomies', $input ) ) {
			$names = wpagent_acpt_names( $input['taxonomies'], 'taxonomy', true );
			if ( is_wp_error( $names ) ) {
				return $names;
			}
			$changes['associations'] = $names;
		}
		if ( array_key_exists( 'has_archive', $input ) ) {
			if ( ! is_bool( $input['has_archive'] ) ) {
				return new WP_Error( 'wpagent_acpt_boolean', __( 'has_archive akzeptiert nur true oder false.', 'wp-agent-companion' ), array( 'status' => 400 ) );
			}
			$changes['has_archive'] = $input['has_archive'];
		}
	} else {
		if ( $create || array_key_exists( 'object_types', $input ) ) {
			$names = wpagent_acpt_names( $input['object_types'] ?? null, 'post_type', false );
			if ( is_wp_error( $names ) ) {
				return $names;
			}
			$changes['associations'] = $names;
		}
		if ( array_key_exists( 'show_admin_column', $input ) ) {
			if ( ! is_bool( $input['show_admin_column'] ) ) {
				return new WP_Error( 'wpagent_acpt_boolean', __( 'show_admin_column akzeptiert nur true oder false.', 'wp-agent-companion' ), array( 'status' => 400 ) );
			}
			$changes['show_admin_column'] = $input['show_admin_column'];
		}
	}
	if ( ! $create && array() === $changes ) {
		return new WP_Error( 'wpagent_acpt_no_changes', __( 'Die Aktualisierung enthält keine freigegebene Änderung.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	return $changes;
}

/** @return true|WP_Error */
function wpagent_acpt_validate_new_slug( string $kind, string $slug, array $provider ) {
	try {
		$reserved = $provider['reserved_terms']::list();
	} catch ( Throwable $error ) {
		return new WP_Error( 'wpagent_acpt_api', __( 'ACPT Lite konnte die reservierten Bezeichner nicht zuverlässig lesen.', 'wp-agent-companion' ), array( 'status' => 500 ) );
	}
	if ( ! is_array( $reserved ) ) {
		return new WP_Error( 'wpagent_acpt_api', __( 'ACPT Lite lieferte keine gültige Liste reservierter Bezeichner.', 'wp-agent-companion' ), array( 'status' => 500 ) );
	}
	if ( in_array( $slug, $reserved, true ) ) {
		return new WP_Error( 'wpagent_acpt_reserved', __( 'Der Bezeichner ist von WordPress oder ACPT Lite reserviert.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	return wpagent_acpt_validate_rewrite_path( $slug );
}

/** @return array<string,mixed> */
function wpagent_acpt_default_raw( string $kind, string $slug ): array {
	$base = array(
		'id' => wp_generate_uuid4(), 'slug' => $slug, 'singular' => '', 'plural' => '', 'native' => false, 'labels' => array(),
		'settings' => array(
			'description' => '', 'public' => true, 'publicly_queryable' => true, 'show_ui' => true, 'show_in_menu' => true,
			'show_in_nav_menus' => true, 'show_in_rest' => true, 'hierarchical' => false, 'query_var' => true,
		),
		'associations' => array(),
	);
	if ( 'post_type' === $kind ) {
		$base['icon'] = 'admin-post';
		$base['supports'] = array();
		$base['settings'] += array( 'rewrite' => true, 'custom_rewrite' => '', 'with_front' => true, 'has_archive' => false, 'exclude_from_search' => false, 'can_export' => true, 'delete_with_user' => false, 'menu_position' => null );
	} else {
		$base['settings'] += array( 'rewrite' => array( 'slug' => $slug, 'with_front' => true ), 'show_tagcloud' => true, 'show_in_quick_edit' => true, 'show_admin_column' => false, 'sort' => false );
	}
	return $base;
}

/** @return array<string,mixed> */
function wpagent_acpt_apply_changes( string $kind, array $raw, array $changes ): array {
	foreach ( $changes as $field => $value ) {
		switch ( $field ) {
			case 'slug': $raw['slug'] = $value; break;
			case 'singular_label': $raw['singular'] = $value; break;
			case 'plural_label': $raw['plural'] = $value; break;
			case 'icon': case 'supports': case 'associations': $raw[ $field ] = $value; break;
			case 'description': $raw['settings']['description'] = $value; break;
			case 'hierarchical': case 'show_in_rest': $raw['settings'][ $field ] = $value; break;
			case 'public':
				$raw['settings']['public'] = $value;
				$raw['settings']['publicly_queryable'] = $value;
				$raw['settings']['show_in_nav_menus'] = $value;
				if ( 'post_type' === $kind ) { $raw['settings']['exclude_from_search'] = ! $value; }
				break;
			case 'show_ui':
				$raw['settings']['show_ui'] = $value;
				$raw['settings']['show_in_menu'] = $value;
				if ( 'taxonomy' === $kind ) { $raw['settings']['show_tagcloud'] = $value; $raw['settings']['show_in_quick_edit'] = $value; }
				break;
			case 'rewrite_slug':
				if ( 'post_type' === $kind ) { $raw['settings']['rewrite'] = true; $raw['settings']['custom_rewrite'] = $value; }
				else { $raw['settings']['rewrite'] = array( 'slug' => '' === $value ? $raw['slug'] : $value, 'with_front' => true ); }
				break;
			case 'has_archive': case 'show_admin_column': $raw['settings'][ $field ] = $value; break;
		}
	}
	return $raw;
}

/** @return object|WP_Error */
function wpagent_acpt_hydrate( string $kind, array $raw ) {
	$provider = wpagent_acpt_provider();
	if ( is_wp_error( $provider ) ) {
		return $provider;
	}
	$class = 'post_type' === $kind ? $provider['post_model'] : $provider['tax_model'];
	$data = array(
		'id' => $raw['id'], 'native' => false, 'labels' => $raw['labels'], 'settings' => $raw['settings'],
	);
	if ( 'post_type' === $kind ) {
		$data += array( 'name' => $raw['slug'], 'singular' => $raw['singular'], 'plural' => $raw['plural'], 'icon' => $raw['icon'], 'supports' => $raw['supports'] );
	} else {
		$data += array( 'slug' => $raw['slug'], 'singular' => $raw['singular'], 'plural' => $raw['plural'] );
	}
	try {
		$model = $class::hydrateFromArray( $data );
		$defaults = $model->defaultLabels();
		$raw['labels'] = array_merge( $defaults, $raw['labels'] );
		$data['labels'] = $raw['labels'];
		return $class::hydrateFromArray( $data );
	} catch ( Throwable $error ) {
		return new WP_Error( 'wpagent_acpt_model', __( 'ACPT Lite hat die begrenzte Definition abgelehnt.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
}

/** @return array<string,mixed>|WP_Error */
function wpagent_acpt_refresh_default_labels( string $kind, array $before, array $after ) {
	if ( $before['singular'] === $after['singular'] && $before['plural'] === $after['plural'] ) {
		return $after;
	}
	$before_model = wpagent_acpt_hydrate( $kind, $before );
	$after_model = wpagent_acpt_hydrate( $kind, $after );
	if ( is_wp_error( $before_model ) || is_wp_error( $after_model ) ) {
		return new WP_Error( 'wpagent_acpt_model', __( 'Die ACPT-Lite-Standardbeschriftungen konnten nicht sicher aktualisiert werden.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$old_defaults = $before_model->defaultLabels();
	$new_defaults = $after_model->defaultLabels();
	foreach ( $new_defaults as $key => $value ) {
		if ( ! array_key_exists( $key, $before['labels'] ) || ( array_key_exists( $key, $old_defaults ) && $before['labels'][ $key ] === $old_defaults[ $key ] ) ) {
			$after['labels'][ $key ] = $value;
		}
	}
	return $after;
}

/** @return array<string,mixed>|WP_Error */
function wpagent_acpt_expected_raw( string $kind, array $raw ) {
	$model = wpagent_acpt_hydrate( $kind, $raw );
	if ( is_wp_error( $model ) ) {
		return $model;
	}
	$expected = wpagent_acpt_raw_model( $kind, $model );
	if ( is_wp_error( $expected ) ) {
		return $expected;
	}
	$expected['associations'] = array_values( array_unique( array_map( 'strval', $raw['associations'] ) ) );
	sort( $expected['associations'], SORT_STRING );
	return $expected;
}

/** @return true|WP_Error */
function wpagent_acpt_sync_associations( string $kind, string $model_id, array $desired ) {
	$provider = wpagent_acpt_provider();
	if ( is_wp_error( $provider ) ) {
		return $provider;
	}
	$post_repository = $provider['post_repository'];
	$tax_repository = $provider['tax_repository'];
	try {
		$current_model = 'post_type' === $kind
			? $post_repository::get( array( 'id' => $model_id ) )
			: $tax_repository::get( array( 'id' => $model_id ) );
		if ( ! is_array( $current_model ) || 1 !== count( $current_model ) ) {
			throw new RuntimeException( 'ACPT model missing after save.' );
		}
		$current_raw = wpagent_acpt_raw_model( $kind, reset( $current_model ) );
		if ( is_wp_error( $current_raw ) ) {
			return $current_raw;
		}
		$desired_pairs = array();
		foreach ( $desired as $name ) {
			$post_id = 'post_type' === $kind ? $model_id : $post_repository::getId( $name );
			$tax_id = 'post_type' === $kind ? $tax_repository::getId( $name ) : $model_id;
			if ( ! $post_id || ! $tax_id ) {
				return new WP_Error( 'wpagent_acpt_association', __( 'Mindestens eine Zuordnung ist nicht als ACPT-Lite-Providerdefinition verfügbar.', 'wp-agent-companion' ), array( 'status' => 409 ) );
			}
			$desired_pairs[] = array( $post_id, $tax_id );
		}
		foreach ( $current_raw['associations'] as $name ) {
			$post_id = 'post_type' === $kind ? $model_id : $post_repository::getId( $name );
			$tax_id = 'post_type' === $kind ? $tax_repository::getId( $name ) : $model_id;
			if ( $post_id && $tax_id ) {
				$tax_repository::removeAssocPost( $post_id, $tax_id );
			}
		}
		foreach ( $desired_pairs as $pair ) {
			$tax_repository::assocToPostType( $pair[0], $pair[1] );
		}
		$cache = wpagent_acpt_flush_provider_cache( $provider );
		if ( is_wp_error( $cache ) ) {
			return $cache;
		}
	} catch ( Throwable $error ) {
		return new WP_Error( 'wpagent_acpt_association', __( 'ACPT Lite konnte die Definition nicht vollständig zuordnen.', 'wp-agent-companion' ), array( 'status' => 500 ) );
	}
	return true;
}

/** @return bool */
function wpagent_acpt_delete_owned_definition( string $kind, string $slug, string $expected_id, array $provider ): bool {
	$model = wpagent_acpt_model( $kind, $slug );
	if ( wpagent_acpt_is_not_found_error( $model ) ) {
		return true;
	}
	if ( is_wp_error( $model ) || ! method_exists( $model, 'getId' ) ) {
		return false;
	}
	try {
		$current_id = $model->getId();
	} catch ( Throwable $error ) {
		return false;
	}
	if ( ! is_string( $current_id ) || ! hash_equals( $expected_id, $current_id ) ) {
		return false;
	}
	$repository = 'post_type' === $kind ? $provider['post_repository'] : $provider['tax_repository'];
	try {
		'post_type' === $kind ? $repository::delete( $slug, false ) : $repository::delete( $slug );
	} catch ( Throwable $error ) {
		return false;
	}
	if ( is_wp_error( wpagent_acpt_flush_provider_cache( $provider ) ) ) {
		return false;
	}
	return wpagent_acpt_is_not_found_error( wpagent_acpt_model( $kind, $slug ) );
}

/** @return bool */
function wpagent_acpt_restore_raw( string $kind, array $raw ): bool {
	$restored = wpagent_acpt_save_raw( $kind, $raw );
	$rollback_model = wpagent_acpt_model( $kind, $raw['slug'] );
	$rollback_raw = is_wp_error( $rollback_model ) ? $rollback_model : wpagent_acpt_raw_model( $kind, $rollback_model );
	return ! is_wp_error( $restored ) && ! is_wp_error( $rollback_raw ) && hash_equals( wpagent_acpt_hash( $raw ), wpagent_acpt_hash( $rollback_raw ) );
}

/** @return true|WP_Error */
function wpagent_acpt_save_raw( string $kind, array $raw ) {
	$provider = wpagent_acpt_provider();
	if ( is_wp_error( $provider ) ) {
		return $provider;
	}
	$model = wpagent_acpt_hydrate( $kind, $raw );
	if ( is_wp_error( $model ) ) {
		return $model;
	}
	$repository = 'post_type' === $kind ? $provider['post_repository'] : $provider['tax_repository'];
	try {
		$repository::save( $model );
	} catch ( Throwable $error ) {
		return new WP_Error( 'wpagent_acpt_write', __( 'ACPT Lite konnte die Definition nicht speichern.', 'wp-agent-companion' ), array( 'status' => 500 ) );
	}
	$cache = wpagent_acpt_flush_provider_cache( $provider );
	if ( is_wp_error( $cache ) ) {
		return $cache;
	}
	return wpagent_acpt_sync_associations( $kind, $raw['id'], $raw['associations'] );
}

function wpagent_acpt_mark_rewrite_reload(): void {
	delete_option( 'rewrite_rules' );
	wp_cache_delete( 'rewrite_rules', 'options' );
}

/** @return array<string,mixed>|WP_Error */
function wpagent_acpt_create_model( string $kind, $input ) {
	$provider = wpagent_acpt_provider();
	if ( is_wp_error( $provider ) ) { return $provider; }
	$input = is_array( $input ) ? $input : array();
	$changes = wpagent_acpt_validate_changes( $kind, $input, true );
	if ( is_wp_error( $changes ) ) { return $changes; }
	$slug = $changes['slug'];
	$lock = wpagent_acpt_acquire_lock();
	if ( is_wp_error( $lock ) ) { return $lock; }
	try {
			$repository = 'post_type' === $kind ? $provider['post_repository'] : $provider['tax_repository'];
			$cache = wpagent_acpt_flush_provider_cache( $provider );
			if ( is_wp_error( $cache ) ) { return $cache; }
			try {
				$provider_exists = $repository::exists( $slug );
			} catch ( Throwable $error ) {
				return new WP_Error( 'wpagent_acpt_read', __( 'ACPT Lite konnte bestehende Definitionen nicht zuverlässig prüfen.', 'wp-agent-companion' ), array( 'status' => 500 ) );
			}
			if ( $provider_exists || post_type_exists( $slug ) || taxonomy_exists( $slug ) ) {
			return new WP_Error( 'wpagent_acpt_exists', __( 'Der Bezeichner ist bereits durch ACPT Lite, WordPress oder einen anderen Provider belegt.', 'wp-agent-companion' ), array( 'status' => 409 ) );
		}
			$slug_status = wpagent_acpt_validate_new_slug( $kind, $slug, $provider );
			if ( is_wp_error( $slug_status ) ) { return $slug_status; }
			$rewrite_path = '' !== ( $changes['rewrite_slug'] ?? '' ) ? $changes['rewrite_slug'] : $slug;
			if ( $rewrite_path !== $slug ) {
				$rewrite_status = wpagent_acpt_validate_rewrite_path( $rewrite_path );
				if ( is_wp_error( $rewrite_status ) ) { return $rewrite_status; }
			}
			$raw = wpagent_acpt_apply_changes( $kind, wpagent_acpt_default_raw( $kind, $slug ), $changes );
		$saved = wpagent_acpt_save_raw( $kind, $raw );
		if ( is_wp_error( $saved ) ) {
			$error_data = $saved->get_error_data();
			$saved->add_data( array( 'status' => is_array( $error_data ) ? (int) ( $error_data['status'] ?? 500 ) : 500, 'rollback_verified' => wpagent_acpt_delete_owned_definition( $kind, $slug, $raw['id'], $provider ) ) );
			return $saved;
		}
		do_action( 'wpagent_acpt_after_write', $kind, $slug, 'create' );
		$current = wpagent_acpt_model( $kind, $slug );
		$current_raw = is_wp_error( $current ) ? $current : wpagent_acpt_raw_model( $kind, $current );
		$expected_raw = wpagent_acpt_expected_raw( $kind, $raw );
		if ( is_wp_error( $current_raw ) || is_wp_error( $expected_raw ) || ! hash_equals( wpagent_acpt_hash( $expected_raw ), wpagent_acpt_hash( $current_raw ) ) ) {
			$rolled_back = wpagent_acpt_delete_owned_definition( $kind, $slug, $raw['id'], $provider );
			return new WP_Error( 'wpagent_acpt_verify', __( 'ACPT Lite hat die Definition nicht unverändert gespeichert.', 'wp-agent-companion' ), array( 'status' => 500, 'rollback_verified' => $rolled_back ) );
		}
		wpagent_acpt_mark_rewrite_reload();
		$state = wpagent_acpt_state( $kind, $current, 0 );
		if ( is_wp_error( $state ) ) {
			$error_data = $state->get_error_data();
			$state->add_data( array( 'status' => is_array( $error_data ) ? (int) ( $error_data['status'] ?? 500 ) : 500, 'rollback_verified' => wpagent_acpt_delete_owned_definition( $kind, $slug, $raw['id'], $provider ) ) );
			return $state;
		}
		return array( 'model' => $state, 'verified_persistence' => true, 'reload_required' => true );
	} finally {
		wpagent_acpt_release_lock( $lock );
	}
}

/** @return array<string,mixed>|WP_Error */
function wpagent_acpt_update_model( string $kind, $input ) {
	$input = is_array( $input ) ? $input : array();
	$slug = wpagent_acpt_slug( $input['slug'] ?? '', $kind );
	if ( is_wp_error( $slug ) ) { return $slug; }
	$expected_hash = is_string( $input['expected_hash'] ?? null ) ? $input['expected_hash'] : '';
	if ( ! preg_match( '/^[a-f0-9]{64}$/', $expected_hash ) ) {
		return new WP_Error( 'wpagent_acpt_hash', __( 'expected_hash ist ungültig.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$changes = wpagent_acpt_validate_changes( $kind, $input, false );
	if ( is_wp_error( $changes ) ) { return $changes; }
	$lock = wpagent_acpt_acquire_lock();
	if ( is_wp_error( $lock ) ) { return $lock; }
	try {
		$current = wpagent_acpt_model( $kind, $slug );
		if ( is_wp_error( $current ) ) { return $current; }
		$before = wpagent_acpt_raw_model( $kind, $current );
		if ( is_wp_error( $before ) ) { return $before; }
			if ( ! hash_equals( wpagent_acpt_hash( $before ), $expected_hash ) ) {
				return new WP_Error( 'wpagent_acpt_conflict', __( 'Die ACPT-Lite-Definition wurde seit dem Lesen geändert. Lade den aktuellen Zustand neu.', 'wp-agent-companion' ), array( 'status' => 409 ) );
			}
			if ( array_key_exists( 'rewrite_slug', $changes ) ) {
				$rewrite_path = '' !== $changes['rewrite_slug'] ? $changes['rewrite_slug'] : $slug;
				$rewrite_status = wpagent_acpt_validate_rewrite_path( $rewrite_path, $kind, $slug );
				if ( is_wp_error( $rewrite_status ) ) { return $rewrite_status; }
			}
			$after = wpagent_acpt_apply_changes( $kind, $before, $changes );
		$after = wpagent_acpt_refresh_default_labels( $kind, $before, $after );
		if ( is_wp_error( $after ) ) { return $after; }
		$saved = wpagent_acpt_save_raw( $kind, $after );
		if ( is_wp_error( $saved ) ) {
			$error_data = $saved->get_error_data();
			$saved->add_data( array( 'status' => is_array( $error_data ) ? (int) ( $error_data['status'] ?? 500 ) : 500, 'rollback_verified' => wpagent_acpt_restore_raw( $kind, $before ) ) );
			return $saved;
		}
		do_action( 'wpagent_acpt_after_write', $kind, $slug, 'update' );
		$reloaded = wpagent_acpt_model( $kind, $slug );
		$reloaded_raw = is_wp_error( $reloaded ) ? $reloaded : wpagent_acpt_raw_model( $kind, $reloaded );
		$expected_raw = wpagent_acpt_expected_raw( $kind, $after );
		if ( is_wp_error( $reloaded_raw ) || is_wp_error( $expected_raw ) || ! hash_equals( wpagent_acpt_hash( $expected_raw ), wpagent_acpt_hash( $reloaded_raw ) ) ) {
			$rollback_verified = wpagent_acpt_restore_raw( $kind, $before );
			return new WP_Error( 'wpagent_acpt_verify', __( 'ACPT Lite hat den aktualisierten Zustand nicht unverändert gespeichert.', 'wp-agent-companion' ), array( 'status' => 500, 'rollback_verified' => $rollback_verified ) );
		}
		wpagent_acpt_mark_rewrite_reload();
		$state = wpagent_acpt_state( $kind, $reloaded );
		if ( is_wp_error( $state ) ) {
			$error_data = $state->get_error_data();
			$state->add_data( array( 'status' => is_array( $error_data ) ? (int) ( $error_data['status'] ?? 500 ) : 500, 'rollback_verified' => wpagent_acpt_restore_raw( $kind, $before ) ) );
			return $state;
		}
		return array( 'model' => $state, 'verified_persistence' => true, 'reload_required' => true );
	} finally {
		wpagent_acpt_release_lock( $lock );
	}
}

/** @return array<string,mixed>|WP_Error */
function wpagent_acpt_delete_model( string $kind, $input ) {
	$provider = wpagent_acpt_provider();
	if ( is_wp_error( $provider ) ) { return $provider; }
	$input = is_array( $input ) ? $input : array();
	$slug = wpagent_acpt_slug( $input['slug'] ?? '', $kind );
	if ( is_wp_error( $slug ) ) { return $slug; }
	$expected_hash = is_string( $input['expected_hash'] ?? null ) ? $input['expected_hash'] : '';
	if ( ! preg_match( '/^[a-f0-9]{64}$/', $expected_hash ) ) {
		return new WP_Error( 'wpagent_acpt_hash', __( 'expected_hash ist ungültig.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	if ( true !== ( $input['confirm'] ?? false ) ) {
		return new WP_Error( 'wpagent_acpt_confirm', __( 'Zum Löschen muss confirm ausdrücklich true sein.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$lock = wpagent_acpt_acquire_lock();
	if ( is_wp_error( $lock ) ) { return $lock; }
	try {
		$model = wpagent_acpt_model( $kind, $slug );
		if ( is_wp_error( $model ) ) { return $model; }
		$before = wpagent_acpt_raw_model( $kind, $model );
		if ( is_wp_error( $before ) ) { return $before; }
		if ( ! hash_equals( wpagent_acpt_hash( $before ), $expected_hash ) ) {
			return new WP_Error( 'wpagent_acpt_conflict', __( 'Die ACPT-Lite-Definition wurde seit dem Lesen geändert. Lade den aktuellen Zustand neu.', 'wp-agent-companion' ), array( 'status' => 409 ) );
		}
		$state = wpagent_acpt_state( $kind, $model );
		if ( is_wp_error( $state ) ) { return $state; }
		if ( $state['meta_group_links'] > 0 ) {
			return new WP_Error( 'wpagent_acpt_dependencies', __( 'Die Definition ist mit ACPT-Lite-Metafeldern verknüpft und wird deshalb nicht gelöscht.', 'wp-agent-companion' ), array( 'status' => 409 ) );
		}
		if ( $state['content_count'] > 0 && true !== ( $input['confirm_content'] ?? false ) ) {
			return new WP_Error( 'wpagent_acpt_content', __( 'Die Definition besitzt gespeicherte Inhalte. Bestätige ihren Erhalt zusätzlich mit confirm_content.', 'wp-agent-companion' ), array( 'status' => 409 ) );
		}
		$repository = 'post_type' === $kind ? $provider['post_repository'] : $provider['tax_repository'];
		try {
			'post_type' === $kind ? $repository::delete( $slug, false ) : $repository::delete( $slug );
		} catch ( Throwable $error ) {
			return new WP_Error( 'wpagent_acpt_delete', __( 'ACPT Lite konnte die Definition nicht löschen.', 'wp-agent-companion' ), array( 'status' => 500, 'rollback_verified' => wpagent_acpt_restore_raw( $kind, $before ) ) );
		}
		$cache = wpagent_acpt_flush_provider_cache( $provider );
		if ( is_wp_error( $cache ) ) {
			$cache->add_data( array( 'status' => 500, 'rollback_verified' => wpagent_acpt_restore_raw( $kind, $before ) ) );
			return $cache;
		}
			$deleted_state = wpagent_acpt_model( $kind, $slug );
			if ( ! wpagent_acpt_is_not_found_error( $deleted_state ) ) {
				return new WP_Error( 'wpagent_acpt_delete', __( 'ACPT Lite hat die Definition nach dem Löschen weiter ausgeliefert.', 'wp-agent-companion' ), array( 'status' => 500, 'rollback_verified' => wpagent_acpt_restore_raw( $kind, $before ) ) );
			}
		wpagent_acpt_mark_rewrite_reload();
		return array( 'deleted' => true, 'slug' => $slug, 'retained_content' => $state['content_count'], 'verified_persistence' => true, 'reload_required' => true );
	} finally {
		wpagent_acpt_release_lock( $lock );
	}
}

function wpagent_exec_create_acpt_post_type( $input ) { return wpagent_acpt_create_model( 'post_type', $input ); }
function wpagent_exec_update_acpt_post_type( $input ) { return wpagent_acpt_update_model( 'post_type', $input ); }
function wpagent_exec_delete_acpt_post_type( $input ) { return wpagent_acpt_delete_model( 'post_type', $input ); }
function wpagent_exec_create_acpt_taxonomy( $input ) { return wpagent_acpt_create_model( 'taxonomy', $input ); }
function wpagent_exec_update_acpt_taxonomy( $input ) { return wpagent_acpt_update_model( 'taxonomy', $input ); }
function wpagent_exec_delete_acpt_taxonomy( $input ) { return wpagent_acpt_delete_model( 'taxonomy', $input ); }
