<?php
/** Shared state, schemas and transformations for the GeneratePress bridge. */

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

define( 'WPAGENT_GENERATEPRESS_LOCK_OPTION', 'wp_agent_generatepress_settings_lock' );
define( 'WPAGENT_GENERATEPRESS_LOCK_TTL', 300 );
define( 'WPAGENT_GENERATEPRESS_MAX_OPTION_BYTES', 2097152 );
define( 'WPAGENT_GENERATEPRESS_MAX_ITEMS', 5000 );

/** @return array<string,mixed> */
function wpagent_generatepress_layout_schema(): array {
	$sidebar = array( 'type' => 'string', 'enum' => array( 'left-sidebar', 'right-sidebar', 'no-sidebar', 'both-sidebars', 'both-left', 'both-right' ) );
	return array(
		'type'                 => 'object',
		'properties'           => array(
			'container_width'      => array( 'type' => 'integer', 'minimum' => 700, 'maximum' => 2000 ),
			'content_layout'       => array( 'type' => 'string', 'enum' => array( 'separate-containers', 'one-container' ) ),
			'sidebar_layout'       => $sidebar,
			'blog_sidebar_layout'  => $sidebar,
			'single_sidebar_layout' => $sidebar,
			'footer_widgets'       => array( 'type' => 'integer', 'minimum' => 0, 'maximum' => 5 ),
		),
		'minProperties'        => 1,
		'additionalProperties' => false,
	);
}

/** @return array<string,mixed> */
function wpagent_generatepress_color_schema( bool $allow_empty = true ): array {
	return array( 'type' => 'string', 'minLength' => $allow_empty ? 0 : 1, 'maxLength' => 64 );
}

/** @return array<string,mixed> */
function wpagent_generatepress_surface_schema(): array {
	$properties = array();
	foreach ( wpagent_generatepress_surface_keys() as $key ) {
		$properties[ $key ] = wpagent_generatepress_color_schema();
	}
	return array( 'type' => 'object', 'properties' => $properties, 'minProperties' => 1, 'additionalProperties' => false );
}

/** @return array<string,mixed> */
function wpagent_generatepress_buttons_schema(): array {
	$color = wpagent_generatepress_color_schema();
	return array(
		'type'                 => 'object',
		'properties'           => array( 'background' => $color, 'background_hover' => $color, 'text' => $color, 'text_hover' => $color ),
		'minProperties'        => 1,
		'additionalProperties' => false,
	);
}

/** @return array<string,mixed> */
function wpagent_generatepress_palette_schema(): array {
	return array(
		'type'                 => 'object',
		'properties'           => array(
			'colors' => array(
				'type'     => 'array',
				'minItems' => 1,
				'maxItems' => 20,
				'items'    => array(
					'type'                 => 'object',
					'properties'           => array(
						'slug'  => array( 'type' => 'string', 'pattern' => '^[a-z0-9](?:[a-z0-9 -]{0,38}[a-z0-9])?$' ),
						'color' => wpagent_generatepress_color_schema( false ),
					),
					'required'             => array( 'slug', 'color' ),
					'additionalProperties' => false,
				),
			),
		),
		'required'             => array( 'colors' ),
		'additionalProperties' => false,
	);
}

