<?php
/** Versionierte, builder-unabhängige Designrichtungen. */

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

/** @return string|WP_Error */
function wpagent_design_direction_lock() {
	return wpagent_state_acquire_scoped_lock( 'design-directions' );
}

function wpagent_design_direction_unlock( string $token ): void {
	wpagent_state_release_scoped_lock( 'design-directions', $token );
}

/** @return array<string,mixed> */
function wpagent_design_direction_summary_schema(): array {
	return array(
		'type'       => 'object',
		'properties' => array(
			'id' => array( 'type' => 'string', 'maxLength' => 64 ), 'title' => array( 'type' => 'string', 'maxLength' => 150 ), 'summary' => array( 'type' => 'string', 'maxLength' => 1000 ),
			'version' => array( 'type' => 'integer', 'minimum' => 1 ), 'active' => array( 'type' => 'boolean' ), 'updated_at' => array( 'type' => 'string', 'maxLength' => 100 ),
		), 'additionalProperties' => false,
	);
}

/** @return array<string,mixed> */
function wpagent_design_direction_schema(): array {
	$schema = wpagent_design_direction_summary_schema();
	$schema['properties']['voice'] = array( 'type' => 'string', 'maxLength' => 2000 );
	$schema['properties']['rules'] = array( 'type' => 'array', 'maxItems' => 20, 'items' => array( 'type' => 'string', 'maxLength' => 300 ) );
	$schema['properties']['avoid'] = array( 'type' => 'array', 'maxItems' => 20, 'items' => array( 'type' => 'string', 'maxLength' => 300 ) );
	$schema['properties']['profile'] = wpagent_design_profile_schema();
	$schema['properties']['preview'] = array(
		'type'       => 'object',
		'properties' => array(
			'variables' => array( 'type' => 'object', 'maxProperties' => 64, 'additionalProperties' => array( 'type' => 'string', 'maxLength' => 100 ) ),
			'warnings' => array( 'type' => 'array', 'maxItems' => 8, 'items' => array( 'type' => 'string', 'maxLength' => 300 ) ),
			'passes' => array( 'type' => 'boolean' ),
		),
		'additionalProperties' => false,
	);
	return $schema;
}

/** @return array<string,mixed> */
function wpagent_ability_list_design_directions(): array {
	return array(
		'label' => __( 'Designrichtungen auflisten', 'wp-agent-companion' ), 'description' => __( 'Listet gespeicherte Designrichtungen kompakt und markiert die aktive Fassung.', 'wp-agent-companion' ), 'category' => 'wp-agent',
		'input_schema' => array( 'type' => 'object', 'properties' => array(), 'additionalProperties' => false, 'default' => array() ),
		'output_schema' => array( 'type' => 'object', 'properties' => array( 'items' => array( 'type' => 'array', 'maxItems' => 20, 'items' => wpagent_design_direction_summary_schema() ), 'total' => array( 'type' => 'integer', 'maximum' => 20 ), 'state_hash' => array( 'type' => 'string', 'pattern' => '^[a-f0-9]{64}$' ) ), 'additionalProperties' => false ),
		'execute_callback' => 'wpagent_exec_list_design_directions', 'permission_callback' => 'wpagent_perm_edit_posts',
		'meta' => array(
			'show_in_rest' => true,
			'annotations'  => array( 'readonly' => true, 'destructive' => false, 'idempotent' => true ),
			'mcp'          => array(
				'uri'         => 'wpagently://site/design-directions',
				'annotations' => array( 'audience' => array( 'assistant' ) ),
			),
		),
	);
}

/** @return array<string,mixed> */
function wpagent_ability_get_design_direction(): array {
	return wpagent_design_direction_ability( __( 'Designrichtung lesen', 'wp-agent-companion' ), 'wpagent_exec_get_design_direction', true, array( 'id' => array( 'type' => 'string', 'maxLength' => 64 ) ), array( 'direction' => wpagent_design_direction_schema(), 'state_hash' => array( 'type' => 'string', 'pattern' => '^[a-f0-9]{64}$' ) ), array( 'id' ) );
}

/** @return array<string,mixed> */
function wpagent_ability_upsert_design_direction(): array {
	return wpagent_design_direction_ability(
		__( 'Designrichtung speichern', 'wp-agent-companion' ),
		'wpagent_exec_upsert_design_direction',
		false,
		array(
			'id' => array( 'type' => 'string', 'maxLength' => 64 ), 'title' => array( 'type' => 'string', 'maxLength' => 150 ), 'summary' => array( 'type' => 'string', 'maxLength' => 1000 ), 'voice' => array( 'type' => 'string', 'maxLength' => 2000 ),
			'rules' => array( 'type' => 'array', 'maxItems' => 20, 'items' => array( 'type' => 'string', 'maxLength' => 300 ) ), 'avoid' => array( 'type' => 'array', 'maxItems' => 20, 'items' => array( 'type' => 'string', 'maxLength' => 300 ) ),
			'profile' => wpagent_design_profile_schema(), 'source' => array( 'type' => 'string', 'maxLength' => 30000 ), 'expected_version' => array( 'type' => 'integer', 'minimum' => 0 ), 'expected_state_hash' => array( 'type' => 'string', 'pattern' => '^[a-f0-9]{64}$' ),
		),
		array( 'direction' => wpagent_design_direction_schema(), 'verified' => array( 'type' => 'boolean' ), 'state_hash' => array( 'type' => 'string', 'pattern' => '^[a-f0-9]{64}$' ) ),
		array( 'id', 'title', 'expected_state_hash' ),
		false,
		false
	);
}

