<?php
/** Verified application of Elementor v4 Global Classes to atomic elements. */

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

function wpagent_ability_set_elementor_element_global_classes(): array {
	$output = wpagent_elementor_element_write_output_schema();
	$output['properties']['global_class_ids'] = array( 'type' => 'array', 'items' => array( 'type' => 'string' ) );
	return array(
		'label'               => __( 'Elementor v4 Global Classes am Element setzen', 'wp-agent-companion' ),
		'description'         => __( 'Ersetzt die Global Classes eines atomaren Elementor-v4-Elements durch eine exakt bestätigte Liste. Konfliktschutz, Revision, Rücklese- und Frontend-Prüfung sowie Rollback sind verpflichtend.', 'wp-agent-companion' ),
		'category'            => 'wp-agent',
		'input_schema'        => array(
			'type'                 => 'object',
			'properties'           => array(
				'post_id'          => array( 'type' => 'integer' ),
				'element_id'       => array( 'type' => 'string', 'pattern' => '^[A-Za-z0-9_-]{1,64}$' ),
				'expected_hash'    => array( 'type' => 'string', 'pattern' => '^[a-f0-9]{64}$' ),
				'global_class_ids' => array( 'type' => 'array', 'maxItems' => 100, 'items' => array( 'type' => 'string', 'pattern' => '^[a-z][a-z0-9_-]{0,63}$' ) ),
			),
			'required'             => array( 'post_id', 'element_id', 'expected_hash', 'global_class_ids' ),
			'additionalProperties' => false,
		),
		'output_schema'       => $output,
		'execute_callback'    => 'wpagent_exec_set_elementor_element_global_classes',
		'permission_callback' => 'wpagent_perm_manage_options',
		'meta'                => array( 'show_in_rest' => true, 'annotations' => array( 'readonly' => false, 'destructive' => false, 'idempotent' => true ) ),
	);
}