/** @return array<string,mixed> */
function wpagent_generatepress_typography_schema(): array {
	$size = array(
		'type'                 => 'object',
		'properties'           => array(
			'desktop' => array( 'type' => 'number', 'minimum' => 0, 'maximum' => 400 ),
			'tablet'  => array( 'type' => 'number', 'minimum' => 0, 'maximum' => 400 ),
			'mobile'  => array( 'type' => 'number', 'minimum' => 0, 'maximum' => 400 ),
			'unit'    => array( 'type' => 'string', 'enum' => array( 'px', 'em', 'rem', 'vw' ) ),
		),
		'minProperties'        => 1,
		'additionalProperties' => false,
	);
	$line_height = $size;
	$line_height['properties']['desktop']['maximum'] = 10;
	$line_height['properties']['tablet']['maximum']  = 10;
	$line_height['properties']['mobile']['maximum']  = 10;
	$line_height['properties']['unit']['enum']        = array( '', 'em', 'px' );
	return array(
		'type'                 => 'object',
		'properties'           => array(
			'target'         => array( 'type' => 'string', 'enum' => array( 'body', 'h1', 'h2', 'h3', 'buttons' ) ),
			'font_family'    => array( 'type' => 'string', 'minLength' => 1, 'maxLength' => 100 ),
			'font_weight'    => array( 'type' => 'string', 'enum' => array( 'normal', 'bold', '100', '200', '300', '400', '500', '600', '700', '800', '900' ) ),
			'text_transform' => array( 'type' => 'string', 'enum' => array( '', 'none', 'capitalize', 'uppercase', 'lowercase' ) ),
			'font_size'      => $size,
			'line_height'    => $line_height,
		),
		'required'             => array( 'target' ),
		'minProperties'        => 2,
		'additionalProperties' => false,
	);
}

/** @return array<string,array<string,mixed>> */
function wpagent_generatepress_section_schemas(): array {
	return array(
		'layout'         => wpagent_generatepress_layout_schema(),
		'global-colors'  => wpagent_generatepress_palette_schema(),
		'surface-colors' => wpagent_generatepress_surface_schema(),
		'buttons'        => wpagent_generatepress_buttons_schema(),
		'typography'     => wpagent_generatepress_typography_schema(),
	);
}

/** @return string[] */
function wpagent_generatepress_surface_keys(): array {
	return array(
		'background_color', 'text_color', 'link_color', 'link_color_hover',
		'content_background_color', 'content_text_color', 'content_link_color', 'content_link_hover_color',
		'header_background_color', 'site_title_color', 'navigation_background_color', 'navigation_text_color',
	);
}

function wpagent_generatepress_is_active(): bool {
	return 'generatepress' === get_template();
}

function wpagent_generatepress_version(): string {
	$theme = wp_get_theme( 'generatepress' );
	return $theme->exists() ? (string) $theme->get( 'Version' ) : '';
}

function wpagent_generatepress_runtime_ready(): bool {
	return wpagent_generatepress_is_active()
		&& function_exists( 'generate_get_defaults' )
		&& function_exists( 'generate_get_color_defaults' )
		&& function_exists( 'generate_get_dynamic_css' )
		&& function_exists( 'generate_update_dynamic_css_cache' );
}

/** @return array{settings:array{exists:bool,value:array},cache:array<string,array{exists:bool,value:mixed}>}|WP_Error */
function wpagent_generatepress_snapshot() {
	$missing = new stdClass();
	$value   = get_option( 'generate_settings', $missing );
	$exists  = ! ( $value instanceof stdClass );
	if ( $exists && ! is_array( $value ) ) {
		return new WP_Error( 'wpagent_generatepress_invalid_state', __( 'GeneratePress enthält einen ungültigen Einstellungsstand.', 'wp-agent-companion' ), array( 'status' => 502 ) );
	}
	$value = $exists ? $value : array();
	$nodes = 0;
	if ( strlen( maybe_serialize( $value ) ) > WPAGENT_GENERATEPRESS_MAX_OPTION_BYTES || ! wpagent_generatepress_json_safe( $value, 0, $nodes ) ) {
		return new WP_Error( 'wpagent_generatepress_state_too_large', __( 'Der GeneratePress-Einstellungsstand ist zu groß oder ungültig für eine sichere Transaktion.', 'wp-agent-companion' ), array( 'status' => 502 ) );
	}

	$cache = array();
	foreach ( array( 'generate_dynamic_css_output', 'generate_dynamic_css_cached_version' ) as $name ) {
		$cached         = get_option( $name, $missing );
		$cache[ $name ] = array( 'exists' => ! ( $cached instanceof stdClass ), 'value' => $cached instanceof stdClass ? null : $cached );
		if ( ! ( $cached instanceof stdClass ) && strlen( maybe_serialize( $cached ) ) > WPAGENT_GENERATEPRESS_MAX_OPTION_BYTES ) {
			return new WP_Error( 'wpagent_generatepress_cache_too_large', __( 'Der GeneratePress-CSS-Cache ist zu groß für eine sichere Transaktion.', 'wp-agent-companion' ), array( 'status' => 502 ) );
		}
	}
	return array( 'settings' => array( 'exists' => $exists, 'value' => $value ), 'cache' => $cache );
}