/** @return array<string,mixed> */
function wpagent_ability_activate_design_direction(): array {
	return wpagent_design_direction_ability(
		__( 'Designrichtung aktivieren', 'wp-agent-companion' ), 'wpagent_exec_activate_design_direction', false,
		array( 'id' => array( 'type' => 'string', 'maxLength' => 64 ), 'expected_version' => array( 'type' => 'integer', 'minimum' => 1 ), 'approve_warnings' => array( 'type' => 'boolean', 'default' => false ), 'expected_state_hash' => array( 'type' => 'string', 'pattern' => '^[a-f0-9]{64}$' ) ),
		array( 'direction' => wpagent_design_direction_schema(), 'verified' => array( 'type' => 'boolean' ), 'state_hash' => array( 'type' => 'string', 'pattern' => '^[a-f0-9]{64}$' ) ), array( 'id', 'expected_version', 'expected_state_hash' )
	);
}

/** @return array<string,mixed> */
function wpagent_ability_delete_design_direction(): array {
	return wpagent_design_direction_ability(
		__( 'Designrichtung löschen', 'wp-agent-companion' ), 'wpagent_exec_delete_design_direction', false,
		array( 'id' => array( 'type' => 'string', 'maxLength' => 64 ), 'expected_version' => array( 'type' => 'integer', 'minimum' => 1 ), 'expected_state_hash' => array( 'type' => 'string', 'pattern' => '^[a-f0-9]{64}$' ) ),
		array( 'id' => array( 'type' => 'string', 'maxLength' => 64 ), 'deleted' => array( 'type' => 'boolean' ), 'state_hash' => array( 'type' => 'string', 'pattern' => '^[a-f0-9]{64}$' ) ), array( 'id', 'expected_version', 'expected_state_hash' ), true
	);
}

/** @return array<string,mixed> */
function wpagent_design_direction_ability( string $label, string $callback, bool $readonly, array $input, array $output, array $required = array(), bool $destructive = false, bool $idempotent = true ): array {
	$input_schema = array( 'type' => 'object', 'properties' => $input, 'additionalProperties' => false );
	if ( $required ) {
		$input_schema['required'] = $required;
	}
	return array(
		'label' => $label, 'description' => __( 'Verwaltet versionierte Designrichtungen aus validierten Profilen oder sicheren Schriftimporten.', 'wp-agent-companion' ), 'category' => 'wp-agent',
		'input_schema' => $input_schema, 'output_schema' => array( 'type' => 'object', 'properties' => $output, 'additionalProperties' => false ),
		'execute_callback' => $callback, 'permission_callback' => $readonly ? 'wpagent_perm_edit_posts' : 'wpagent_perm_manage_options',
		'meta' => array( 'show_in_rest' => true, 'annotations' => array( 'readonly' => $readonly, 'destructive' => $destructive, 'idempotent' => $readonly && $idempotent ) ),
	);
}

/** @return string[]|WP_Error */
function wpagent_design_direction_text_list( $value, string $field ) {
	if ( ! is_array( $value ) ) {
		return new WP_Error( 'wpagent_design_direction_bad_rules', __( 'Designregeln müssen als Liste übergeben werden.', 'wp-agent-companion' ), array( 'status' => 400, 'field' => $field ) );
	}
	if ( count( $value ) > 20 ) {
		return new WP_Error( 'wpagent_design_direction_rule_limit', __( 'Eine Designrichtung darf höchstens 20 Regeln pro Liste enthalten.', 'wp-agent-companion' ), array( 'status' => 400, 'field' => $field ) );
	}
	$result = array();
	foreach ( $value as $item ) {
		$text = wpagent_state_text( $item, 300, $field );
		if ( is_wp_error( $text ) ) {
			return $text;
		}
		if ( '' !== $text ) {
			$result[] = $text;
		}
	}
	return array_values( array_unique( $result ) );
}