/** @return string|WP_Error */
function wpagent_elementor_global_classes_prop_key( array $element ) {
	try {
		$type = \Elementor\Modules\GlobalClasses\Utils\Atomic_Elements_Utils::get_element_type( $element );
		$instance = \Elementor\Modules\GlobalClasses\Utils\Atomic_Elements_Utils::get_element_instance( $type );
		if ( ! \Elementor\Modules\GlobalClasses\Utils\Atomic_Elements_Utils::is_atomic_element( $instance ) || ! method_exists( $instance, 'get_props_schema' ) ) {
			return new WP_Error( 'wpagent_elementor_global_classes_not_atomic', __( 'Global Classes können nur auf atomare Elementor-v4-Elemente angewendet werden.', 'wp-agent-companion' ), array( 'status' => 409 ) );
		}
		$schema = $instance->get_props_schema();
	} catch ( Throwable ) {
		return new WP_Error( 'wpagent_elementor_global_classes_not_atomic', __( 'Elementor konnte das atomare Element-Schema nicht lesen.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	$keys = array();
	foreach ( is_array( $schema ) ? $schema : array() as $key => $prop ) {
		if ( is_string( $key ) && \Elementor\Modules\GlobalClasses\Utils\Atomic_Elements_Utils::is_classes_prop( $prop ) ) {
			$keys[] = $key;
		}
	}
	if ( 1 !== count( $keys ) ) {
		return new WP_Error( 'wpagent_elementor_global_classes_prop_unavailable', __( 'Das atomare Elementor-Element besitzt keine eindeutige Global-Classes-Eigenschaft.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	return $keys[0];
}

/** @return true|WP_Error */
function wpagent_elementor_verify_global_class_render( int $post_id, array $class_ids ) {
	$snapshot = wpagent_elementor_global_classes_snapshot();
	if ( is_wp_error( $snapshot ) ) {
		return $snapshot;
	}
	try {
		$html = \Elementor\Plugin::$instance->frontend->get_builder_content_for_display( $post_id, true );
	} catch ( Throwable ) {
		return new WP_Error( 'wpagent_elementor_global_class_render_failed', __( 'Elementor konnte die Global Classes nicht im Frontend prüfen.', 'wp-agent-companion' ), array( 'status' => 500 ) );
	}
	if ( ! is_string( $html ) || '' === trim( $html ) ) {
		return new WP_Error( 'wpagent_elementor_global_class_render_failed', __( 'Elementor lieferte keine Frontend-Ausgabe für die Global-Class-Prüfung.', 'wp-agent-companion' ), array( 'status' => 500 ) );
	}
	$class_tokens = array();
	if ( preg_match_all( '/\\bclass\\s*=\\s*(["\'])(.*?)\\1/is', $html, $matches ) ) {
		foreach ( $matches[2] as $attribute ) {
			foreach ( preg_split( '/\\s+/', trim( html_entity_decode( $attribute, ENT_QUOTES | ENT_HTML5, 'UTF-8' ) ) ) ?: array() as $token ) {
				if ( '' !== $token ) {
					$class_tokens[ $token ] = true;
				}
			}
		}
	}
	foreach ( $class_ids as $class_id ) {
		$rendered_label = is_string( $snapshot['items'][ $class_id ]['label'] ?? null ) ? $snapshot['items'][ $class_id ]['label'] : '';
		if ( '' === $rendered_label || ! isset( $class_tokens[ $rendered_label ] ) ) {
			return new WP_Error( 'wpagent_elementor_global_class_render_failed', __( 'Mindestens eine Global Class fehlt in Elementors Frontend-Ausgabe.', 'wp-agent-companion' ), array( 'status' => 500, 'class_id' => $class_id ) );
		}
	}
	return true;
}

/** @return array<string,mixed>|WP_Error */
function wpagent_exec_set_elementor_element_global_classes( $input ) {
	$input = is_array( $input ) ? $input : array();
	$capability = wpagent_elementor_global_classes_require_capability( 'elementor_global_classes_apply_class' );
	if ( is_wp_error( $capability ) ) {
		return $capability;
	}
	$post_id = absint( $input['post_id'] ?? 0 );
	$element_id = is_string( $input['element_id'] ?? null ) ? $input['element_id'] : '';
	$expected_hash = is_string( $input['expected_hash'] ?? null ) ? $input['expected_hash'] : '';
	$class_ids = $input['global_class_ids'] ?? null;
	if ( ! preg_match( '/^[A-Za-z0-9_-]{1,64}$/', $element_id ) ) {
		return new WP_Error( 'wpagent_elementor_bad_id', __( 'element_id ist ungültig.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	if ( ! preg_match( '/^[a-f0-9]{64}$/', $expected_hash ) ) {
		return new WP_Error( 'wpagent_elementor_hash', __( 'expected_hash muss ein SHA-256-Hash sein.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	if ( ! is_array( $class_ids ) || ! array_is_list( $class_ids ) || count( $class_ids ) > 100 || count( array_unique( $class_ids ) ) !== count( $class_ids ) ) {
		return new WP_Error( 'wpagent_elementor_global_classes_bad_ids', __( 'global_class_ids muss eine eindeutige Liste mit höchstens 100 IDs sein.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	foreach ( $class_ids as $class_id ) {
		if ( ! is_string( $class_id ) || ! preg_match( '/^[a-z][a-z0-9_-]{0,63}$/', $class_id ) ) {
			return new WP_Error( 'wpagent_elementor_global_classes_bad_ids', __( 'global_class_ids enthält eine ungültige ID.', 'wp-agent-companion' ), array( 'status' => 400 ) );
		}
	}
	$snapshot = wpagent_elementor_global_classes_snapshot();
	if ( is_wp_error( $snapshot ) ) {
		return $snapshot;
	}
	$missing = array_values( array_diff( $class_ids, array_keys( $snapshot['items'] ) ) );
	if ( $missing ) {
		return new WP_Error( 'wpagent_elementor_global_class_not_found', __( 'Mindestens eine Global Class existiert nicht.', 'wp-agent-companion' ), array( 'status' => 404, 'class_ids' => $missing ) );
	}
	$loaded = wpagent_elementor_editable_document( $post_id );
	if ( is_wp_error( $loaded ) ) {
		return $loaded;
	}
	$lock = wpagent_elementor_acquire_lock( $post_id );
	if ( is_wp_error( $lock ) ) {
		return $lock;
	}
	try {
		$loaded = wpagent_elementor_editable_document( $post_id );
		if ( is_wp_error( $loaded ) ) {
			return $loaded;
		}
		$before = wpagent_elementor_document_state( $post_id, $loaded['document'] );
		if ( ! hash_equals( $before['hash'], $expected_hash ) ) {
			return new WP_Error( 'wpagent_elementor_conflict', __( 'Das Elementor-Dokument wurde seit dem Lesen verändert.', 'wp-agent-companion' ), array( 'status' => 409, 'current_hash' => $before['hash'] ) );
		}
		$located = wpagent_elementor_locate_element( $before['elements'], $element_id );
		if ( is_wp_error( $located ) ) {
			return $located;
		}
		$prop_key = wpagent_elementor_global_classes_prop_key( $located['element'] );
		if ( is_wp_error( $prop_key ) ) {
			return $prop_key;
		}
		try {
			$wrapped = \Elementor\Modules\AtomicWidgets\PropTypes\Classes_Prop_Type::generate( $class_ids );
			$validator = \Elementor\Modules\AtomicWidgets\PropTypes\Classes_Prop_Type::make();
		} catch ( Throwable ) {
			return wpagent_elementor_global_classes_unavailable_error();
		}
		if ( ! $validator->validate( $wrapped ) ) {
			return new WP_Error( 'wpagent_elementor_global_classes_bad_ids', __( 'Elementor lehnt die Global-Class-Liste ab.', 'wp-agent-companion' ), array( 'status' => 400 ) );
		}
		$settings = is_array( $located['element']['settings'] ?? null ) ? $located['element']['settings'] : array();
		if ( ( $settings[ $prop_key ] ?? null ) === $wrapped ) {
			$frontend = wpagent_elementor_verify_frontend( $post_id, $before['element_count'] );
			$render = is_wp_error( $frontend ) ? $frontend : wpagent_elementor_verify_global_class_render( $post_id, $class_ids );
			if ( is_wp_error( $render ) ) {
				return $render;
			}
			$before['previous_hash'] = $before['hash'];
			$before['revision_id'] = 0;
			$before['element_id'] = $element_id;
			$before['path'] = $located['path'];
			$before['element'] = $located['element'];
			$before['global_class_ids'] = $class_ids;
			$before['changed'] = false;
			$before['verified'] = true;
			$before['frontend_verified'] = true;
			return $before;
		}
		$settings[ $prop_key ] = $wrapped;
		$elements = $before['elements'];
		if ( ! wpagent_elementor_replace_element_settings( $elements, $element_id, $settings ) ) {
			return new WP_Error( 'wpagent_elementor_element_not_found', __( 'Elementor-Element nicht gefunden.', 'wp-agent-companion' ), array( 'status' => 404 ) );
		}
		$normalized = wpagent_elementor_normalize_elements( $loaded['document'], $elements );
		if ( is_wp_error( $normalized ) ) {
			return $normalized;
		}
		$revision_id = wpagent_elementor_save_revision( $post_id, $before['hash'] );
		if ( is_wp_error( $revision_id ) ) {
			return $revision_id;
		}
		try {
			$saved = wpagent_elementor_save_document( $loaded['document'], array( 'elements' => $elements ), false );
		} catch ( Throwable ) {
			$saved = false;
		}
		$fresh_document = \Elementor\Plugin::$instance->documents->get( $post_id, false );
		$after = is_object( $fresh_document ) ? wpagent_elementor_document_state( $post_id, $fresh_document ) : null;
		$fresh_element = is_array( $after ) ? wpagent_elementor_locate_element( $after['elements'], $element_id ) : null;
		$readback = is_array( $fresh_element ) ? ( $fresh_element['element']['settings'][ $prop_key ] ?? null ) : null;
		$verified = true === $saved && is_array( $after ) && wpagent_elementor_elements_contain_requested( $after['elements'], $normalized ) && $readback === $wrapped;
		$frontend = $verified ? wpagent_elementor_verify_frontend( $post_id, $after['element_count'] ) : false;
		$render = $verified && ! is_wp_error( $frontend ) ? wpagent_elementor_verify_global_class_render( $post_id, $class_ids ) : false;
		if ( ! $verified || is_wp_error( $frontend ) || is_wp_error( $render ) || false === $render ) {
			$rolled_back = wpagent_elementor_restore_revision_internal( $post_id, $revision_id, $before['hash'] );
			return new WP_Error( 'wpagent_elementor_global_class_apply_verify_failed', __( 'Die Global-Class-Änderung bestand die Rücklese- oder Frontend-Prüfung nicht.', 'wp-agent-companion' ), array( 'status' => 500, 'rolled_back' => $rolled_back, 'revision_id' => $revision_id ) );
		}
		$after['previous_hash'] = $before['hash'];
		$after['revision_id'] = $revision_id;
		$after['element_id'] = $element_id;
		$after['path'] = $fresh_element['path'];
		$after['element'] = $fresh_element['element'];
		$after['global_class_ids'] = $class_ids;
		$after['changed'] = true;
		$after['verified'] = true;
		$after['frontend_verified'] = true;
		return $after;
	} finally {
		wpagent_elementor_release_lock( $post_id, $lock );
	}
}