function wpagent_generatepress_json_safe( $value, int $depth = 0, int &$nodes = 0 ): bool {
	if ( $depth > 12 || ++$nodes > WPAGENT_GENERATEPRESS_MAX_ITEMS ) {
		return false;
	}
	if ( is_array( $value ) ) {
		foreach ( $value as $key => $child ) {
			if ( ( ! is_int( $key ) && ! is_string( $key ) ) || ! wpagent_generatepress_json_safe( $child, $depth + 1, $nodes ) ) {
				return false;
			}
		}
		return true;
	}
	if ( is_string( $value ) ) {
		return strlen( $value ) <= 65536 && wp_check_invalid_utf8( $value ) === $value && ! preg_match( '/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/', $value );
	}
	return is_null( $value ) || is_bool( $value ) || is_int( $value ) || is_float( $value );
}

/** @param array{settings:array{exists:bool,value:array}} $snapshot */
function wpagent_generatepress_state_hash( array $snapshot ): string {
	$parent   = wp_get_theme( get_template() );
	$child    = wp_get_theme( get_stylesheet() );
	$identity = get_template() . '@' . $parent->get( 'Version' ) . '|' . get_stylesheet() . '@' . $child->get( 'Version' );
	$settings = $snapshot['settings'];
	return hash( 'sha256', $identity . "\0" . ( $settings['exists'] ? '1' : '0' ) . "\0" . maybe_serialize( $settings['value'] ) );
}

/** @param array<string,mixed> $stored @return array<string,mixed> */
function wpagent_generatepress_effective_settings( array $stored ): array {
	return array_replace( generate_get_defaults(), generate_get_color_defaults(), $stored );
}

/** @return array<string,mixed>|WP_Error */
function wpagent_generatepress_read_section( string $section, array $stored ) {
	$effective = wpagent_generatepress_effective_settings( $stored );
	switch ( $section ) {
		case 'layout':
			$layout = array(
				'container_width'       => (int) $effective['container_width'],
				'content_layout'        => (string) $effective['content_layout_setting'],
				'sidebar_layout'        => (string) $effective['layout_setting'],
				'blog_sidebar_layout'   => (string) $effective['blog_layout_setting'],
				'single_sidebar_layout' => (string) $effective['single_layout_setting'],
				'footer_widgets'        => (int) $effective['footer_widget_setting'],
			);
			$valid = rest_validate_value_from_schema( $layout, wpagent_generatepress_layout_schema(), 'layout' );
			if ( is_wp_error( $valid ) ) {
				return new WP_Error( 'wpagent_generatepress_invalid_provider_state', __( 'GeneratePress enthält einen ungültigen Einstellungsstand.', 'wp-agent-companion' ), array( 'status' => 502 ) );
			}
			return $layout;
		case 'global-colors':
			return wpagent_generatepress_read_palette( $effective['global_colors'] ?? array() );
		case 'surface-colors':
			$result = array();
			foreach ( wpagent_generatepress_surface_keys() as $key ) {
				$color = wpagent_generatepress_safe_provider_color( $effective[ $key ] ?? '', true );
				if ( is_wp_error( $color ) ) {
					return $color;
				}
				$result[ $key ] = $color;
			}
			return $result;
		case 'buttons':
			$result = array();
			foreach ( array( 'background' => 'form_button_background_color', 'background_hover' => 'form_button_background_color_hover', 'text' => 'form_button_text_color', 'text_hover' => 'form_button_text_color_hover' ) as $public => $provider ) {
				$color = wpagent_generatepress_safe_provider_color( $effective[ $provider ] ?? '', true );
				if ( is_wp_error( $color ) ) {
					return $color;
				}
				$result[ $public ] = $color;
			}
			return $result;
		case 'typography':
			return wpagent_generatepress_read_typography( $effective['typography'] ?? array() );
	}
	return new WP_Error( 'wpagent_generatepress_unknown_section', __( 'Unbekannter GeneratePress-Designbereich.', 'wp-agent-companion' ), array( 'status' => 400 ) );
}

