<?php
/**
 * Exact, read-only integration for the separate Spectra Blocks plugin.
 *
 * This is deliberately independent from the legacy UAGB/Spectra integration.
 * It exposes only data whose source and shape can be verified on a live,
 * active Spectra Blocks 1.0.4 installation without its Pro runtime.
 */

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

const WPAGENT_SPECTRA_BLOCKS_READ_VERSION           = '1.0.4';
const WPAGENT_SPECTRA_BLOCKS_READ_MAX_PAGE_SIZE     = 50;
const WPAGENT_SPECTRA_BLOCKS_READ_MAX_PAGE           = 1000;
const WPAGENT_SPECTRA_BLOCKS_READ_MAX_SEARCH_LENGTH  = 100;
const WPAGENT_SPECTRA_BLOCKS_READ_MAX_POPUP_BYTES    = 131072;
const WPAGENT_SPECTRA_BLOCKS_READ_MAX_POPUP_BLOCKS   = 100;
const WPAGENT_SPECTRA_BLOCKS_READ_MAX_POPUP_DEPTH    = 8;
const WPAGENT_SPECTRA_BLOCKS_READ_MAX_STYLE_ITEMS    = 50;
const WPAGENT_SPECTRA_BLOCKS_READ_MAX_STYLE_BYTES    = 262144;

/** @return array<string,mixed> */
function wpagent_spectra_blocks_read_ability( string $label, string $description, array $input, array $output, string $callback ): array {
	return array(
		'label'               => $label,
		'description'         => $description,
		'category'            => 'wp-agent',
		'input_schema'        => $input,
		'output_schema'       => $output,
		'execute_callback'    => $callback,
		'permission_callback' => 'wpagent_perm_manage_options',
		'meta'                => array(
			'show_in_rest' => true,
			'annotations'  => array( 'readonly' => true, 'destructive' => false, 'idempotent' => true ),
		),
	);
}

/** @return bool */
function wpagent_spectra_blocks_read_pro_active(): bool {
	if ( defined( 'SPECTRA_BLOCKS_PRO_VER' ) || defined( 'SPECTRA_BLOCKS_PRO_FILE' ) || class_exists( 'SpectraBlocksPro\\Plugin' ) ) {
		return true;
	}
	$plugin = 'spectra-blocks-pro/spectra-blocks-pro.php';
	$active = get_option( 'active_plugins', array() );
	if ( is_array( $active ) && in_array( $plugin, $active, true ) ) {
		return true;
	}
	if ( is_multisite() ) {
		$network_active = get_site_option( 'active_sitewide_plugins', array() );
		return is_array( $network_active ) && array_key_exists( $plugin, $network_active );
	}
	return false;
}

