<?php
/** Shared helpers for Elementor's native global colors and typography kit settings. */

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

define( 'WPAGENT_ELEMENTOR_DESIGN_MAX_TOKENS', 100 );
define( 'WPAGENT_ELEMENTOR_DESIGN_MAX_BYTES', 256 * KB_IN_BYTES );

/** @return string[] */
function wpagent_elementor_design_system_ids(): array {
	return array( 'primary', 'secondary', 'text', 'accent' );
}

/** @return object|WP_Error */
function wpagent_elementor_design_active_kit() {
	if ( ! current_user_can( 'manage_options' ) ) {
		return new WP_Error( 'wpagent_forbidden', __( 'Keine Berechtigung.', 'wp-agent-companion' ), array( 'status' => 403 ) );
	}
	if (
		! class_exists( '\\Elementor\\Plugin' )
		|| ! isset( \Elementor\Plugin::$instance->kits_manager )
		|| ! is_object( \Elementor\Plugin::$instance->kits_manager )
		|| ! method_exists( \Elementor\Plugin::$instance->kits_manager, 'get_active_kit' )
	) {
		return wpagent_elementor_unavailable_error();
	}
	try {
		$kit = \Elementor\Plugin::$instance->kits_manager->get_active_kit();
	} catch ( Throwable ) {
		return wpagent_elementor_unavailable_error();
	}
	if (
		! is_object( $kit )
		|| ! method_exists( $kit, 'get_id' )
		|| ! method_exists( $kit, 'get_data' )
		|| ! method_exists( $kit, 'get_settings' )
		|| ! method_exists( $kit, 'get_settings_for_display' )
		|| ! method_exists( $kit, 'save' )
		|| ! method_exists( $kit, 'is_editable_by_current_user' )
		|| absint( $kit->get_id() ) < 1
		|| ! $kit->is_editable_by_current_user()
	) {
		return new WP_Error(
			'wpagent_elementor_design_unavailable',
			__( 'Das aktive Elementor-Kit ist nicht bearbeitbar.', 'wp-agent-companion' ),
			array( 'status' => 409 )
		);
	}
	return $kit;
}

/** @return object|WP_Error */
function wpagent_elementor_design_fresh_kit( int $kit_id ) {
	if (
		! isset( \Elementor\Plugin::$instance->documents )
		|| ! is_object( \Elementor\Plugin::$instance->documents )
		|| ! method_exists( \Elementor\Plugin::$instance->documents, 'get' )
	) {
		return wpagent_elementor_unavailable_error();
	}
	try {
		$kit = \Elementor\Plugin::$instance->documents->get( $kit_id, false );
		if (
			! is_object( $kit )
			|| ! method_exists( $kit, 'get_id' )
			|| ! method_exists( $kit, 'get_data' )
			|| ! method_exists( $kit, 'get_settings' )
			|| ! method_exists( $kit, 'get_settings_for_display' )
			|| ! method_exists( $kit, 'save' )
			|| ! method_exists( $kit, 'is_editable_by_current_user' )
			|| absint( $kit->get_id() ) !== $kit_id
			|| ! $kit->is_editable_by_current_user()
		) {
			return new WP_Error( 'wpagent_elementor_design_unavailable', __( 'Das aktive Elementor-Kit ist nicht bearbeitbar.', 'wp-agent-companion' ), array( 'status' => 409 ) );
		}
	} catch ( Throwable ) {
		return wpagent_elementor_unavailable_error();
	}
	return $kit;
}