/** @param array<string,mixed> $direction @return array<string,mixed> */
function wpagent_design_direction_preview( array $direction ): array {
	$profile   = $direction['profile'];
	$variables = array();
	foreach ( array( 'colors' => 'color', 'spacing' => 'space', 'radius' => 'radius' ) as $field => $prefix ) {
		foreach ( $profile[ $field ] as $slug => $value ) {
			$variables[ '--wpagently-' . $prefix . '-' . sanitize_key( $slug ) ] = $value;
		}
	}
	if ( '' !== $profile['base_size'] ) {
		$variables['--wpagently-base-size'] = $profile['base_size'];
	}
	if ( ! empty( $profile['font_families'][0] ) ) {
		$variables['--wpagently-font-primary'] = $profile['font_families'][0];
		$variables['--wpagently-font-heading'] = $profile['font_families'][0];
	}
	if ( ! empty( $profile['font_families'][1] ) ) {
		$variables['--wpagently-font-body'] = $profile['font_families'][1];
	}
	$warnings = array();
	if ( empty( $profile['font_families'] ) ) {
		$warnings[] = __( 'Keine primäre Schriftfamilie festgelegt.', 'wp-agent-companion' );
	} elseif ( count( $profile['font_families'] ) < 2 ) {
		$warnings[] = __( 'Keine separate Schriftfamilie für Fließtext festgelegt.', 'wp-agent-companion' );
	}
	if ( count( $profile['colors'] ) > 8 ) {
		$warnings[] = __( 'Mehr als acht Farben erhöhen das Risiko einer inkonsistenten Oberfläche.', 'wp-agent-companion' );
	}
	if ( '' === $direction['voice'] ) {
		$warnings[] = __( 'Die Tonalität ist nicht festgelegt.', 'wp-agent-companion' );
	}
	if ( empty( $direction['rules'] ) ) {
		$warnings[] = __( 'Es fehlen positive Gestaltungsregeln.', 'wp-agent-companion' );
	}
	if ( empty( $direction['avoid'] ) ) {
		$warnings[] = __( 'Es fehlen ausdrücklich zu vermeidende Gestaltungsmuster.', 'wp-agent-companion' );
	}
	return array( 'variables' => (object) $variables, 'warnings' => $warnings, 'passes' => empty( $warnings ) );
}

function wpagent_design_direction_import_font_role( string $label ): string {
	$label = strtolower( remove_accents( $label ) );
	$label = preg_replace( '/[^a-z0-9]+/', '', $label );
	if ( ! is_string( $label ) || '' === $label ) {
		return '';
	}
	if ( preg_match( '/(?:fontsize|fontweight|fontstyle|lineheight|letterspacing|textstyle)/', $label ) ) {
		return '';
	}
	if ( ! preg_match( '/(?:font|typeface|schrift)/', $label ) ) {
		return '';
	}
	if ( preg_match( '/(?:heading|headings|headline|display|title|h1|uberschrift|uberschriften|ueberschrift|ueberschriften|titel)/', $label ) ) {
		return 'heading';
	}
	if ( preg_match( '/(?:body|bodytext|paragraph|copy|content|base|fliesstext|fliesztext|grundschrift)/', $label ) ) {
		return 'body';
	}
	return '';
}