/** @return string|WP_Error */
function wpagent_generatepress_safe_provider_color( $color, bool $allow_empty ) {
	if ( ! is_string( $color ) || strlen( $color ) > 64 ) {
		return new WP_Error( 'wpagent_generatepress_invalid_provider_color', __( 'GeneratePress liefert einen ungültigen Farbwert.', 'wp-agent-companion' ), array( 'status' => 502 ) );
	}
	$color = trim( $color );
	if ( '' === $color && $allow_empty ) {
		return '';
	}
	if ( preg_match( '/^var\(--[a-z0-9](?:[a-z0-9-]{0,38}[a-z0-9])?\)$/', $color ) ) {
		return $color;
	}
	$validated = wpagent_generatepress_validate_color( $color, $allow_empty );
	if ( is_wp_error( $validated ) ) {
		return new WP_Error( 'wpagent_generatepress_invalid_provider_color', __( 'GeneratePress liefert einen ungültigen Farbwert.', 'wp-agent-companion' ), array( 'status' => 502 ) );
	}
	return $validated;
}

/** @return array<int,array{name:string,slug:string,color:string}>|WP_Error */
function wpagent_generatepress_read_palette( $palette ) {
	if ( ! is_array( $palette ) || count( $palette ) > 32 ) {
		return new WP_Error( 'wpagent_generatepress_invalid_palette', __( 'GeneratePress liefert eine ungültige Farbpalette.', 'wp-agent-companion' ), array( 'status' => 502 ) );
	}
	$result = array();
	$seen   = array();
	foreach ( $palette as $item ) {
		if ( ! is_array( $item ) || ! is_string( $item['slug'] ?? null ) || ! is_string( $item['color'] ?? null ) ) {
			return new WP_Error( 'wpagent_generatepress_invalid_palette', __( 'GeneratePress liefert eine ungültige Farbpalette.', 'wp-agent-companion' ), array( 'status' => 502 ) );
		}
		$slug = $item['slug'];
		$name = is_string( $item['name'] ?? null ) ? $item['name'] : $slug;
		$color = wpagent_generatepress_validate_color( $item['color'], false );
		if ( isset( $seen[ $slug ] ) || ! preg_match( '/^[a-z0-9](?:[a-z0-9 -]{0,38}[a-z0-9])?$/', $slug ) || strlen( $name ) > 80 || sanitize_text_field( $name ) !== $name || wp_check_invalid_utf8( $name ) !== $name || is_wp_error( $color ) ) {
			return new WP_Error( 'wpagent_generatepress_invalid_palette', __( 'GeneratePress liefert eine ungültige Farbpalette.', 'wp-agent-companion' ), array( 'status' => 502 ) );
		}
		$seen[ $slug ] = true;
		$result[] = array( 'name' => $name, 'slug' => $slug, 'color' => $color );
	}
	return $result;
}