/** @return string|WP_Error */
function wpagent_elementor_design_plain_text( $value, int $max_length, string $error_code ) {
	if ( ! is_string( $value ) ) {
		return new WP_Error( $error_code, __( 'Ein Elementor-Designwert hat nicht das erwartete Textformat.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$value = trim( $value );
	if ( '' === $value || strlen( $value ) > $max_length || preg_match( '/[\x00-\x1F\x7F<>]/u', $value ) ) {
		return new WP_Error( $error_code, __( 'Ein Elementor-Designwert enthält ungültige oder zu lange Zeichen.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$sanitized = sanitize_text_field( $value );
	if ( $sanitized !== $value ) {
		return new WP_Error( $error_code, __( 'Ein Elementor-Designwert würde beim Speichern verändert.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	return $value;
}

function wpagent_elementor_design_font_error( string $error_code ): WP_Error {
	return new WP_Error(
		$error_code,
		__( 'Eine Schriftliste enthält nicht erlaubte CSS-Syntax.', 'wp-agent-companion' ),
		array( 'status' => 400 )
	);
}

/** @return string|WP_Error */
function wpagent_elementor_design_font_list( $value, int $max_length, string $error_code, bool $allow_quoted_items = false ) {
	$value = wpagent_elementor_design_plain_text( $value, $max_length, $error_code );
	if ( is_wp_error( $value ) ) {
		return $value;
	}
	if ( ! $allow_quoted_items ) {
		return 1 === preg_match( "/^[\\p{L}\\p{M}\\p{N}\\s,._&+’'\\-]+$/u", $value )
			? $value
			: wpagent_elementor_design_font_error( $error_code );
	}

	$characters = preg_split( '//u', $value, -1, PREG_SPLIT_NO_EMPTY );
	if ( false === $characters ) {
		return wpagent_elementor_design_font_error( $error_code );
	}
	$items = array();
	$current = '';
	$quote = '';
	foreach ( $characters as $character ) {
		if ( '' !== $quote ) {
			$current .= $character;
			if ( $character === $quote ) {
				$quote = '';
			}
			continue;
		}
		if ( '"' === $character || "'" === $character ) {
			$quote = $character;
			$current .= $character;
		} elseif ( ',' === $character ) {
			$items[] = trim( $current );
			$current = '';
		} else {
			$current .= $character;
		}
	}
	$items[] = trim( $current );
	if ( '' !== $quote || count( $items ) > 20 || in_array( '', $items, true ) ) {
		return wpagent_elementor_design_font_error( $error_code );
	}

	foreach ( $items as $item ) {
		$first = $item[0];
		$last = $item[ strlen( $item ) - 1 ];
		if ( '"' === $first || "'" === $first ) {
			if ( $last !== $first || strlen( $item ) < 3 ) {
				return wpagent_elementor_design_font_error( $error_code );
			}
			$content = substr( $item, 1, -1 );
			$pattern = '"' === $first
				? "/^[\\p{L}\\p{M}\\p{N}\\s,._&+’'\\-]+$/u"
				: '/^[\\p{L}\\p{M}\\p{N}\\s,._&+’"\\-]+$/u';
		} else {
			$content = $item;
			$pattern = '/^[\\p{L}\\p{M}\\p{N}\\s._&+’\\-]+$/u';
		}
		if ( 1 !== preg_match( $pattern, $content ) ) {
			return wpagent_elementor_design_font_error( $error_code );
		}
	}
	return $value;
}

/** @return string|WP_Error */
function wpagent_elementor_design_color_value( $value ) {
	if ( ! is_string( $value ) ) {
		return new WP_Error( 'wpagent_elementor_design_bad_color', __( 'Globale Elementor-Farben müssen gültige CSS-Farbwerte sein.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$value = trim( $value );
	if ( preg_match( '/^#(?:[a-f0-9]{3,4}|[a-f0-9]{6}|[a-f0-9]{8})$/i', $value ) || 'transparent' === strtolower( $value ) ) {
		return $value;
	}
	if ( preg_match( '/^rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)$/i', $value, $match ) ) {
		return max( (int) $match[1], (int) $match[2], (int) $match[3] ) <= 255
			? $value
			: new WP_Error( 'wpagent_elementor_design_bad_color', __( 'RGB-Farbkanäle müssen zwischen 0 und 255 liegen.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	if ( preg_match( '/^rgba\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*((?:0(?:\.\d+)?)|(?:1(?:\.0+)?))\s*\)$/i', $value, $match ) ) {
		return max( (int) $match[1], (int) $match[2], (int) $match[3] ) <= 255
			? $value
			: new WP_Error( 'wpagent_elementor_design_bad_color', __( 'RGBA-Farbkanäle müssen zwischen 0 und 255 liegen.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	return new WP_Error(
		'wpagent_elementor_design_bad_color',
		__( 'Erlaubt sind Hex-, RGB-, RGBA- und transparente globale Elementor-Farben.', 'wp-agent-companion' ),
		array( 'status' => 400 )
	);
}

/**
 * @param array<int,mixed> $items
 * @return array<int,array{id:string,title:string,value:string}>|WP_Error
 */
function wpagent_elementor_design_normalize_colors( array $items, bool $system, bool $provider_format = false ) {
	if ( ! array_is_list( $items ) || count( $items ) > WPAGENT_ELEMENTOR_DESIGN_MAX_TOKENS ) {
		return new WP_Error( 'wpagent_elementor_design_bad_colors', __( 'Elementor-Farben müssen eine begrenzte Liste sein.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$normalized = array();
	$seen = array();
	foreach ( $items as $item ) {
		if ( ! is_array( $item ) || array_is_list( $item ) ) {
			return new WP_Error( 'wpagent_elementor_design_bad_colors', __( 'Jede Elementor-Farbe muss ein Objekt sein.', 'wp-agent-companion' ), array( 'status' => 400 ) );
		}
		$id = $provider_format ? ( $item['_id'] ?? null ) : ( $item['id'] ?? null );
		$title = $item['title'] ?? null;
		$value = $provider_format ? ( $item['color'] ?? null ) : ( $item['value'] ?? null );
		if ( ! is_string( $id ) || ! preg_match( '/^[a-z0-9][a-z0-9_-]{0,63}$/', $id ) || isset( $seen[ $id ] ) ) {
			return new WP_Error( 'wpagent_elementor_design_bad_id', __( 'Elementor-Design-IDs müssen eindeutig und sicher formatiert sein.', 'wp-agent-companion' ), array( 'status' => 400 ) );
		}
		if ( ! $system && in_array( $id, wpagent_elementor_design_system_ids(), true ) ) {
			return new WP_Error( 'wpagent_elementor_design_bad_id', __( 'Eigene Elementor-Token dürfen keine System-ID verwenden.', 'wp-agent-companion' ), array( 'status' => 400 ) );
		}
		$title = wpagent_elementor_design_plain_text( $title, 100, 'wpagent_elementor_design_bad_title' );
		if ( is_wp_error( $title ) ) {
			return $title;
		}
		$value = wpagent_elementor_design_color_value( $value );
		if ( is_wp_error( $value ) ) {
			return $value;
		}
		$seen[ $id ] = true;
		$normalized[] = array( 'id' => $id, 'title' => $title, 'value' => $value );
	}
	if ( $system ) {
		$by_id = array_column( $normalized, null, 'id' );
		if ( array_diff( wpagent_elementor_design_system_ids(), array_keys( $by_id ) ) || count( $by_id ) !== 4 ) {
			return new WP_Error( 'wpagent_elementor_design_system_tokens', __( 'Elementors vier System-Token müssen vollständig vorhanden sein.', 'wp-agent-companion' ), array( 'status' => 400 ) );
		}
		$normalized = array_map( static fn( string $id ): array => $by_id[ $id ], wpagent_elementor_design_system_ids() );
	}
	return $normalized;
}

/** @return string[] */
function wpagent_elementor_design_devices(): array {
	$devices = array( 'mobile', 'tablet', 'mobile_extra', 'tablet_extra', 'laptop', 'widescreen' );
	if (
		class_exists( '\\Elementor\\Plugin' )
		&& isset( \Elementor\Plugin::$instance->breakpoints )
		&& is_object( \Elementor\Plugin::$instance->breakpoints )
		&& method_exists( \Elementor\Plugin::$instance->breakpoints, 'get_breakpoints' )
	) {
		try {
			$breakpoints = \Elementor\Plugin::$instance->breakpoints->get_breakpoints();
			if ( is_array( $breakpoints ) ) {
				$devices = array_merge( $devices, array_keys( $breakpoints ) );
			}
		} catch ( Throwable ) {
			// The stable built-in device list remains available.
		}
	}
	return array_values( array_unique( array_filter( $devices, static fn( $item ): bool => is_string( $item ) && preg_match( '/^[a-z][a-z0-9_]{0,31}$/', $item ) ) ) );
}

/** @return string[] */
function wpagent_elementor_design_known_style_keys(): array {
	static $known_keys = null;
	if ( is_array( $known_keys ) ) {
		return $known_keys;
	}
	$keys = array( 'font_family', 'font_weight', 'text_transform', 'font_style', 'text_decoration' );
	foreach ( array( 'font_size', 'line_height', 'letter_spacing', 'word_spacing' ) as $base ) {
		$keys[] = $base;
		foreach ( wpagent_elementor_design_devices() as $device ) {
			if ( 'desktop' !== $device ) {
				$keys[] = $base . '_' . $device;
			}
		}
	}
	$known_keys = array_values( array_unique( $keys ) );
	return $known_keys;
}

/** @return array<string,mixed> */
function wpagent_elementor_design_style_schema(): array {
	$properties = array();
	foreach ( wpagent_elementor_design_known_style_keys() as $key ) {
		if ( 'font_family' === $key ) {
			$properties[ $key ] = array( 'type' => 'string', 'minLength' => 1, 'maxLength' => 160 );
			continue;
		}
		if ( 'font_weight' === $key ) {
			$properties[ $key ] = array( 'type' => array( 'string', 'integer' ), 'minimum' => 1, 'maximum' => 1000, 'maxLength' => 6, 'pattern' => '^(?:normal|bold|[1-9][0-9]{0,3})$' );
			continue;
		}
		if ( 'text_transform' === $key ) {
			$properties[ $key ] = array( 'type' => 'string', 'enum' => array( 'none', 'uppercase', 'lowercase', 'capitalize' ) );
			continue;
		}
		if ( 'font_style' === $key ) {
			$properties[ $key ] = array( 'type' => 'string', 'enum' => array( 'normal', 'italic', 'oblique' ) );
			continue;
		}
		if ( 'text_decoration' === $key ) {
			$properties[ $key ] = array( 'type' => 'string', 'enum' => array( 'none', 'underline', 'overline', 'line-through' ) );
			continue;
		}
		$minimum = str_starts_with( $key, 'letter_spacing' ) || str_starts_with( $key, 'word_spacing' ) ? -10000 : 0;
		$properties[ $key ] = array(
			'type'                 => 'object',
			'properties'           => array(
				'size' => array( 'type' => 'number', 'minimum' => $minimum, 'maximum' => 10000 ),
				'unit' => array( 'type' => 'string', 'enum' => array( 'px', 'em', 'rem', '%', 'vw', 'vh', 'vmin', 'vmax', 'ch' ) ),
			),
			'required'             => array( 'size', 'unit' ),
			'additionalProperties' => false,
		);
	}
	return array(
		'type'                 => 'object',
		'properties'           => $properties,
		'maxProperties'        => count( $properties ),
		'additionalProperties' => false,
	);
}

/** @return mixed|WP_Error */
function wpagent_elementor_design_normalize_style_value( string $key, $value, bool $strict_font_syntax = false ) {
	if ( ! in_array( $key, wpagent_elementor_design_known_style_keys(), true ) ) {
		return new WP_Error( 'wpagent_elementor_design_bad_typography', __( 'Ein unbekanntes Typografiefeld wurde abgelehnt.', 'wp-agent-companion' ), array( 'status' => 400, 'field' => $key ) );
	}
	if ( 'font_family' === $key ) {
		$value = $strict_font_syntax
			? wpagent_elementor_design_font_list( $value, 160, 'wpagent_elementor_design_bad_typography' )
			: wpagent_elementor_design_plain_text( $value, 160, 'wpagent_elementor_design_bad_typography' );
		if ( is_wp_error( $value ) || str_contains( $value, ';' ) || str_contains( $value, '{' ) || str_contains( $value, '}' ) ) {
			return is_wp_error( $value ) ? $value : new WP_Error( 'wpagent_elementor_design_bad_typography', __( 'Die Schriftfamilie enthält nicht erlaubte CSS-Zeichen.', 'wp-agent-companion' ), array( 'status' => 400 ) );
		}
		return $value;
	}
	if ( 'font_weight' === $key ) {
		$value = is_int( $value ) ? (string) $value : $value;
		if ( ! is_string( $value ) || ( ! in_array( $value, array( 'normal', 'bold' ), true ) && ( ! ctype_digit( $value ) || (int) $value < 1 || (int) $value > 1000 ) ) ) {
			return new WP_Error( 'wpagent_elementor_design_bad_typography', __( 'Das Schriftgewicht ist ungültig.', 'wp-agent-companion' ), array( 'status' => 400 ) );
		}
		return $value;
	}
	$enums = array(
		'text_transform' => array( 'none', 'uppercase', 'lowercase', 'capitalize' ),
		'font_style' => array( 'normal', 'italic', 'oblique' ),
		'text_decoration' => array( 'none', 'underline', 'overline', 'line-through' ),
	);
	if ( isset( $enums[ $key ] ) ) {
		return is_string( $value ) && in_array( $value, $enums[ $key ], true )
			? $value
			: new WP_Error( 'wpagent_elementor_design_bad_typography', __( 'Eine typografische Auswahl ist ungültig.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	if ( preg_match( '/^(font_size|line_height|letter_spacing|word_spacing)(?:_[a-z][a-z0-9_]{0,31})?$/', $key, $match ) ) {
		if ( ! is_array( $value ) || array_is_list( $value ) || array_diff( array_keys( $value ), array( 'size', 'unit' ) ) ) {
			return new WP_Error( 'wpagent_elementor_design_bad_typography', __( 'Responsive Typografiewerte benötigen size und unit.', 'wp-agent-companion' ), array( 'status' => 400 ) );
		}
		$size = $value['size'] ?? null;
		$unit = $value['unit'] ?? null;
		if ( ! is_int( $size ) && ! is_float( $size ) ) {
			return new WP_Error( 'wpagent_elementor_design_bad_typography', __( 'Die Typografiegröße muss eine Zahl sein.', 'wp-agent-companion' ), array( 'status' => 400 ) );
		}
		$minimum = in_array( $match[1], array( 'letter_spacing', 'word_spacing' ), true ) ? -10000 : 0;
		if ( $size < $minimum || $size > 10000 || ! is_string( $unit ) || ! in_array( $unit, array( 'px', 'em', 'rem', '%', 'vw', 'vh', 'vmin', 'vmax', 'ch' ), true ) ) {
			return new WP_Error( 'wpagent_elementor_design_bad_typography', __( 'Typografiegröße oder Einheit liegt außerhalb des erlaubten Bereichs.', 'wp-agent-companion' ), array( 'status' => 400 ) );
		}
		return array( 'size' => $size, 'unit' => $unit );
	}
	return new WP_Error( 'wpagent_elementor_design_bad_typography', __( 'Ein unbekanntes Typografiefeld wurde abgelehnt.', 'wp-agent-companion' ), array( 'status' => 400, 'field' => $key ) );
}

/**
 * @param array<int,mixed> $items
 * @return array<int,array{id:string,title:string,styles:array<string,mixed>}>|WP_Error
 */
function wpagent_elementor_design_normalize_typography( array $items, bool $system, bool $provider_format = false ) {
	if ( ! array_is_list( $items ) || count( $items ) > WPAGENT_ELEMENTOR_DESIGN_MAX_TOKENS ) {
		return new WP_Error( 'wpagent_elementor_design_bad_typography', __( 'Elementor-Typografie muss eine begrenzte Liste sein.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$normalized = array();
	$seen = array();
	foreach ( $items as $item ) {
		if ( ! is_array( $item ) || array_is_list( $item ) ) {
			return new WP_Error( 'wpagent_elementor_design_bad_typography', __( 'Jedes Elementor-Typografie-Token muss ein Objekt sein.', 'wp-agent-companion' ), array( 'status' => 400 ) );
		}
		$id = $provider_format ? ( $item['_id'] ?? null ) : ( $item['id'] ?? null );
		$title = $item['title'] ?? null;
		if ( ! is_string( $id ) || ! preg_match( '/^[a-z0-9][a-z0-9_-]{0,63}$/', $id ) || isset( $seen[ $id ] ) ) {
			return new WP_Error( 'wpagent_elementor_design_bad_id', __( 'Elementor-Design-IDs müssen eindeutig und sicher formatiert sein.', 'wp-agent-companion' ), array( 'status' => 400 ) );
		}
		if ( ! $system && in_array( $id, wpagent_elementor_design_system_ids(), true ) ) {
			return new WP_Error( 'wpagent_elementor_design_bad_id', __( 'Eigene Elementor-Token dürfen keine System-ID verwenden.', 'wp-agent-companion' ), array( 'status' => 400 ) );
		}
		$title = wpagent_elementor_design_plain_text( $title, 100, 'wpagent_elementor_design_bad_title' );
		if ( is_wp_error( $title ) ) {
			return $title;
		}
		$styles = array();
		if ( $provider_format ) {
			foreach ( $item as $provider_key => $value ) {
				if ( ! is_string( $provider_key ) || in_array( $provider_key, array( '_id', 'title' ), true ) ) {
					continue;
				}
				$key = str_starts_with( $provider_key, 'typography_' ) ? substr( $provider_key, 11 ) : ( str_starts_with( $provider_key, 'styles_' ) ? substr( $provider_key, 7 ) : '' );
				if ( '' === $key || 'typography' === $key || '' === $value || null === $value ) {
					continue;
				}
				if ( is_array( $value ) && isset( $value['size'], $value['unit'] ) ) {
					$value = array( 'size' => is_numeric( $value['size'] ) ? 0 + $value['size'] : $value['size'], 'unit' => $value['unit'] );
				}
				$styles[ $key ] = $value;
			}
		} else {
			$styles = $item['styles'] ?? null;
			if ( ! is_array( $styles ) || array_is_list( $styles ) ) {
				return new WP_Error( 'wpagent_elementor_design_bad_typography', __( 'styles muss ein Typografie-Objekt sein.', 'wp-agent-companion' ), array( 'status' => 400 ) );
			}
		}
		if ( count( $styles ) > 100 ) {
			return new WP_Error( 'wpagent_elementor_design_bad_typography', __( 'Ein Typografie-Token enthält zu viele Felder.', 'wp-agent-companion' ), array( 'status' => 400 ) );
		}
		$clean_styles = array();
		foreach ( $styles as $key => $value ) {
			if ( ! is_string( $key ) || ! preg_match( '/^[a-z][a-z0-9_]{0,79}$/', $key ) ) {
				return new WP_Error( 'wpagent_elementor_design_bad_typography', __( 'Ein Typografiefeld hat einen ungültigen Namen.', 'wp-agent-companion' ), array( 'status' => 400 ) );
			}
			$clean_value = wpagent_elementor_design_normalize_style_value( $key, $value, ! $provider_format );
			if ( is_wp_error( $clean_value ) ) {
				return $clean_value;
			}
			$clean_styles[ $key ] = $clean_value;
		}
		$seen[ $id ] = true;
		$normalized[] = array( 'id' => $id, 'title' => $title, 'styles' => $clean_styles );
	}
	if ( $system ) {
		$by_id = array_column( $normalized, null, 'id' );
		if ( array_diff( wpagent_elementor_design_system_ids(), array_keys( $by_id ) ) || count( $by_id ) !== 4 ) {
			return new WP_Error( 'wpagent_elementor_design_system_tokens', __( 'Elementors vier System-Token müssen vollständig vorhanden sein.', 'wp-agent-companion' ), array( 'status' => 400 ) );
		}
		$normalized = array_map( static fn( string $id ): array => $by_id[ $id ], wpagent_elementor_design_system_ids() );
	}
	return $normalized;
}

/** @return array<string,mixed>|WP_Error */
function wpagent_elementor_design_system_state( $kit ) {
	try {
		$raw = $kit->get_data( 'settings' );
		$system_colors = $kit->get_settings_for_display( 'system_colors' );
		$custom_colors = $kit->get_settings_for_display( 'custom_colors' );
		if ( is_array( $raw ) && isset( $raw['system_typography'] ) && is_array( $raw['system_typography'] ) ) {
			$system_typography = $raw['system_typography'];
		} else {
			$control = method_exists( $kit, 'get_controls' ) ? $kit->get_controls( 'system_typography' ) : array();
			$system_typography = is_array( $control ) && is_array( $control['default'] ?? null ) ? $control['default'] : array();
		}
		$custom_typography = $kit->get_settings( 'custom_typography' );
		$fallback_font = $kit->get_settings( 'default_generic_fonts' );
	} catch ( Throwable ) {
		return new WP_Error( 'wpagent_elementor_design_read_failed', __( 'Elementor konnte sein globales Designsystem nicht lesen.', 'wp-agent-companion' ), array( 'status' => 500 ) );
	}
	$system_colors = wpagent_elementor_design_normalize_colors( is_array( $system_colors ) ? $system_colors : array(), true, true );
	$custom_colors = wpagent_elementor_design_normalize_colors( is_array( $custom_colors ) ? $custom_colors : array(), false, true );
	$system_typography = wpagent_elementor_design_normalize_typography( is_array( $system_typography ) ? $system_typography : array(), true, true );
	$custom_typography = wpagent_elementor_design_normalize_typography( is_array( $custom_typography ) ? $custom_typography : array(), false, true );
	foreach ( array( $system_colors, $custom_colors, $system_typography, $custom_typography ) as $value ) {
		if ( is_wp_error( $value ) ) {
			return $value;
		}
	}
	$fallback_font = wpagent_elementor_design_plain_text( is_string( $fallback_font ) && '' !== trim( $fallback_font ) ? $fallback_font : 'Sans-serif', 200, 'wpagent_elementor_design_bad_fallback' );
	if ( is_wp_error( $fallback_font ) ) {
		return $fallback_font;
	}
	$state = array(
		'kit_id' => absint( $kit->get_id() ),
		'elementor_version' => defined( 'ELEMENTOR_VERSION' ) ? (string) ELEMENTOR_VERSION : '',
		'system_colors' => $system_colors,
		'custom_colors' => $custom_colors,
		'system_typography' => $system_typography,
		'custom_typography' => $custom_typography,
		'fallback_font' => $fallback_font,
	);
	$hash_state = $state;
	unset( $hash_state['kit_id'], $hash_state['elementor_version'] );
	$state['hash'] = hash( 'sha256', (string) wp_json_encode( wpagent_elementor_canonicalize( $hash_state ), JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE ) );
	return $state;
}

function wpagent_elementor_design_lock_is_owned( int $kit_id, string $token ): bool {
	return wpagent_elementor_lock_is_owned( $kit_id, $token );
}

function wpagent_elementor_design_refresh_lock( int $kit_id, string $token ): bool {
	return wpagent_elementor_refresh_lock( $kit_id, $token );
}

function wpagent_elementor_design_lock_checkpoint( int $kit_id, string $token ): bool {
	return wpagent_elementor_design_lock_is_owned( $kit_id, $token )
		&& wpagent_elementor_design_refresh_lock( $kit_id, $token )
		&& wpagent_elementor_design_lock_is_owned( $kit_id, $token );
}