/** @return string|WP_Error */
function wpagent_design_direction_import_font_value( string $value ) {
	$value = trim( preg_replace( '/\s*!important\s*$/i', '', $value ) ?? $value );
	$value = trim( $value, " \t\n\r\0\x0B`*_" );
	if ( preg_match( '/(?:var|url|calc|min|max|clamp)\s*\(/i', $value ) ) {
		return new WP_Error( 'wpagent_design_direction_bad_import_font', __( 'Importierte Schriften müssen als literale Schriftfamilien statt als dynamische CSS-Ausdrücke vorliegen.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$font = wpagent_design_font_family_value( $value );
	if ( is_wp_error( $font ) || '' === $font ) {
		return new WP_Error( 'wpagent_design_direction_bad_import_font', __( 'Eine importierte Schriftfamilie enthält ungültige CSS-Syntax.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	return $font;
}

/** @return array{heading:string,body:string}|WP_Error */
function wpagent_design_direction_import_font_pair( string $source ) {
	$candidates        = array( 'heading' => array(), 'body' => array() );
	$important         = array( 'heading' => array(), 'body' => array() );
	$label_candidates = array( 'heading' => array(), 'body' => array() );
	$css_source = preg_replace( '!/\*.*?\*/!s', '', $source );
	$css_source = is_string( $css_source ) ? $css_source : $source;
	if ( preg_match_all( '/(?:^|[;{\r\n])\s*--([a-z0-9_-]{1,120})\s*:\s*([^;{}\r\n]{1,200}?)\s*(?:;|(?=\s*(?:}|$)))/imu', $css_source, $matches, PREG_SET_ORDER ) ) {
		foreach ( array_slice( $matches, 0, 100 ) as $match ) {
			$role = wpagent_design_direction_import_font_role( (string) $match[1] );
			if ( '' !== $role ) {
				if ( preg_match( '/\s*!important\s*$/i', (string) $match[2] ) ) {
					array_unshift( $important[ $role ], (string) $match[2] );
				} else {
					array_unshift( $candidates[ $role ], (string) $match[2] );
				}
			}
		}
	}

	foreach ( preg_split( '/\r\n|\r|\n/', $source ) ?: array() as $line ) {
		$line = preg_replace( '/^\s*(?:[-+*]|\d+[.)])\s*/', '', $line );
		if (
			! is_string( $line )
			|| str_contains( $line, '{' )
			|| str_contains( $line, '}' )
			|| str_contains( $line, ';' )
			|| ! preg_match( '/^(.{1,120}?)\s*[:=]\s*(.{1,200})$/u', trim( $line ), $match )
		) {
			continue;
		}
		$role = wpagent_design_direction_import_font_role( (string) $match[1] );
		if ( '' !== $role ) {
			array_unshift( $label_candidates[ $role ], (string) $match[2] );
		}
	}

	$result = array();
	foreach ( array( 'heading', 'body' ) as $role ) {
		$role_candidates = ! empty( $label_candidates[ $role ] )
			? $label_candidates[ $role ]
			: ( ! empty( $important[ $role ] ) ? $important[ $role ] : $candidates[ $role ] );
		if ( empty( $role_candidates ) ) {
			return new WP_Error( 'wpagent_design_direction_import_font_pair_required', __( 'Der Import muss je eine Schriftfamilie für Überschriften und Fließtext enthalten.', 'wp-agent-companion' ), array( 'status' => 400 ) );
		}
		$value = wpagent_design_direction_import_font_value( $role_candidates[0] );
		if ( is_wp_error( $value ) ) {
			return $value;
		}
		$result[ $role ] = $value;
	}
	return $result;
}

/** @return array<string,mixed>|WP_Error */
function wpagent_design_direction_import_profile( $source, ?array $base_profile = null ) {
	if ( ! is_string( $source ) ) {
		return new WP_Error( 'wpagent_design_direction_bad_import', __( 'Die Designrichtung muss als Text importiert werden.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$length = function_exists( 'mb_strlen' ) ? mb_strlen( $source ) : strlen( $source );
	if ( $length > 30000 ) {
		return new WP_Error( 'wpagent_design_direction_import_too_long', __( 'Ein Designrichtungsimport darf höchstens 30.000 Zeichen enthalten.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$source = trim( wp_check_invalid_utf8( str_replace( "\0", '', $source ), true ) );
	if ( '' === $source ) {
		return new WP_Error( 'wpagent_design_direction_bad_import', __( 'Die importierte Designrichtung darf nicht leer sein.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}

	$profile = null === $base_profile ? wpagent_normalized_design_profile() : $base_profile;
	$decoded = json_decode( $source, true );
	if ( JSON_ERROR_NONE === json_last_error() ) {
		if ( ! is_array( $decoded ) || array_is_list( $decoded ) ) {
			return new WP_Error( 'wpagent_design_direction_bad_import', __( 'Ein JSON-Import muss ein Objekt enthalten.', 'wp-agent-companion' ), array( 'status' => 400 ) );
		}
		$raw_profile = isset( $decoded['profile'] ) ? $decoded['profile'] : $decoded;
		if ( ! is_array( $raw_profile ) || array_is_list( $raw_profile ) ) {
			return new WP_Error( 'wpagent_design_direction_bad_import', __( 'Das importierte Designprofil muss ein Objekt enthalten.', 'wp-agent-companion' ), array( 'status' => 400 ) );
		}
		$imported_fonts = $raw_profile['font_families'] ?? null;
		$font_aliases   = isset( $raw_profile['heading_font'], $raw_profile['body_font'] ) ? $raw_profile : $decoded;
		if ( ! is_array( $imported_fonts ) && isset( $font_aliases['heading_font'], $font_aliases['body_font'] ) ) {
			if ( ! is_string( $font_aliases['heading_font'] ) || ! is_string( $font_aliases['body_font'] ) ) {
				return new WP_Error( 'wpagent_design_direction_bad_import_font', __( 'Importierte Schriftfamilien müssen als Text vorliegen.', 'wp-agent-companion' ), array( 'status' => 400 ) );
			}
			$heading_font = wpagent_design_direction_import_font_value( $font_aliases['heading_font'] );
			$body_font    = wpagent_design_direction_import_font_value( $font_aliases['body_font'] );
			if ( is_wp_error( $heading_font ) ) {
				return $heading_font;
			}
			if ( is_wp_error( $body_font ) ) {
				return $body_font;
			}
			$imported_fonts = array( $heading_font, $body_font );
		}
		if ( ! is_array( $imported_fonts ) || count( $imported_fonts ) < 2 ) {
			return new WP_Error( 'wpagent_design_direction_import_font_pair_required', __( 'Der Import muss je eine Schriftfamilie für Überschriften und Fließtext enthalten.', 'wp-agent-companion' ), array( 'status' => 400 ) );
		}
		foreach ( array( 'colors', 'base_size', 'spacing', 'radius', 'notes' ) as $field ) {
			if ( array_key_exists( $field, $raw_profile ) ) {
				$profile[ $field ] = $raw_profile[ $field ];
			}
		}
		$profile['font_families'] = $imported_fonts;
		$validated = wpagent_validate_design_profile( $profile );
		if ( is_wp_error( $validated ) ) {
			return $validated;
		}
		return $validated;
	}
	if ( preg_match( '/^[\[{]/', $source ) ) {
		return new WP_Error( 'wpagent_design_direction_bad_import', __( 'Der Designrichtungsimport enthält ungültiges JSON.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}

	$fonts = wpagent_design_direction_import_font_pair( $source );
	if ( is_wp_error( $fonts ) ) {
		return $fonts;
	}
	$profile['font_families'] = array_values( array_unique( array_merge( array( $fonts['heading'], $fonts['body'] ), $profile['font_families'] ) ) );
	$profile['font_families'] = array_slice( $profile['font_families'], 0, 10 );
	return wpagent_validate_design_profile( $profile );
}

/** @return array<string,array<string,mixed>> */
function wpagent_normalized_design_directions( ?array $stored = null ): array {
	$directions = array();
	$stored = null === $stored ? wpagent_state_array_option( WPAGENT_COMPANION_OPT_DESIGN_DIRECTIONS ) : $stored;
	foreach ( $stored as $value ) {
		if ( ! is_array( $value ) ) {
			continue;
		}
		$id      = wpagent_state_id( $value['id'] ?? '' );
		$title   = wpagent_state_text( $value['title'] ?? '', 150, 'title' );
		$summary = wpagent_state_text( $value['summary'] ?? '', 1000, 'summary' );
		$voice   = wpagent_state_text( $value['voice'] ?? '', 2000, 'voice' );
		$rules   = wpagent_design_direction_text_list( $value['rules'] ?? array(), 'rules' );
		$avoid   = wpagent_design_direction_text_list( $value['avoid'] ?? array(), 'avoid' );
		$profile = wpagent_validate_design_profile( $value['profile'] ?? array() );
		if ( is_wp_error( $id ) || is_wp_error( $title ) || '' === $title || is_wp_error( $summary ) || is_wp_error( $voice ) || is_wp_error( $rules ) || is_wp_error( $avoid ) || is_wp_error( $profile ) ) {
			continue;
		}
		$directions[ $id ] = array(
			'id' => $id, 'title' => $title, 'summary' => $summary, 'voice' => $voice, 'rules' => $rules, 'avoid' => $avoid, 'profile' => $profile,
			'version' => max( 1, absint( $value['version'] ?? 1 ) ), 'updated_at' => sanitize_text_field( (string) ( $value['updated_at'] ?? '' ) ),
		);
	}
	ksort( $directions, SORT_STRING );
	return $directions;
}

function wpagent_active_design_direction_id(): string {
	$id = (string) get_option( WPAGENT_COMPANION_OPT_ACTIVE_DESIGN_DIRECTION, '' );
	return isset( wpagent_normalized_design_directions()[ $id ] ) ? $id : '';
}

/** @return string|WP_Error */
function wpagent_design_direction_state_hash() {
	return wpagent_state_hash_for_options( array(
		WPAGENT_COMPANION_OPT_DESIGN_DIRECTIONS,
		WPAGENT_COMPANION_OPT_ACTIVE_DESIGN_DIRECTION,
		WPAGENT_COMPANION_OPT_DESIGN_PROFILE,
	) );
}

/** @param array<string,mixed> $direction @return array<string,mixed> */
function wpagent_design_direction_for_output( array $direction ): array {
	$preview             = wpagent_design_direction_preview( $direction );
	$direction['active']  = $direction['id'] === wpagent_active_design_direction_id();
	$direction['profile'] = wpagent_design_profile_for_output( $direction['profile'] );
	$direction['preview'] = $preview;
	return $direction;
}

function wpagent_exec_list_design_directions( $input = array() ): array {
	$items = array();
	foreach ( wpagent_normalized_design_directions() as $direction ) {
		$output = wpagent_design_direction_for_output( $direction );
		$items[] = array_intersect_key( $output, array_flip( array( 'id', 'title', 'summary', 'version', 'active', 'updated_at' ) ) );
	}
	$hash = wpagent_design_direction_state_hash();
	return is_wp_error( $hash ) ? $hash : array( 'items' => $items, 'total' => count( $items ), 'state_hash' => $hash );
}

/** @return array|WP_Error */
function wpagent_exec_get_design_direction( $input ) {
	$id = wpagent_state_id( is_array( $input ) ? ( $input['id'] ?? '' ) : '' );
	if ( is_wp_error( $id ) ) {
		return $id;
	}
	$direction = wpagent_normalized_design_directions()[ $id ] ?? null;
	if ( null === $direction ) {
		return new WP_Error( 'wpagent_design_direction_not_found', __( 'Designrichtung nicht gefunden.', 'wp-agent-companion' ), array( 'status' => 404 ) );
	}
	$hash = wpagent_design_direction_state_hash();
	return is_wp_error( $hash ) ? $hash : array( 'direction' => wpagent_design_direction_for_output( $direction ), 'state_hash' => $hash );
}

/** @return int|WP_Error */
function wpagent_design_direction_expected_version( array $input, int $current ): int|WP_Error {
	if ( ! array_key_exists( 'expected_version', $input ) ) {
		return $current;
	}
	if ( ! is_int( $input['expected_version'] ) && ! ctype_digit( (string) $input['expected_version'] ) ) {
		return new WP_Error( 'wpagent_design_direction_bad_version', __( 'expected_version muss eine nicht negative Ganzzahl sein.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$expected = (int) $input['expected_version'];
	return $expected === $current
		? $expected
		: new WP_Error( 'wpagent_design_direction_conflict', __( 'Die Designrichtung wurde zwischenzeitlich geändert. Lade sie neu und wiederhole die Änderung.', 'wp-agent-companion' ), array( 'status' => 409, 'current_version' => $current ) );
}

/** @return array|WP_Error */
function wpagent_exec_upsert_design_direction( $input ) {
	$input = is_array( $input ) ? $input : array();
	$id = wpagent_state_id( $input['id'] ?? '' );
	if ( is_wp_error( $id ) ) {
		return $id;
	}
	$title = wpagent_state_text( $input['title'] ?? '', 150, 'title' );
	$summary = wpagent_state_text( $input['summary'] ?? '', 1000, 'summary' );
	$voice = wpagent_state_text( $input['voice'] ?? '', 2000, 'voice' );
	$rules = wpagent_design_direction_text_list( $input['rules'] ?? array(), 'rules' );
	$avoid = wpagent_design_direction_text_list( $input['avoid'] ?? array(), 'avoid' );
	$has_source  = array_key_exists( 'source', $input );
	$has_profile = array_key_exists( 'profile', $input );
	if ( $has_source && $has_profile ) {
		return new WP_Error( 'wpagent_design_direction_import_conflict', __( 'Übergib entweder source oder profile, aber nicht beides.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	if ( ! $has_source && ! $has_profile ) {
		return new WP_Error( 'wpagent_design_direction_profile_required', __( 'Übergib entweder ein validiertes profile oder eine importierbare source.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	foreach ( array( $title, $summary, $voice, $rules, $avoid ) as $value ) {
		if ( is_wp_error( $value ) ) {
			return $value;
		}
	}
	if ( '' === $title ) {
		return new WP_Error( 'wpagent_design_direction_missing_title', __( 'Der Titel der Designrichtung darf nicht leer sein.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	return wpagent_state_with_scoped_lock( 'design-directions', static function ( string $lock ) use ( $input, $id, $title, $summary, $voice, $rules, $avoid, $has_source ) {
		$snapshots = array();
		foreach ( array( WPAGENT_COMPANION_OPT_DESIGN_DIRECTIONS, WPAGENT_COMPANION_OPT_ACTIVE_DESIGN_DIRECTION, WPAGENT_COMPANION_OPT_DESIGN_PROFILE ) as $name ) {
			$snapshot = wpagent_state_option_snapshot( $name );
			if ( ! $snapshot['readable'] ) {
				return new WP_Error( 'wpagent_design_direction_persist_failed', __( 'Designrichtung konnte nicht verifiziert gespeichert werden.', 'wp-agent-companion' ), array( 'status' => 500, 'recovery_required' => true ) );
			}
			$snapshots[ $name ] = $snapshot;
		}
		$required = wpagent_state_require_expected_hash( $input, wpagent_state_snapshot_hash( $snapshots ) );
		if ( is_wp_error( $required ) ) { return $required; }
		$base_profile = wpagent_normalized_design_profile( is_array( $snapshots[ WPAGENT_COMPANION_OPT_DESIGN_PROFILE ]['value'] ) ? $snapshots[ WPAGENT_COMPANION_OPT_DESIGN_PROFILE ]['value'] : array() );
		$profile = $has_source ? wpagent_design_direction_import_profile( $input['source'], $base_profile ) : wpagent_validate_design_profile( $input['profile'] ?? array() );
		if ( is_wp_error( $profile ) ) { return $profile; }
		$directions = wpagent_normalized_design_directions( is_array( $snapshots[ WPAGENT_COMPANION_OPT_DESIGN_DIRECTIONS ]['value'] ) ? $snapshots[ WPAGENT_COMPANION_OPT_DESIGN_DIRECTIONS ]['value'] : array() );
		$current = isset( $directions[ $id ] ) ? $directions[ $id ]['version'] : 0;
		if ( $current > 0 && ! array_key_exists( 'expected_version', $input ) ) {
			return new WP_Error( 'wpagent_design_direction_version_required', __( 'Beim Ändern einer bestehenden Designrichtung ist expected_version erforderlich.', 'wp-agent-companion' ), array( 'status' => 409, 'current_version' => $current ) );
		}
		$expected = wpagent_design_direction_expected_version( $input, $current );
		if ( is_wp_error( $expected ) ) {
			return $expected;
		}
		if ( 0 === $current && count( $directions ) >= 20 ) {
			return new WP_Error( 'wpagent_design_direction_limit', __( 'Es können höchstens 20 Designrichtungen gespeichert werden.', 'wp-agent-companion' ), array( 'status' => 400 ) );
		}
		$active_raw = $snapshots[ WPAGENT_COMPANION_OPT_ACTIVE_DESIGN_DIRECTION ]['value'];
		$active = is_string( $active_raw ) && isset( $directions[ $active_raw ] ) ? $active_raw : '';
		$was_active = $id === $active;
		$directions[ $id ] = array(
			'id' => $id, 'title' => $title, 'summary' => $summary, 'voice' => $voice, 'rules' => $rules, 'avoid' => $avoid, 'profile' => $profile,
			'version' => $current + 1, 'updated_at' => wpagent_state_now(),
		);
		$updates = array( WPAGENT_COMPANION_OPT_DESIGN_DIRECTIONS => $directions );
		if ( $was_active ) { $updates[ WPAGENT_COMPANION_OPT_ACTIVE_DESIGN_DIRECTION ] = ''; }
		$persisted = wpagent_state_commit_options( $updates, $snapshots, 'design-directions', $lock, 'wpagent_design_direction_persist_failed', __( 'Designrichtung konnte nicht verifiziert gespeichert werden.', 'wp-agent-companion' ) );
		if ( is_wp_error( $persisted ) ) { return $persisted; }
		$output = wpagent_design_direction_for_output( $directions[ $id ] );
		$output['active'] = false;
		$hash = wpagent_design_direction_state_hash();
		return is_wp_error( $hash ) ? $hash : array( 'direction' => $output, 'verified' => true, 'state_hash' => $hash );
	}, 'wpagent_design_direction_persist_failed', __( 'Designrichtung konnte nicht verifiziert gespeichert werden.', 'wp-agent-companion' ) );
}

/** @return array|WP_Error */
function wpagent_exec_activate_design_direction( $input ) {
	$input = is_array( $input ) ? $input : array();
	$id = wpagent_state_id( $input['id'] ?? '' );
	if ( is_wp_error( $id ) ) {
		return $id;
	}
	return wpagent_state_with_scoped_lock( 'design-directions', static function ( string $lock ) use ( $input, $id ) {
		$snapshots = array();
		foreach ( array( WPAGENT_COMPANION_OPT_DESIGN_DIRECTIONS, WPAGENT_COMPANION_OPT_ACTIVE_DESIGN_DIRECTION, WPAGENT_COMPANION_OPT_DESIGN_PROFILE ) as $name ) {
			$snapshot = wpagent_state_option_snapshot( $name );
			if ( ! $snapshot['readable'] ) {
				return new WP_Error( 'wpagent_design_direction_activate_failed', __( 'Die aktive Designrichtung konnte nicht verifiziert gespeichert werden.', 'wp-agent-companion' ), array( 'status' => 500, 'recovery_required' => true ) );
			}
			$snapshots[ $name ] = $snapshot;
		}
		$required = wpagent_state_require_expected_hash( $input, wpagent_state_snapshot_hash( $snapshots ) );
		if ( is_wp_error( $required ) ) { return $required; }
		$directions = wpagent_normalized_design_directions( is_array( $snapshots[ WPAGENT_COMPANION_OPT_DESIGN_DIRECTIONS ]['value'] ) ? $snapshots[ WPAGENT_COMPANION_OPT_DESIGN_DIRECTIONS ]['value'] : array() );
		if ( ! isset( $directions[ $id ] ) ) {
			return new WP_Error( 'wpagent_design_direction_not_found', __( 'Designrichtung nicht gefunden.', 'wp-agent-companion' ), array( 'status' => 404 ) );
		}
		$expected = wpagent_design_direction_expected_version( $input, $directions[ $id ]['version'] );
		if ( is_wp_error( $expected ) ) {
			return $expected;
		}
		$preview = wpagent_design_direction_preview( $directions[ $id ] );
		if ( ! $preview['passes'] && empty( $input['approve_warnings'] ) ) {
			return new WP_Error( 'wpagent_design_direction_review_required', __( 'Die Designrichtung hat offene Konsistenzwarnungen. Prüfe sie und bestätige sie ausdrücklich.', 'wp-agent-companion' ), array( 'status' => 409, 'warnings' => $preview['warnings'] ) );
		}
		$persisted = wpagent_state_commit_options( array( WPAGENT_COMPANION_OPT_DESIGN_PROFILE => $directions[ $id ]['profile'], WPAGENT_COMPANION_OPT_ACTIVE_DESIGN_DIRECTION => $id ), $snapshots, 'design-directions', $lock, 'wpagent_design_direction_activate_failed', __( 'Die aktive Designrichtung konnte nicht verifiziert gespeichert werden.', 'wp-agent-companion' ) );
		if ( is_wp_error( $persisted ) ) { return $persisted; }
		$output = wpagent_design_direction_for_output( $directions[ $id ] );
		$output['active'] = true;
		$hash = wpagent_design_direction_state_hash();
		return is_wp_error( $hash ) ? $hash : array( 'direction' => $output, 'verified' => true, 'state_hash' => $hash );
	}, 'wpagent_design_direction_activate_failed', __( 'Die aktive Designrichtung konnte nicht verifiziert gespeichert werden.', 'wp-agent-companion' ) );
}

/** @return array|WP_Error */
function wpagent_exec_delete_design_direction( $input ) {
	$input = is_array( $input ) ? $input : array();
	$id = wpagent_state_id( $input['id'] ?? '' );
	if ( is_wp_error( $id ) ) {
		return $id;
	}
	return wpagent_state_with_scoped_lock( 'design-directions', static function ( string $lock ) use ( $input, $id ) {
		$snapshots = array();
		foreach ( array( WPAGENT_COMPANION_OPT_DESIGN_DIRECTIONS, WPAGENT_COMPANION_OPT_ACTIVE_DESIGN_DIRECTION, WPAGENT_COMPANION_OPT_DESIGN_PROFILE ) as $name ) {
			$snapshot = wpagent_state_option_snapshot( $name );
			if ( ! $snapshot['readable'] ) {
				return new WP_Error( 'wpagent_design_direction_persist_failed', __( 'Designrichtung konnte nicht verifiziert gelöscht werden.', 'wp-agent-companion' ), array( 'status' => 500, 'recovery_required' => true ) );
			}
			$snapshots[ $name ] = $snapshot;
		}
		$required = wpagent_state_require_expected_hash( $input, wpagent_state_snapshot_hash( $snapshots ) );
		if ( is_wp_error( $required ) ) { return $required; }
		$directions = wpagent_normalized_design_directions( is_array( $snapshots[ WPAGENT_COMPANION_OPT_DESIGN_DIRECTIONS ]['value'] ) ? $snapshots[ WPAGENT_COMPANION_OPT_DESIGN_DIRECTIONS ]['value'] : array() );
		if ( ! isset( $directions[ $id ] ) ) {
			$hash = wpagent_design_direction_state_hash();
			return is_wp_error( $hash ) ? $hash : array( 'id' => $id, 'deleted' => false, 'state_hash' => $hash );
		}
		$active_raw = $snapshots[ WPAGENT_COMPANION_OPT_ACTIVE_DESIGN_DIRECTION ]['value'];
		if ( is_string( $active_raw ) && $id === $active_raw ) {
			return new WP_Error( 'wpagent_design_direction_active', __( 'Die aktive Designrichtung kann nicht gelöscht werden. Aktiviere zuerst eine andere Richtung.', 'wp-agent-companion' ), array( 'status' => 409 ) );
		}
		if ( ! array_key_exists( 'expected_version', $input ) ) {
			return new WP_Error( 'wpagent_design_direction_version_required', __( 'Beim Ändern einer bestehenden Designrichtung ist expected_version erforderlich.', 'wp-agent-companion' ), array( 'status' => 409, 'current_version' => $directions[ $id ]['version'] ) );
		}
		$expected = wpagent_design_direction_expected_version( $input, $directions[ $id ]['version'] );
		if ( is_wp_error( $expected ) ) {
			return $expected;
		}
		unset( $directions[ $id ] );
		$persisted = wpagent_state_commit_options( array( WPAGENT_COMPANION_OPT_DESIGN_DIRECTIONS => $directions ), $snapshots, 'design-directions', $lock, 'wpagent_design_direction_persist_failed', __( 'Designrichtung konnte nicht verifiziert gelöscht werden.', 'wp-agent-companion' ) );
		if ( is_wp_error( $persisted ) ) { return $persisted; }
		$hash = wpagent_design_direction_state_hash();
		return is_wp_error( $hash ) ? $hash : array( 'id' => $id, 'deleted' => true, 'state_hash' => $hash );
	}, 'wpagent_design_direction_persist_failed', __( 'Designrichtung konnte nicht verifiziert gelöscht werden.', 'wp-agent-companion' ) );
}
