<?php
/** Atomic native writes for Elementor's global design-system kit settings. */

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

/** @return array<string,mixed> */
function wpagent_elementor_design_system_input_schema(): array {
	$color = array(
		'type' => 'object',
		'properties' => array(
			'id' => array( 'type' => 'string', 'pattern' => '^[a-z0-9][a-z0-9_-]{0,63}$' ),
			'title' => array( 'type' => 'string', 'minLength' => 1, 'maxLength' => 100 ),
			'value' => array( 'type' => 'string', 'minLength' => 1, 'maxLength' => 100 ),
		),
		'required' => array( 'id', 'title', 'value' ),
		'additionalProperties' => false,
	);
	$typography = array(
		'type' => 'object',
		'properties' => array(
			'id' => array( 'type' => 'string', 'pattern' => '^[a-z0-9][a-z0-9_-]{0,63}$' ),
			'title' => array( 'type' => 'string', 'minLength' => 1, 'maxLength' => 100 ),
			'styles' => array( 'type' => 'object', 'additionalProperties' => true ),
		),
		'required' => array( 'id', 'title', 'styles' ),
		'additionalProperties' => false,
	);
	return array(
		'type' => 'object',
		'properties' => array(
			'expected_hash' => array( 'type' => 'string', 'pattern' => '^[a-f0-9]{64}$' ),
			'system_colors' => array( 'type' => 'array', 'minItems' => 4, 'maxItems' => 4, 'items' => $color ),
			'custom_colors' => array( 'type' => 'array', 'maxItems' => WPAGENT_ELEMENTOR_DESIGN_MAX_TOKENS, 'items' => $color ),
			'system_typography' => array( 'type' => 'array', 'minItems' => 4, 'maxItems' => 4, 'items' => $typography ),
			'custom_typography' => array( 'type' => 'array', 'maxItems' => WPAGENT_ELEMENTOR_DESIGN_MAX_TOKENS, 'items' => $typography ),
			'fallback_font' => array( 'type' => 'string', 'minLength' => 1, 'maxLength' => 200 ),
		),
		'required' => array( 'expected_hash' ),
		'additionalProperties' => false,
	);
}

function wpagent_ability_update_elementor_design_system(): array {
	$output = wpagent_elementor_design_system_output_schema();
	$output['properties']['previous_hash'] = array( 'type' => 'string' );
	$output['properties']['changed'] = array( 'type' => 'boolean' );
	$output['properties']['verified'] = array( 'type' => 'boolean' );
	$output['properties']['rolled_back'] = array( 'type' => 'boolean' );
	return array(
		'label' => __( 'Elementor-Designsystem aktualisieren', 'wp-agent-companion' ),
		'description' => __( 'Ersetzt ausgewählte globale Elementor-Tokenlisten atomar über das aktive Kit. Konfliktschutz, exakter Readback, Cache-Leerung und automatischer Rollback sichern die Änderung.', 'wp-agent-companion' ),
		'category' => 'wp-agent',
		'input_schema' => wpagent_elementor_design_system_input_schema(),
		'output_schema' => $output,
		'execute_callback' => 'wpagent_exec_update_elementor_design_system',
		'permission_callback' => 'wpagent_perm_manage_options',
		'meta' => array( 'show_in_rest' => true, 'annotations' => array( 'readonly' => false, 'destructive' => false, 'idempotent' => true ) ),
	);
}