/** @return array<int,array<string,mixed>>|WP_Error */
function wpagent_generatepress_read_typography( $typography ) {
	if ( ! is_array( $typography ) || count( $typography ) > 100 ) {
		return new WP_Error( 'wpagent_generatepress_invalid_typography', __( 'GeneratePress liefert ungültige Typografie-Einstellungen.', 'wp-agent-companion' ), array( 'status' => 502 ) );
	}
	$known  = array( 'body', 'h1', 'h2', 'h3', 'buttons' );
	$result = array();
	foreach ( $typography as $entry ) {
		if ( ! is_array( $entry ) || ! in_array( $entry['selector'] ?? '', $known, true ) ) {
			continue;
		}
		$row = array( 'target' => $entry['selector'] );
		foreach ( array( 'fontFamily' => 'font_family', 'fontWeight' => 'font_weight', 'textTransform' => 'text_transform' ) as $provider => $public ) {
			if ( is_string( $entry[ $provider ] ?? null ) && '' !== $entry[ $provider ] ) {
				$value = $entry[ $provider ];
				$valid = true;
				if ( 'fontFamily' === $provider ) {
					$valid = strlen( $value ) <= 100 && sanitize_text_field( $value ) === $value && (bool) preg_match( '/^[\p{L}\p{N}][\p{L}\p{N} ._-]{0,99}$/u', $value );
				} elseif ( 'fontWeight' === $provider ) {
					$valid = in_array( $value, array( 'normal', 'bold', '100', '200', '300', '400', '500', '600', '700', '800', '900' ), true );
				} else {
					$valid = in_array( $value, array( 'none', 'capitalize', 'uppercase', 'lowercase' ), true );
				}
				if ( ! $valid ) {
					return new WP_Error( 'wpagent_generatepress_invalid_provider_state', __( 'GeneratePress enthält einen ungültigen Einstellungsstand.', 'wp-agent-companion' ), array( 'status' => 502 ) );
				}
				$row[ $public ] = $value;
			}
		}
		$size = wpagent_generatepress_read_responsive_numbers( $entry, 'fontSize', 'fontSizeUnit', 400, array( 'px', 'em', 'rem', 'vw' ) );
		if ( is_wp_error( $size ) ) {
			return $size;
		}
		if ( $size ) {
			$row['font_size'] = $size;
		}
		$line = wpagent_generatepress_read_responsive_numbers( $entry, 'lineHeight', 'lineHeightUnit', 10, array( '', 'em', 'px' ) );
		if ( is_wp_error( $line ) ) {
			return $line;
		}
		if ( $line ) {
			$row['line_height'] = $line;
		}
		$result[] = $row;
	}
	usort( $result, static fn( array $left, array $right ): int => array_search( $left['target'], $known, true ) <=> array_search( $right['target'], $known, true ) );
	return $result;
}

/** @param string[] $allowed_units @return array<string,int|float|string>|WP_Error */
function wpagent_generatepress_read_responsive_numbers( array $entry, string $base, string $unit_key, float $maximum, array $allowed_units ) {
	$result = array();
	foreach ( array( 'desktop' => $base, 'tablet' => $base . 'Tablet', 'mobile' => $base . 'Mobile' ) as $public => $provider ) {
		$value = $entry[ $provider ] ?? '';
		if ( '' === $value || null === $value ) {
			continue;
		}
		$number = is_numeric( $value ) ? (float) $value : NAN;
		if ( ! is_finite( $number ) || $number < 0 || $number > $maximum ) {
			return new WP_Error( 'wpagent_generatepress_invalid_provider_state', __( 'GeneratePress enthält einen ungültigen Einstellungsstand.', 'wp-agent-companion' ), array( 'status' => 502 ) );
		}
		$result[ $public ] = $number;
	}
	if ( $result ) {
		$unit = $entry[ $unit_key ] ?? null;
		if ( ! is_string( $unit ) || ! in_array( $unit, $allowed_units, true ) ) {
			return new WP_Error( 'wpagent_generatepress_invalid_provider_state', __( 'GeneratePress enthält einen ungültigen Einstellungsstand.', 'wp-agent-companion' ), array( 'status' => 502 ) );
		}
		$result['unit'] = $unit;
	}
	return $result;
}