/** @return array{version:string}|WP_Error */
function wpagent_spectra_blocks_read_require_contract() {
	if ( ! defined( 'SPECTRA_BLOCKS_VER' ) || ! defined( 'SPECTRA_BLOCKS_FILE' ) ) {
		return new WP_Error( 'wpagent_spectra_blocks_read_provider', __( 'Spectra Blocks ist nicht aktiv.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	$version = (string) SPECTRA_BLOCKS_VER;
	if ( ! hash_equals( WPAGENT_SPECTRA_BLOCKS_READ_VERSION, $version ) ) {
		return new WP_Error( 'wpagent_spectra_blocks_read_provider', __( 'Die schreibgeschützte Spectra-Blocks-Integration erfordert exakt Version 1.0.4.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	if ( 'spectra-blocks/spectra-blocks.php' !== plugin_basename( (string) SPECTRA_BLOCKS_FILE ) ) {
		return new WP_Error( 'wpagent_spectra_blocks_read_provider', __( 'Die aktive Spectra-Blocks-Installation hat nicht die erwartete Plugin-Identität.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	if ( wpagent_spectra_blocks_read_pro_active() ) {
		return new WP_Error( 'wpagent_spectra_blocks_read_pro', __( 'Die schreibgeschützte Spectra-Blocks-Integration ist nur für die nachweisbar Pro-freie Laufzeit verfügbar.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	return array( 'version' => $version );
}

/** @return array<string,mixed> */
function wpagent_spectra_blocks_read_provider_schema(): array {
	return array(
		'type'                 => 'object',
		'properties'           => array(
			'slug'                          => array( 'type' => 'string', 'enum' => array( 'spectra-blocks' ) ),
			'version'                       => array( 'type' => 'string', 'enum' => array( WPAGENT_SPECTRA_BLOCKS_READ_VERSION ) ),
			'pro_active'                    => array( 'type' => 'boolean', 'enum' => array( false ) ),
			'block_catalog_available'       => array( 'type' => 'boolean' ),
			'global_block_styles_available' => array( 'type' => 'boolean' ),
			'popup_builder_available'       => array( 'type' => 'boolean' ),
		),
		'required'             => array( 'slug', 'version', 'pro_active', 'block_catalog_available', 'global_block_styles_available', 'popup_builder_available' ),
		'additionalProperties' => false,
	);
}

/** @return array<string,mixed> */
function wpagent_ability_get_spectra_blocks_provider(): array {
	return wpagent_spectra_blocks_read_ability(
		__( 'Spectra-Blocks-Provider lesen', 'wp-agent-companion' ),
		__( 'Bestätigt die aktive, exakt gebundene Spectra-Blocks-Installation samt Pro-Abwesenheit und verfügbaren, rein lesenden Teiloberflächen.', 'wp-agent-companion' ),
		array( 'type' => 'object', 'properties' => array(), 'additionalProperties' => false, 'default' => array() ),
		wpagent_spectra_blocks_read_provider_schema(),
		'wpagent_exec_get_spectra_blocks_provider'
	);
}

/** @return array<string,mixed>|WP_Error */
function wpagent_exec_get_spectra_blocks_provider( $input ) {
	$contract = wpagent_spectra_blocks_read_require_contract();
	if ( is_wp_error( $contract ) ) {
		return $contract;
	}
	$registry = WP_Block_Type_Registry::get_instance();
	return array(
		'slug'                          => 'spectra-blocks',
		'version'                       => $contract['version'],
		'pro_active'                    => false,
		'block_catalog_available'       => class_exists( 'Spectra_Blocks_Admin_Helper' ) && is_callable( array( 'Spectra_Blocks_Admin_Helper', 'get_block_options' ) ),
		'global_block_styles_available' => class_exists( 'SpectraBlocks\\GlobalStyles\\Engine' ) && class_exists( 'SpectraBlocks\\StyleGuide\\Engine' ),
		'popup_builder_available'       => post_type_exists( 'spectra-blocks-popup' ) && $registry->is_registered( 'spectra/popup-builder' ),
	);
}

/** @return array<string,mixed> */
function wpagent_spectra_blocks_read_catalog_item_schema(): array {
	return array(
		'type'                 => 'object',
		'properties'           => array(
			'name'        => array( 'type' => 'string', 'pattern' => '^spectra/[a-z0-9-]+$' ),
			'title'       => array( 'type' => 'string', 'maxLength' => 160 ),
			'description' => array( 'type' => 'string', 'maxLength' => 500 ),
			'category'    => array( 'type' => 'string', 'maxLength' => 80 ),
			'active'      => array( 'type' => 'boolean' ),
			'parent'      => array( 'type' => 'array', 'maxItems' => 8, 'items' => array( 'type' => 'string', 'maxLength' => 100 ) ),
		),
		'required'             => array( 'name', 'title', 'description', 'category', 'active', 'parent' ),
		'additionalProperties' => false,
	);
}

/** @return array<string,mixed> */
function wpagent_ability_list_spectra_blocks_catalog(): array {
	return wpagent_spectra_blocks_read_ability(
		__( 'Spectra-Blocks-Katalog lesen', 'wp-agent-companion' ),
		__( 'Listet nur live registrierte Spectra-Blocks samt ihres vom Provider aufgelösten Aktivierungszustands auf.', 'wp-agent-companion' ),
		array(
			'type'                 => 'object',
			'properties'           => array(
				'search'   => array( 'type' => 'string', 'maxLength' => WPAGENT_SPECTRA_BLOCKS_READ_MAX_SEARCH_LENGTH, 'default' => '' ),
				'active'   => array( 'type' => 'string', 'enum' => array( 'all', 'active', 'inactive' ), 'default' => 'all' ),
				'page'     => array( 'type' => 'integer', 'minimum' => 1, 'maximum' => WPAGENT_SPECTRA_BLOCKS_READ_MAX_PAGE, 'default' => 1 ),
				'per_page' => array( 'type' => 'integer', 'minimum' => 1, 'maximum' => WPAGENT_SPECTRA_BLOCKS_READ_MAX_PAGE_SIZE, 'default' => 25 ),
			),
			'additionalProperties' => false,
			'default'              => array(),
		),
		array(
			'type'                 => 'object',
			'properties'           => array(
				'version'     => array( 'type' => 'string', 'enum' => array( WPAGENT_SPECTRA_BLOCKS_READ_VERSION ) ),
				'items'       => array( 'type' => 'array', 'maxItems' => WPAGENT_SPECTRA_BLOCKS_READ_MAX_PAGE_SIZE, 'items' => wpagent_spectra_blocks_read_catalog_item_schema() ),
				'total'       => array( 'type' => 'integer', 'minimum' => 0 ),
				'page'        => array( 'type' => 'integer', 'minimum' => 1 ),
				'per_page'    => array( 'type' => 'integer', 'minimum' => 1, 'maximum' => WPAGENT_SPECTRA_BLOCKS_READ_MAX_PAGE_SIZE ),
				'total_pages' => array( 'type' => 'integer', 'minimum' => 0 ),
				'hash'        => array( 'type' => 'string', 'pattern' => '^[a-f0-9]{64}$' ),
			),
			'required'             => array( 'version', 'items', 'total', 'page', 'per_page', 'total_pages', 'hash' ),
			'additionalProperties' => false,
		),
		'wpagent_exec_list_spectra_blocks_catalog'
	);
}

/** @return array{search:string,active:string,page:int,per_page:int}|WP_Error */
function wpagent_spectra_blocks_read_catalog_input( $input ) {
	$input = is_array( $input ) && ! wp_is_numeric_array( $input ) ? $input : array();
	$search = $input['search'] ?? '';
	if ( ! is_string( $search ) || strlen( $search ) > WPAGENT_SPECTRA_BLOCKS_READ_MAX_SEARCH_LENGTH ) {
		return new WP_Error( 'wpagent_spectra_blocks_read_search', __( 'Die Spectra-Blocks-Suche ist ungültig oder zu lang.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$active = $input['active'] ?? 'all';
	if ( ! is_string( $active ) || ! in_array( $active, array( 'all', 'active', 'inactive' ), true ) ) {
		return new WP_Error( 'wpagent_spectra_blocks_read_filter', __( 'Der Spectra-Blocks-Aktivierungsfilter ist ungültig.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$page = $input['page'] ?? 1;
	$per_page = $input['per_page'] ?? 25;
	if ( ! is_int( $page ) || $page < 1 || $page > WPAGENT_SPECTRA_BLOCKS_READ_MAX_PAGE || ! is_int( $per_page ) || $per_page < 1 || $per_page > WPAGENT_SPECTRA_BLOCKS_READ_MAX_PAGE_SIZE ) {
		return new WP_Error( 'wpagent_spectra_blocks_read_page', __( 'Die Spectra-Blocks-Seite liegt außerhalb der festen Grenze.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	return array( 'search' => trim( sanitize_text_field( $search ) ), 'active' => $active, 'page' => $page, 'per_page' => $per_page );
}

/** @return array<string,mixed>|WP_Error */
function wpagent_spectra_blocks_read_catalog() {
	if ( ! class_exists( 'Spectra_Blocks_Admin_Helper' ) || ! is_callable( array( 'Spectra_Blocks_Admin_Helper', 'get_block_options' ) ) ) {
		return new WP_Error( 'wpagent_spectra_blocks_read_catalog', __( 'Die native Spectra-Blocks-Katalog-API ist nicht verfügbar.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	$options = Spectra_Blocks_Admin_Helper::get_block_options();
	if ( ! is_array( $options ) ) {
		return new WP_Error( 'wpagent_spectra_blocks_read_catalog', __( 'Die native Spectra-Blocks-Katalog-API lieferte keinen gültigen Katalog.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	$registry = WP_Block_Type_Registry::get_instance();
	$items = array();
	foreach ( $options as $name => $provider ) {
		if ( ! is_string( $name ) || 1 !== preg_match( '/\Aspectra\/[a-z0-9-]+\z/D', $name ) || ! is_array( $provider ) ) {
			continue;
		}
		$type = $registry->get_registered( $name );
		if ( ! $type instanceof WP_Block_Type ) {
			continue;
		}
		$parent = array();
		foreach ( array_slice( is_array( $type->parent ) ? $type->parent : array(), 0, 8 ) as $entry ) {
			if ( is_string( $entry ) && 1 === preg_match( '/\A(?:core|spectra)\/[a-z0-9-]+\z/D', $entry ) ) {
				$parent[] = $entry;
			}
		}
		$items[] = array(
			'name'        => $name,
			'title'       => mb_substr( sanitize_text_field( (string) $type->title ), 0, 160 ),
			'description' => mb_substr( wp_strip_all_tags( (string) $type->description ), 0, 500 ),
			'category'    => mb_substr( sanitize_key( (string) $type->category ), 0, 80 ),
			'active'      => ! empty( $provider['is_activate'] ),
			'parent'      => array_values( array_unique( $parent ) ),
		);
	}
	usort( $items, static fn( array $left, array $right ): int => strcmp( $left['name'], $right['name'] ) );
	return $items;
}

/** @return array<string,mixed>|WP_Error */
function wpagent_exec_list_spectra_blocks_catalog( $input ) {
	$contract = wpagent_spectra_blocks_read_require_contract();
	if ( is_wp_error( $contract ) ) {
		return $contract;
	}
	$input = wpagent_spectra_blocks_read_catalog_input( $input );
	if ( is_wp_error( $input ) ) {
		return $input;
	}
	$catalog = wpagent_spectra_blocks_read_catalog();
	if ( is_wp_error( $catalog ) ) {
		return $catalog;
	}
	$filtered = array_values( array_filter( $catalog, static function ( array $item ) use ( $input ): bool {
		if ( 'active' === $input['active'] && ! $item['active'] ) {
			return false;
		}
		if ( 'inactive' === $input['active'] && $item['active'] ) {
			return false;
		}
		if ( '' === $input['search'] ) {
			return true;
		}
		return false !== stripos( implode( "\n", array( $item['name'], $item['title'], $item['description'], $item['category'], implode( ' ', $item['parent'] ) ) ), $input['search'] );
	} ) );
	$total = count( $filtered );
	return array(
		'version'     => $contract['version'],
		'items'       => array_slice( $filtered, ( $input['page'] - 1 ) * $input['per_page'], $input['per_page'] ),
		'total'       => $total,
		'page'        => $input['page'],
		'per_page'    => $input['per_page'],
		'total_pages' => (int) ceil( $total / $input['per_page'] ),
		'hash'        => hash( 'sha256', wp_json_encode( $catalog, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE ) ?: '' ),
	);
}

/** @return array<string,mixed> */
function wpagent_ability_get_spectra_blocks_settings(): array {
	return wpagent_spectra_blocks_read_ability(
		__( 'Spectra-Blocks-Einstellungen lesen', 'wp-agent-companion' ),
		__( 'Liest ausschließlich eine kleine, dokumentierte Liste nicht vertraulicher Spectra-Blocks-Schalter. Anmeldedaten und Captcha-Daten werden nie zurückgegeben.', 'wp-agent-companion' ),
		array( 'type' => 'object', 'properties' => array(), 'additionalProperties' => false, 'default' => array() ),
		array(
			'type'                 => 'object',
			'properties'           => array(
				'version'                    => array( 'type' => 'string', 'enum' => array( WPAGENT_SPECTRA_BLOCKS_READ_VERSION ) ),
				'templates_button_enabled'   => array( 'type' => 'boolean' ),
				'animations_enabled'         => array( 'type' => 'boolean' ),
				'global_block_styles_enabled' => array( 'type' => 'boolean' ),
				'responsive_blocks_enabled'  => array( 'type' => 'boolean' ),
				'local_google_fonts_enabled' => array( 'type' => 'boolean' ),
				'preload_local_fonts_enabled' => array( 'type' => 'boolean' ),
				'analytics_opt_in'            => array( 'type' => 'boolean' ),
			),
			'required'             => array( 'version', 'templates_button_enabled', 'animations_enabled', 'global_block_styles_enabled', 'responsive_blocks_enabled', 'local_google_fonts_enabled', 'preload_local_fonts_enabled', 'analytics_opt_in' ),
			'additionalProperties' => false,
		),
		'wpagent_exec_get_spectra_blocks_settings'
	);
}

function wpagent_spectra_blocks_read_enabled_option( string $name, string $enabled ): bool {
	return hash_equals( $enabled, (string) get_option( $name, '' ) );
}

/** @return array<string,mixed>|WP_Error */
function wpagent_exec_get_spectra_blocks_settings( $input ) {
	$contract = wpagent_spectra_blocks_read_require_contract();
	if ( is_wp_error( $contract ) ) {
		return $contract;
	}
	return array(
		'version'                    => $contract['version'],
		'templates_button_enabled'   => wpagent_spectra_blocks_read_enabled_option( 'spectra_blocks_enable_templates_button', 'yes' ),
		'animations_enabled'         => wpagent_spectra_blocks_read_enabled_option( 'spectra_blocks_enable_animations_extension', 'enabled' ),
		'global_block_styles_enabled' => wpagent_spectra_blocks_read_enabled_option( 'spectra_blocks_enable_gbs_extension', 'enabled' ),
		'responsive_blocks_enabled'  => wpagent_spectra_blocks_read_enabled_option( 'spectra_blocks_enable_block_responsive', 'enabled' ),
		'local_google_fonts_enabled' => wpagent_spectra_blocks_read_enabled_option( 'spectra_blocks_load_gfonts_locally', 'enabled' ),
		'preload_local_fonts_enabled' => wpagent_spectra_blocks_read_enabled_option( 'spectra_blocks_preload_local_fonts', 'enabled' ),
		'analytics_opt_in'            => wpagent_spectra_blocks_read_enabled_option( 'spectra_blocks_analytics_optin', 'yes' ),
	);
}

/** @return array<int,string> */
function wpagent_spectra_blocks_read_safe_style_names( $value, string $pattern ): array {
	if ( ! is_array( $value ) || wp_is_numeric_array( $value ) ) {
		return array();
	}
	$names = array();
	foreach ( array_keys( $value ) as $name ) {
		if ( is_string( $name ) && 1 === preg_match( $pattern, $name ) ) {
			$names[] = $name;
		}
	}
	$names = array_values( array_unique( $names ) );
	sort( $names, SORT_STRING );
	return array_slice( $names, 0, WPAGENT_SPECTRA_BLOCKS_READ_MAX_STYLE_ITEMS );
}

/** @return array<int,array<string,mixed>> */
function wpagent_spectra_blocks_read_style_chromatics( $value ): array {
	if ( ! is_array( $value ) ) {
		return array();
	}
	$result = array();
	foreach ( $value as $index => $entry ) {
		if ( ! is_int( $index ) && ! ctype_digit( (string) $index ) ) {
			continue;
		}
		$index = (int) $index;
		if ( $index < 1 || $index > 7 || ! is_array( $entry ) ) {
			continue;
		}
		$hex = strtolower( (string) ( $entry['hex'] ?? '' ) );
		if ( 1 !== preg_match( '/\A#[a-f0-9]{6}\z/D', $hex ) ) {
			continue;
		}
		$result[] = array(
			'index'   => $index,
			'hex'     => $hex,
			'name'    => mb_substr( sanitize_text_field( (string) ( $entry['name'] ?? '' ) ), 0, 80 ),
			'is_main' => ! empty( $entry['isMain'] ),
		);
	}
	usort( $result, static fn( array $left, array $right ): int => $left['index'] <=> $right['index'] );
	return $result;
}

/** @return array<string,mixed>|WP_Error */
function wpagent_spectra_blocks_read_global_styles_state() {
	if ( ! class_exists( 'SpectraBlocks\\GlobalStyles\\Engine' ) || ! class_exists( 'SpectraBlocks\\StyleGuide\\Engine' ) ) {
		return new WP_Error( 'wpagent_spectra_blocks_read_styles', __( 'Die native Spectra-Blocks-Global-Block-Styles-API ist nicht verfügbar.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	$option_key = \SpectraBlocks\GlobalStyles\Engine::OPTION_KEY_USER_CSS;
	$sentinel = new stdClass();
	$user_css = get_option( $option_key, $sentinel );
	$present = $sentinel !== $user_css;
	if ( $present && ! is_array( $user_css ) ) {
		return new WP_Error( 'wpagent_spectra_blocks_read_styles', __( 'Die Spectra-Blocks-Global-Block-Styles sind beschädigt und werden nicht ausgelesen.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	$user_css = $present ? $user_css : array();
	$json = wp_json_encode( $user_css, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE );
	if ( false === $json || strlen( $json ) > WPAGENT_SPECTRA_BLOCKS_READ_MAX_STYLE_BYTES ) {
		return new WP_Error( 'wpagent_spectra_blocks_read_styles_size', __( 'Die Spectra-Blocks-Global-Block-Styles überschreiten die feste Lesebegrenzung.', 'wp-agent-companion' ), array( 'status' => 413 ) );
	}
	$guide_option = \SpectraBlocks\StyleGuide\Engine::OPTION_KEY;
	$stored_guide = get_option( $guide_option, $sentinel );
	if ( $sentinel !== $stored_guide && ! is_array( $stored_guide ) ) {
		return new WP_Error( 'wpagent_spectra_blocks_read_styles', __( 'Die gespeicherten Spectra-Blocks-Style-Guide-Daten sind beschädigt und werden nicht ausgelesen.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	$stored_guide_json = $sentinel === $stored_guide ? '' : wp_json_encode( $stored_guide, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE );
	if ( false === $stored_guide_json || strlen( $stored_guide_json ) > WPAGENT_SPECTRA_BLOCKS_READ_MAX_STYLE_BYTES ) {
		return new WP_Error( 'wpagent_spectra_blocks_read_styles_size', __( 'Der gespeicherte Spectra-Blocks-Style-Guide überschreitet die feste Lesebegrenzung.', 'wp-agent-companion' ), array( 'status' => 413 ) );
	}
	try {
		$style_engine = \SpectraBlocks\StyleGuide\Engine::get_instance();
		$guide = $style_engine->get_config();
	} catch ( Throwable $error ) {
		return new WP_Error( 'wpagent_spectra_blocks_read_styles', __( 'Die Spectra-Blocks-Style-Guide-API konnte nicht gelesen werden.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	if ( ! is_array( $guide ) ) {
		return new WP_Error( 'wpagent_spectra_blocks_read_styles', __( 'Die Spectra-Blocks-Style-Guide-API lieferte kein gültiges Objekt.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	$semantic_map = wpagent_spectra_blocks_read_safe_style_names( $guide['semantic_map'] ?? array(), '/\A[a-z0-9-]{1,64}\z/D' );
	$preset_names = wpagent_spectra_blocks_read_safe_style_names( $guide['presets'] ?? array(), '/\A[a-zA-Z][a-zA-Z0-9]{0,63}\z/D' );
	$user_css_summary = array(
		'present'                 => $present,
		'class_names'             => wpagent_spectra_blocks_read_safe_style_names( $user_css['classes'] ?? array(), '/\A[a-zA-Z][a-zA-Z0-9_-]{0,79}\z/D' ),
		'variable_names'          => wpagent_spectra_blocks_read_safe_style_names( $user_css['variables'] ?? array(), '/\A--[a-zA-Z][a-zA-Z0-9_-]{0,79}\z/D' ),
		'keyframe_names'          => wpagent_spectra_blocks_read_safe_style_names( $user_css['keyframes'] ?? array(), '/\A[a-zA-Z][a-zA-Z0-9_-]{0,79}\z/D' ),
		'unknown_entries_omitted' => array_diff( array_keys( $user_css ), array( 'classes', 'variables', 'keyframes' ) ) !== array(),
	);
	$user_css_summary['bytes'] = strlen( wp_json_encode( $user_css_summary, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE ) ?: '' );
	return array(
		'user_css' => array(
			'present'                 => $user_css_summary['present'],
			'bytes'                   => $user_css_summary['bytes'],
			'hash'                    => hash( 'sha256', wp_json_encode( $user_css_summary, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE ) ?: '' ),
			'class_names'             => $user_css_summary['class_names'],
			'variable_names'          => $user_css_summary['variable_names'],
			'keyframe_names'          => $user_css_summary['keyframe_names'],
			'unknown_entries_omitted' => $user_css_summary['unknown_entries_omitted'],
		),
		'style_guide' => array(
			'saved'               => $sentinel !== $stored_guide,
			'version'             => max( 0, min( 99, absint( $guide['version'] ?? 0 ) ) ),
			'chromatics'          => wpagent_spectra_blocks_read_style_chromatics( $guide['chromatics'] ?? array() ),
			'semantic_role_names' => $semantic_map,
			'preset_names'        => $preset_names,
		),
	);
}

/** @return array<string,mixed> */
function wpagent_ability_get_spectra_blocks_global_styles(): array {
	$style_name = array( 'type' => 'string', 'maxLength' => 80 );
	return wpagent_spectra_blocks_read_ability(
		__( 'Spectra-Blocks-Global-Block-Styles lesen', 'wp-agent-companion' ),
		__( 'Liest nur begrenzte Metadaten und sichere Farbtoken der nativen Spectra-Blocks-Global-Block-Styles. Rohes CSS, Deklarationswerte und unbekannte Einträge werden nie ausgegeben.', 'wp-agent-companion' ),
		array( 'type' => 'object', 'properties' => array(), 'additionalProperties' => false, 'default' => array() ),
		array(
			'type'                 => 'object',
			'properties'           => array(
				'version'                    => array( 'type' => 'string', 'enum' => array( WPAGENT_SPECTRA_BLOCKS_READ_VERSION ) ),
				'global_block_styles_enabled' => array( 'type' => 'boolean' ),
				'user_css'                   => array( 'type' => 'object', 'properties' => array(
					'present' => array( 'type' => 'boolean' ), 'bytes' => array( 'type' => 'integer', 'minimum' => 0, 'maximum' => WPAGENT_SPECTRA_BLOCKS_READ_MAX_STYLE_BYTES ),
					'hash' => array( 'type' => 'string', 'pattern' => '^[a-f0-9]{64}$' ),
					'class_names' => array( 'type' => 'array', 'maxItems' => WPAGENT_SPECTRA_BLOCKS_READ_MAX_STYLE_ITEMS, 'items' => $style_name ),
					'variable_names' => array( 'type' => 'array', 'maxItems' => WPAGENT_SPECTRA_BLOCKS_READ_MAX_STYLE_ITEMS, 'items' => $style_name ),
					'keyframe_names' => array( 'type' => 'array', 'maxItems' => WPAGENT_SPECTRA_BLOCKS_READ_MAX_STYLE_ITEMS, 'items' => $style_name ),
					'unknown_entries_omitted' => array( 'type' => 'boolean' ),
				), 'required' => array( 'present', 'bytes', 'hash', 'class_names', 'variable_names', 'keyframe_names', 'unknown_entries_omitted' ), 'additionalProperties' => false ),
				'style_guide' => array( 'type' => 'object', 'properties' => array(
					'saved' => array( 'type' => 'boolean' ), 'version' => array( 'type' => 'integer', 'minimum' => 0, 'maximum' => 99 ),
					'chromatics' => array( 'type' => 'array', 'maxItems' => 7, 'items' => array( 'type' => 'object', 'properties' => array(
						'index' => array( 'type' => 'integer', 'minimum' => 1, 'maximum' => 7 ), 'hex' => array( 'type' => 'string', 'pattern' => '^#[a-f0-9]{6}$' ),
						'name' => array( 'type' => 'string', 'maxLength' => 80 ), 'is_main' => array( 'type' => 'boolean' ),
					), 'required' => array( 'index', 'hex', 'name', 'is_main' ), 'additionalProperties' => false ) ),
					'semantic_role_names' => array( 'type' => 'array', 'maxItems' => WPAGENT_SPECTRA_BLOCKS_READ_MAX_STYLE_ITEMS, 'items' => $style_name ),
					'preset_names' => array( 'type' => 'array', 'maxItems' => WPAGENT_SPECTRA_BLOCKS_READ_MAX_STYLE_ITEMS, 'items' => $style_name ),
				), 'required' => array( 'saved', 'version', 'chromatics', 'semantic_role_names', 'preset_names' ), 'additionalProperties' => false ),
			),
			'required'             => array( 'version', 'global_block_styles_enabled', 'user_css', 'style_guide' ),
			'additionalProperties' => false,
		),
		'wpagent_exec_get_spectra_blocks_global_styles'
	);
}

/** @return array<string,mixed>|WP_Error */
function wpagent_exec_get_spectra_blocks_global_styles( $input ) {
	$contract = wpagent_spectra_blocks_read_require_contract();
	if ( is_wp_error( $contract ) ) {
		return $contract;
	}
	$state = wpagent_spectra_blocks_read_global_styles_state();
	if ( is_wp_error( $state ) ) {
		return $state;
	}
	return array_merge( array(
		'version'                    => $contract['version'],
		'global_block_styles_enabled' => wpagent_spectra_blocks_read_enabled_option( 'spectra_blocks_enable_gbs_extension', 'enabled' ),
	), $state );
}

/** @return true|WP_Error */
function wpagent_spectra_blocks_read_popup_contract() {
	$contract = wpagent_spectra_blocks_read_require_contract();
	if ( is_wp_error( $contract ) ) {
		return $contract;
	}
	$type = get_post_type_object( 'spectra-blocks-popup' );
	$registry = WP_Block_Type_Registry::get_instance();
	$popup = $registry->get_registered( 'spectra/popup-builder' );
	if ( ! $type instanceof WP_Post_Type || ! $type->show_in_rest || 'all' !== $type->template_lock || ! $popup instanceof WP_Block_Type || 3 !== (int) $popup->api_version ) {
		return new WP_Error( 'wpagent_spectra_blocks_popup_provider', __( 'Die native Spectra-Blocks-Popup-Builder-API entspricht nicht dem verifizierten Vertrag.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	$template = is_array( $type->template ) ? $type->template : array();
	if ( 1 !== count( $template ) || ! is_array( $template[0] ?? null ) || 'spectra/popup-builder' !== ( $template[0][0] ?? null ) ) {
		return new WP_Error( 'wpagent_spectra_blocks_popup_provider', __( 'Der native Spectra-Blocks-Popup-Builder hat keinen verifizierbaren Wrappervertrag.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	$meta = get_registered_meta_keys( 'post', 'spectra-blocks-popup' );
	$required = array(
		'spectra-blocks-popup-type' => 'string',
		'spectra-blocks-popup-enabled' => 'boolean',
		'spectra-blocks-popup-repetition' => 'number',
	);
	foreach ( $required as $key => $expected_type ) {
		if ( ! is_array( $meta[ $key ] ?? null ) || $expected_type !== ( $meta[ $key ]['type'] ?? null ) || empty( $meta[ $key ]['show_in_rest'] ) ) {
			return new WP_Error( 'wpagent_spectra_blocks_popup_provider', __( 'Die nativen Spectra-Blocks-Popup-Metadaten entsprechen nicht dem verifizierten Vertrag.', 'wp-agent-companion' ), array( 'status' => 409 ) );
		}
	}
	return true;
}

/** @return array{block_count:int,max_depth:int}|WP_Error */
function wpagent_spectra_blocks_read_popup_markup_stats( array $blocks ) {
	if ( 1 !== count( $blocks ) || ! is_array( $blocks[0] ?? null ) || 'spectra/popup-builder' !== ( $blocks[0]['blockName'] ?? null ) ) {
		return new WP_Error( 'wpagent_spectra_blocks_popup_markup', __( 'Der Popup-Inhalt besitzt keinen einzelnen nativen Spectra-Blocks-Popup-Builder-Wrapper.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	$registry = WP_Block_Type_Registry::get_instance();
	$stack = array( array( 'block' => $blocks[0], 'depth' => 1 ) );
	$count = 0;
	$max_depth = 0;
	while ( $stack ) {
		$entry = array_pop( $stack );
		$block = $entry['block'];
		$depth = $entry['depth'];
		if ( ! is_array( $block ) || $depth > WPAGENT_SPECTRA_BLOCKS_READ_MAX_POPUP_DEPTH ) {
			return new WP_Error( 'wpagent_spectra_blocks_popup_markup', __( 'Der Popup-Blockbaum überschreitet die feste Tiefengrenze.', 'wp-agent-companion' ), array( 'status' => 413 ) );
		}
		$name = $block['blockName'] ?? null;
		if ( ! is_string( $name ) || '' === $name || in_array( $name, array( 'core/freeform', 'core/html', 'core/shortcode' ), true ) || ! $registry->is_registered( $name ) ) {
			return new WP_Error( 'wpagent_spectra_blocks_popup_markup', __( 'Der Popup-Inhalt enthält nicht verifizierbares oder rohes Block-Markup.', 'wp-agent-companion' ), array( 'status' => 409 ) );
		}
		++$count;
		$max_depth = max( $max_depth, $depth );
		if ( $count > WPAGENT_SPECTRA_BLOCKS_READ_MAX_POPUP_BLOCKS ) {
			return new WP_Error( 'wpagent_spectra_blocks_popup_markup', __( 'Der Popup-Blockbaum überschreitet die feste Blockgrenze.', 'wp-agent-companion' ), array( 'status' => 413 ) );
		}
		$inner = $block['innerBlocks'] ?? array();
		if ( ! is_array( $inner ) ) {
			return new WP_Error( 'wpagent_spectra_blocks_popup_markup', __( 'Der Popup-Blockbaum hat eine ungültige innere Struktur.', 'wp-agent-companion' ), array( 'status' => 409 ) );
		}
		foreach ( array_reverse( $inner ) as $child ) {
			$stack[] = array( 'block' => $child, 'depth' => $depth + 1 );
		}
	}
	return array( 'block_count' => $count, 'max_depth' => $max_depth );
}

/** @return bool|WP_Error */
function wpagent_spectra_blocks_read_popup_enabled( $value ) {
	if ( true === $value || 1 === $value || '1' === $value ) {
		return true;
	}
	if ( false === $value || 0 === $value || '0' === $value || '' === $value ) {
		return false;
	}
	return new WP_Error( 'wpagent_spectra_blocks_popup_meta', __( 'Der native Spectra-Blocks-Popup-Aktivierungswert ist ungültig.', 'wp-agent-companion' ), array( 'status' => 409 ) );
}

/** @return array<string,mixed> */
function wpagent_ability_get_spectra_blocks_popup(): array {
	return wpagent_spectra_blocks_read_ability(
		__( 'Spectra-Blocks-Popup lesen', 'wp-agent-companion' ),
		__( 'Liest ein einzelnes Popup des nativen Spectra-Blocks-Popup-Builders nur nach CPT-, Metadaten-, Wrapper-, Größen- und Blockbaumprüfung.', 'wp-agent-companion' ),
		array( 'type' => 'object', 'properties' => array( 'id' => array( 'type' => 'integer', 'minimum' => 1 ) ), 'required' => array( 'id' ), 'additionalProperties' => false ),
		array(
			'type'                 => 'object',
			'properties'           => array(
				'id'          => array( 'type' => 'integer', 'minimum' => 1 ),
				'version'     => array( 'type' => 'string', 'enum' => array( WPAGENT_SPECTRA_BLOCKS_READ_VERSION ) ),
				'title'       => array( 'type' => 'string', 'maxLength' => 200 ),
				'status'      => array( 'type' => 'string', 'maxLength' => 20 ),
				'type'        => array( 'type' => 'string', 'enum' => array( 'unset', 'popup', 'banner' ) ),
				'enabled'     => array( 'type' => 'boolean' ),
				'repetition'  => array( 'type' => 'number', 'minimum' => 0, 'maximum' => 365 ),
				'modified'    => array( 'type' => 'string' ),
				'markup'      => array( 'type' => 'string', 'maxLength' => WPAGENT_SPECTRA_BLOCKS_READ_MAX_POPUP_BYTES ),
				'bytes'       => array( 'type' => 'integer', 'minimum' => 1, 'maximum' => WPAGENT_SPECTRA_BLOCKS_READ_MAX_POPUP_BYTES ),
				'block_count' => array( 'type' => 'integer', 'minimum' => 1, 'maximum' => WPAGENT_SPECTRA_BLOCKS_READ_MAX_POPUP_BLOCKS ),
				'max_depth'   => array( 'type' => 'integer', 'minimum' => 1, 'maximum' => WPAGENT_SPECTRA_BLOCKS_READ_MAX_POPUP_DEPTH ),
				'hash'        => array( 'type' => 'string', 'pattern' => '^[a-f0-9]{64}$' ),
			),
			'required'             => array( 'id', 'version', 'title', 'status', 'type', 'enabled', 'repetition', 'modified', 'markup', 'bytes', 'block_count', 'max_depth', 'hash' ),
			'additionalProperties' => false,
		),
		'wpagent_exec_get_spectra_blocks_popup'
	);
}

/** @return array<string,mixed>|WP_Error */
function wpagent_exec_get_spectra_blocks_popup( $input ) {
	$contract = wpagent_spectra_blocks_read_popup_contract();
	if ( is_wp_error( $contract ) ) {
		return $contract;
	}
	$id = is_array( $input ) ? absint( $input['id'] ?? 0 ) : 0;
	$post = get_post( $id );
	if ( ! $post instanceof WP_Post || 'spectra-blocks-popup' !== $post->post_type ) {
		return new WP_Error( 'wpagent_spectra_blocks_popup_not_found', __( 'Spectra-Blocks-Popup nicht gefunden.', 'wp-agent-companion' ), array( 'status' => 404 ) );
	}
	if ( ! current_user_can( 'read_post', $post->ID ) ) {
		return new WP_Error( 'wpagent_spectra_blocks_popup_forbidden', __( 'Das Spectra-Blocks-Popup darf nicht gelesen werden.', 'wp-agent-companion' ), array( 'status' => 403 ) );
	}
	$content = (string) $post->post_content;
	if ( '' === $content || strlen( $content ) > WPAGENT_SPECTRA_BLOCKS_READ_MAX_POPUP_BYTES ) {
		return new WP_Error( 'wpagent_spectra_blocks_popup_size', __( 'Der Spectra-Blocks-Popup-Inhalt ist leer oder überschreitet die feste Lesebegrenzung.', 'wp-agent-companion' ), array( 'status' => 413 ) );
	}
	$blocks = parse_blocks( $content );
	$stats = wpagent_spectra_blocks_read_popup_markup_stats( $blocks );
	if ( is_wp_error( $stats ) ) {
		return $stats;
	}
	$markup = serialize_blocks( $blocks );
	if ( '' === $markup || strlen( $markup ) > WPAGENT_SPECTRA_BLOCKS_READ_MAX_POPUP_BYTES ) {
		return new WP_Error( 'wpagent_spectra_blocks_popup_size', __( 'Das kanonische Spectra-Blocks-Popup-Markup überschreitet die feste Lesebegrenzung.', 'wp-agent-companion' ), array( 'status' => 413 ) );
	}
	$type = get_post_meta( $post->ID, 'spectra-blocks-popup-type', true );
	$type = is_string( $type ) && in_array( $type, array( 'popup', 'banner' ), true ) ? $type : 'unset';
	$enabled = wpagent_spectra_blocks_read_popup_enabled( get_post_meta( $post->ID, 'spectra-blocks-popup-enabled', true ) );
	if ( is_wp_error( $enabled ) ) {
		return $enabled;
	}
	$repetition = get_post_meta( $post->ID, 'spectra-blocks-popup-repetition', true );
	if ( ! is_numeric( $repetition ) || (float) $repetition < 0 || (float) $repetition > 365 ) {
		return new WP_Error( 'wpagent_spectra_blocks_popup_meta', __( 'Der native Spectra-Blocks-Popup-Wiederholungswert ist ungültig.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	$repetition = (float) $repetition;
	return array(
		'id'          => (int) $post->ID,
		'version'     => WPAGENT_SPECTRA_BLOCKS_READ_VERSION,
		'title'       => mb_substr( sanitize_text_field( (string) $post->post_title ), 0, 200 ),
		'status'      => sanitize_key( (string) $post->post_status ),
		'type'        => $type,
		'enabled'     => $enabled,
		'repetition'  => $repetition,
		'modified'    => mysql_to_rfc3339( (string) $post->post_modified ),
		'markup'      => $markup,
		'bytes'       => strlen( $markup ),
		'block_count' => $stats['block_count'],
		'max_depth'   => $stats['max_depth'],
		'hash'        => hash( 'sha256', wp_json_encode( array( 'id' => $post->ID, 'content' => $content, 'modified' => $post->post_modified_gmt, 'type' => $type, 'enabled' => $enabled, 'repetition' => $repetition ), JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE ) ?: '' ),
	);
}