/** @return array<string,mixed>|WP_Error */
function wpagent_exec_update_elementor_design_system( $input ) {
	$input = is_array( $input ) ? $input : array();
	$kit = wpagent_elementor_design_active_kit();
	if ( is_wp_error( $kit ) ) {
		return $kit;
	}
	$expected_hash = is_string( $input['expected_hash'] ?? null ) ? $input['expected_hash'] : '';
	if ( ! preg_match( '/^[a-f0-9]{64}$/', $expected_hash ) ) {
		return new WP_Error( 'wpagent_elementor_design_bad_hash', __( 'expected_hash muss ein vollständiger SHA-256-Hash sein.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$managed_keys = array( 'system_colors', 'custom_colors', 'system_typography', 'custom_typography', 'fallback_font' );
	$provided = array_values( array_filter( $managed_keys, static fn( string $key ): bool => array_key_exists( $key, $input ) ) );
	if ( ! $provided ) {
		return new WP_Error( 'wpagent_elementor_design_no_changes', __( 'Mindestens ein globaler Elementor-Designbereich muss angegeben werden.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	if ( array_diff( array_keys( $input ), array_merge( array( 'expected_hash' ), $managed_keys ) ) ) {
		return new WP_Error( 'wpagent_elementor_design_unknown_field', __( 'Die Anfrage enthält ein unbekanntes Elementor-Designfeld.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}

	$before = wpagent_elementor_design_system_state( $kit );
	if ( is_wp_error( $before ) ) {
		return $before;
	}
	if ( ! hash_equals( $before['hash'], $expected_hash ) ) {
		return new WP_Error( 'wpagent_elementor_design_conflict', __( 'Das globale Elementor-Designsystem wurde seit dem letzten Lesen geändert.', 'wp-agent-companion' ), array( 'status' => 409, 'current_hash' => $before['hash'] ) );
	}
	$allowed_extra_keys = array();
	foreach ( array_merge( $before['system_typography'], $before['custom_typography'] ) as $item ) {
		$allowed_extra_keys = array_merge( $allowed_extra_keys, array_keys( $item['styles'] ) );
	}
	$allowed_extra_keys = array_values( array_unique( array_diff( $allowed_extra_keys, wpagent_elementor_design_known_style_keys() ) ) );

	$target = $before;
	foreach ( $provided as $key ) {
		if ( in_array( $key, array( 'system_colors', 'custom_colors' ), true ) ) {
			if ( ! is_array( $input[ $key ] ) ) {
				return new WP_Error( 'wpagent_elementor_design_bad_colors', __( 'Elementor-Farben müssen als Liste übergeben werden.', 'wp-agent-companion' ), array( 'status' => 400 ) );
			}
			$value = wpagent_elementor_design_normalize_colors( $input[ $key ], 'system_colors' === $key );
			if ( is_wp_error( $value ) ) {
				return $value;
			}
			$target[ $key ] = $value;
		} elseif ( in_array( $key, array( 'system_typography', 'custom_typography' ), true ) ) {
			if ( ! is_array( $input[ $key ] ) ) {
				return new WP_Error( 'wpagent_elementor_design_bad_typography', __( 'Elementor-Typografie muss als Liste übergeben werden.', 'wp-agent-companion' ), array( 'status' => 400 ) );
			}
			$value = wpagent_elementor_design_normalize_typography( $input[ $key ], 'system_typography' === $key, false, $allowed_extra_keys );
			if ( is_wp_error( $value ) ) {
				return $value;
			}
			$target[ $key ] = $value;
		} else {
			$value = wpagent_elementor_design_font_list( $input[ $key ], 200, 'wpagent_elementor_design_bad_fallback', true );
			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_fallback', __( 'Die Fallback-Schrift enthält nicht erlaubte CSS-Zeichen.', 'wp-agent-companion' ), array( 'status' => 400 ) );
			}
			$target['fallback_font'] = $value;
		}
	}
	$hash_target = $target;
	unset( $hash_target['kit_id'], $hash_target['elementor_version'], $hash_target['hash'] );
	$target_hash = hash( 'sha256', (string) wp_json_encode( wpagent_elementor_canonicalize( $hash_target ), JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE ) );
	if ( hash_equals( $before['hash'], $target_hash ) ) {
		$before['previous_hash'] = $before['hash'];
		$before['changed'] = false;
		$before['verified'] = true;
		$before['rolled_back'] = false;
		return $before;
	}

	$kit_id = absint( $before['kit_id'] );
	$lock = wpagent_elementor_acquire_lock( $kit_id );
	if ( is_wp_error( $lock ) ) {
		return $lock;
	}
	try {
		$fresh_kit = wpagent_elementor_design_fresh_kit( $kit_id );
		$fresh_before = is_wp_error( $fresh_kit ) ? $fresh_kit : wpagent_elementor_design_system_state( $fresh_kit );
		if ( is_wp_error( $fresh_before ) ) {
			return $fresh_before;
		}
		if ( ! hash_equals( $fresh_before['hash'], $expected_hash ) ) {
			return new WP_Error( 'wpagent_elementor_design_conflict', __( 'Das globale Elementor-Designsystem wurde während der Vorbereitung geändert.', 'wp-agent-companion' ), array( 'status' => 409, 'current_hash' => $fresh_before['hash'] ) );
		}
		try {
			$raw = $fresh_kit->get_data( 'settings' );
		} catch ( Throwable ) {
			return new WP_Error( 'wpagent_elementor_design_read_failed', __( 'Elementor konnte die ursprünglichen Kit-Einstellungen nicht lesen.', 'wp-agent-companion' ), array( 'status' => 500 ) );
		}
		if ( ! is_array( $raw ) ) {
			return new WP_Error( 'wpagent_elementor_design_read_failed', __( 'Elementor konnte die ursprünglichen Kit-Einstellungen nicht lesen.', 'wp-agent-companion' ), array( 'status' => 500 ) );
		}
		$original_raw = $raw;
		foreach ( $provided as $key ) {
			if ( in_array( $key, array( 'system_colors', 'custom_colors' ), true ) ) {
				$raw[ $key ] = wpagent_elementor_design_colors_to_provider( $target[ $key ] );
			} elseif ( in_array( $key, array( 'system_typography', 'custom_typography' ), true ) ) {
				$raw[ $key ] = wpagent_elementor_design_typography_to_provider( $target[ $key ] );
			} else {
				$raw['default_generic_fonts'] = $target['fallback_font'];
			}
		}
		$encoded = wp_json_encode( $raw );
		if ( false === $encoded || strlen( $encoded ) > WPAGENT_ELEMENTOR_DESIGN_MAX_BYTES ) {
			return new WP_Error( 'wpagent_elementor_design_payload_size', __( 'Das globale Elementor-Designsystem ist für diesen sicheren Pfad zu groß.', 'wp-agent-companion' ), array( 'status' => 413 ) );
		}
		try {
			$saved = $fresh_kit->save( array( 'settings' => $raw ) );
		} catch ( Throwable ) {
			$saved = false;
		}
		if ( true !== $saved ) {
			$rolled_back = wpagent_elementor_design_restore_raw( $kit_id, $original_raw );
			return new WP_Error( 'wpagent_elementor_design_save_failed', __( 'Elementor konnte das globale Designsystem nicht speichern.', 'wp-agent-companion' ), array( 'status' => 500, 'rolled_back' => $rolled_back ) );
		}
		$read_kit = wpagent_elementor_design_fresh_kit( $kit_id );
		$after = is_wp_error( $read_kit ) ? $read_kit : wpagent_elementor_design_system_state( $read_kit );
		if ( is_wp_error( $after ) || ! hash_equals( $target_hash, $after['hash'] ) ) {
			$rolled_back = wpagent_elementor_design_restore_raw( $kit_id, $original_raw );
			return new WP_Error( 'wpagent_elementor_design_verify_failed', __( 'Elementors Readback stimmt nicht mit dem angeforderten globalen Designsystem überein.', 'wp-agent-companion' ), array( 'status' => 500, 'rolled_back' => $rolled_back ) );
		}
		$after['previous_hash'] = $before['hash'];
		$after['changed'] = true;
		$after['verified'] = true;
		$after['rolled_back'] = false;
		return $after;
	} finally {
		wpagent_elementor_release_lock( $kit_id, $lock );
	}
}