/** @return array<string,mixed>|WP_Error */
function wpagent_generatepress_validate_settings( string $section, $settings, array $stored ) {
	$schemas = wpagent_generatepress_section_schemas();
	if ( ! isset( $schemas[ $section ] ) ) {
		return new WP_Error( 'wpagent_generatepress_unknown_section', __( 'Unbekannter GeneratePress-Designbereich.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	if ( ! is_array( $settings ) || ! $settings ) {
		return new WP_Error( 'wpagent_generatepress_no_changes', __( 'Gib mindestens eine zu ändernde GeneratePress-Einstellung an.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$valid = rest_validate_value_from_schema( $settings, $schemas[ $section ], 'settings' );
	if ( is_wp_error( $valid ) ) {
		return new WP_Error( 'wpagent_generatepress_invalid_settings', $valid->get_error_message(), array( 'status' => 400 ) );
	}
	$settings = rest_sanitize_value_from_schema( $settings, $schemas[ $section ], 'settings' );
	if ( is_wp_error( $settings ) || ! is_array( $settings ) ) {
		return new WP_Error( 'wpagent_generatepress_invalid_settings', __( 'Die GeneratePress-Einstellungen sind ungültig.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	if ( 'surface-colors' === $section || 'buttons' === $section ) {
		foreach ( $settings as $key => $color ) {
			$clean = wpagent_generatepress_validate_color( $color, true );
			if ( is_wp_error( $clean ) ) {
				return $clean;
			}
			$settings[ $key ] = $clean;
		}
	}
	if ( 'global-colors' === $section ) {
		$palette = wpagent_generatepress_read_palette( wpagent_generatepress_effective_settings( $stored )['global_colors'] ?? array() );
		if ( is_wp_error( $palette ) ) {
			return $palette;
		}
		$known = array_column( $palette, null, 'slug' );
		$seen  = array();
		foreach ( $settings['colors'] as &$color ) {
			if ( isset( $seen[ $color['slug'] ] ) || ! isset( $known[ $color['slug'] ] ) ) {
				return new WP_Error( 'wpagent_generatepress_unknown_color', __( 'Die Farbpalette darf nur vorhandene, eindeutige GeneratePress-Slugs ändern.', 'wp-agent-companion' ), array( 'status' => 400 ) );
			}
			$seen[ $color['slug'] ] = true;
			$clean = wpagent_generatepress_validate_color( $color['color'], false );
			if ( is_wp_error( $clean ) ) {
				return $clean;
			}
			$color['color'] = $clean;
		}
		unset( $color );
	}
	if ( 'typography' === $section && isset( $settings['font_family'] ) ) {
		$family = trim( $settings['font_family'] );
		if ( sanitize_text_field( $family ) !== $family || ! preg_match( '/^[\p{L}\p{N}][\p{L}\p{N} ._-]{0,99}$/u', $family ) ) {
			return new WP_Error( 'wpagent_generatepress_invalid_font_family', __( 'Der GeneratePress-Fontname enthält nicht erlaubte Zeichen.', 'wp-agent-companion' ), array( 'status' => 400 ) );
		}
		$settings['font_family'] = $family;
	}
	if ( 'typography' === $section ) {
		$target_count = 0;
		$typography   = wpagent_generatepress_effective_settings( $stored )['typography'] ?? array();
		foreach ( is_array( $typography ) ? $typography : array() as $entry ) {
			if ( is_array( $entry ) && ( $entry['selector'] ?? '' ) === $settings['target'] ) {
				++$target_count;
			}
		}
		if ( $target_count > 1 ) {
			return new WP_Error( 'wpagent_generatepress_ambiguous_typography', __( 'GeneratePress enthält mehrere Typografie-Regeln für dieses Ziel. Löse den Konflikt zuerst im Customizer.', 'wp-agent-companion' ), array( 'status' => 409 ) );
		}
	}
	return $settings;
}

/** @return string|WP_Error */
function wpagent_generatepress_validate_color( $color, bool $allow_empty ) {
	$color = is_string( $color ) ? trim( $color ) : '';
	if ( '' === $color && $allow_empty ) {
		return '';
	}
	$valid = (bool) preg_match( '/^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/', $color );
	if ( ! $valid && preg_match( '/^rgba\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(0|1|0?\.\d+)\s*\)$/', $color, $matches ) ) {
		$valid = (int) $matches[1] <= 255 && (int) $matches[2] <= 255 && (int) $matches[3] <= 255 && (float) $matches[4] <= 1;
	}
	if ( ! $valid ) {
		return new WP_Error( 'wpagent_generatepress_invalid_color', __( 'GeneratePress-Farben müssen als Hex oder rgba() angegeben werden.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$clean = function_exists( 'generate_sanitize_rgba_color' ) ? generate_sanitize_rgba_color( $color ) : $color;
	if ( ! is_string( $clean ) || '' === $clean ) {
		return new WP_Error( 'wpagent_generatepress_invalid_color', __( 'GeneratePress hat den Farbwert abgelehnt.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	return $clean;
}

/** @param array<string,mixed> $stored @param array<string,mixed> $settings @return array<string,mixed>|WP_Error */
function wpagent_generatepress_apply_settings( string $section, array $stored, array $settings ) {
	$next = $stored;
	if ( 'layout' === $section ) {
		$map = array(
			'container_width' => 'container_width', 'content_layout' => 'content_layout_setting',
			'sidebar_layout' => 'layout_setting', 'blog_sidebar_layout' => 'blog_layout_setting',
			'single_sidebar_layout' => 'single_layout_setting', 'footer_widgets' => 'footer_widget_setting',
		);
		foreach ( $settings as $key => $value ) {
			$next[ $map[ $key ] ] = (string) $value;
		}
		return $next;
	}
	if ( 'surface-colors' === $section ) {
		return array_replace( $next, $settings );
	}
	if ( 'buttons' === $section ) {
		$map = array(
			'background' => 'form_button_background_color', 'background_hover' => 'form_button_background_color_hover',
			'text' => 'form_button_text_color', 'text_hover' => 'form_button_text_color_hover',
		);
		foreach ( $settings as $key => $value ) {
			$next[ $map[ $key ] ] = $value;
		}
		return $next;
	}
	if ( 'global-colors' === $section ) {
		$palette = wpagent_generatepress_effective_settings( $stored )['global_colors'] ?? array();
		$patch   = array_column( $settings['colors'], 'color', 'slug' );
		foreach ( $palette as &$item ) {
			if ( is_array( $item ) && isset( $patch[ $item['slug'] ?? '' ] ) ) {
				$item['color'] = $patch[ $item['slug'] ];
			}
		}
		unset( $item );
		$next['global_colors'] = array_values( $palette );
		return $next;
	}
	if ( 'typography' === $section ) {
		$entries = wpagent_generatepress_effective_settings( $stored )['typography'] ?? array();
		$index   = null;
		foreach ( $entries as $key => $entry ) {
			if ( is_array( $entry ) && ( $entry['selector'] ?? '' ) === $settings['target'] ) {
				$index = $key;
				break;
			}
		}
		if ( null === $index ) {
			$entries[] = array( 'selector' => $settings['target'], 'module' => 'core', 'group' => '' );
			$index     = array_key_last( $entries );
		}
		$entry = $entries[ $index ];
		$map   = array( 'font_family' => 'fontFamily', 'font_weight' => 'fontWeight', 'text_transform' => 'textTransform' );
		foreach ( $map as $public => $provider ) {
			if ( array_key_exists( $public, $settings ) ) {
				$entry[ $provider ] = $settings[ $public ];
			}
		}
		if ( isset( $settings['font_size'] ) ) {
			$entry = wpagent_generatepress_apply_responsive_numbers( $entry, $settings['font_size'], 'fontSize', 'fontSizeUnit' );
		}
		if ( isset( $settings['line_height'] ) ) {
			$entry = wpagent_generatepress_apply_responsive_numbers( $entry, $settings['line_height'], 'lineHeight', 'lineHeightUnit' );
		}
		$entries[ $index ] = $entry;
		$next['typography'] = array_values( $entries );
		return $next;
	}
	return new WP_Error( 'wpagent_generatepress_unknown_section', __( 'Unbekannter GeneratePress-Designbereich.', 'wp-agent-companion' ), array( 'status' => 400 ) );
}

/** @param array<string,mixed> $entry @param array<string,mixed> $values @return array<string,mixed> */
function wpagent_generatepress_apply_responsive_numbers( array $entry, array $values, string $base, string $unit_key ): array {
	foreach ( array( 'desktop' => $base, 'tablet' => $base . 'Tablet', 'mobile' => $base . 'Mobile' ) as $public => $provider ) {
		if ( array_key_exists( $public, $values ) ) {
			$entry[ $provider ] = (string) $values[ $public ];
		}
	}
	if ( array_key_exists( 'unit', $values ) ) {
		$entry[ $unit_key ] = $values['unit'];
	}
	return $entry;
}
