<?php
/** Server-side Elementor provider for the confirmed Live Editor workspace. */

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

/** @return string[] */
function wpagent_companion_live_editor_elementor_operations(): array {
	return array(
		'open-document',
		'update-document',
		'update-element',
		'create-element',
		'duplicate-element',
		'move-element',
		'delete-element',
		'restore-revision',
	);
}

function wpagent_companion_live_editor_is_elementor_action( string $action ): bool {
	return in_array( $action, array( 'open-elementor-document', 'elementor-mutate' ), true );
}

/** @return true|WP_Error */
function wpagent_companion_live_editor_check_elementor_command_access( array $session, string $action, array $args ) {
	$executor = wpagent_companion_live_editor_executor( $session );
	if ( is_wp_error( $executor ) ) {
		return $executor;
	}
	$post_id = absint( $args['post_id'] ?? 0 );
	if ( $post_id < 1 || ! user_can( $executor, 'edit_post', $post_id ) ) {
		return new WP_Error( 'wpagent_live_editor_post_forbidden', __( 'Der gebundene Agent-Nutzer darf dieses Elementor-Dokument nicht bearbeiten.', 'wp-agent-companion' ), array( 'status' => 403 ) );
	}
	if ( 'open-elementor-document' === $action ) {
		return true;
	}
	$page = is_array( $session['page'] ?? null ) ? $session['page'] : array();
	if ( true !== ( $page['ready'] ?? false ) || 'elementor' !== (string) ( $page['kind'] ?? '' )
		|| $post_id !== absint( $page['post_id'] ?? 0 ) || $post_id !== absint( $args['expected_post_id'] ?? 0 ) ) {
		return new WP_Error( 'wpagent_live_editor_editor_required', __( 'Öffne zuerst dieses Elementor-Dokument im Live-Editor.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	return true;
}

/** @return string|WP_Error */
function wpagent_companion_live_editor_elementor_edit_url( $document, int $post_id ) {
	if ( ! is_object( $document ) || ! method_exists( $document, 'get_edit_url' ) ) {
		return new WP_Error( 'wpagent_live_editor_elementor_url', __( 'Elementor stellte keine sichere Editor-URL bereit.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	$url = (string) $document->get_edit_url();
	$target = wp_parse_url( $url );
	$admin = wp_parse_url( admin_url() );
	if ( ! is_array( $target ) || ! is_array( $admin )
		|| strtolower( (string) ( $target['scheme'] ?? '' ) ) !== strtolower( (string) ( $admin['scheme'] ?? '' ) )
		|| strtolower( (string) ( $target['host'] ?? '' ) ) !== strtolower( (string) ( $admin['host'] ?? '' ) )
		|| (int) ( $target['port'] ?? 0 ) !== (int) ( $admin['port'] ?? 0 ) ) {
		return new WP_Error( 'wpagent_live_editor_elementor_url', __( 'Elementor stellte keine same-origin Editor-URL bereit.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	$admin_path = rtrim( (string) ( $admin['path'] ?? '/' ), '/' ) . '/';
	$target_path = (string) ( $target['path'] ?? '' );
	if ( ! str_starts_with( $target_path, $admin_path ) ) {
		return new WP_Error( 'wpagent_live_editor_elementor_url', __( 'Elementor stellte keine WordPress-Backend-URL bereit.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	$query = array();
	parse_str( (string) ( $target['query'] ?? '' ), $query );
	if ( $post_id !== absint( $query['post'] ?? 0 ) || 'elementor' !== sanitize_key( (string) ( $query['action'] ?? '' ) ) ) {
		return new WP_Error( 'wpagent_live_editor_elementor_url', __( 'Elementor stellte keine URL für das bestätigte Dokument bereit.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	return $url;
}

/** @return array<string,mixed>|WP_Error */
function wpagent_companion_live_editor_elementor_page_descriptor( int $post_id ) {
	$loaded = wpagent_elementor_editable_document( $post_id );
	if ( is_wp_error( $loaded ) ) {
		return $loaded;
	}
	$state = wpagent_elementor_document_state( $post_id, $loaded['document'] );
	$url = wpagent_companion_live_editor_elementor_edit_url( $loaded['document'], $post_id );
	if ( is_wp_error( $url ) ) {
		return $url;
	}
	return array(
		'kind'             => 'elementor',
		'post_id'          => $post_id,
		'title'            => wp_html_excerpt( sanitize_text_field( (string) $loaded['post']->post_title ), 200, '' ),
		'edit_url'         => $url,
		'state_hash'       => (string) $state['hash'],
		'elementor_version' => (string) $state['elementor_version'],
	);
}

/** @return array<string,mixed> */
function wpagent_companion_live_editor_elementor_result_summary( array $result ): array {
	$summary = array();
	foreach ( array( 'post_id', 'hash', 'previous_hash', 'revision_id', 'safety_revision_id', 'element_id', 'operation', 'changed', 'verified', 'frontend_verified', 'element_count' ) as $key ) {
		if ( array_key_exists( $key, $result ) ) {
			$summary[ $key ] = $result[ $key ];
		}
	}
	foreach ( array( 'path', 'previous_path' ) as $key ) {
		if ( isset( $result[ $key ] ) && is_array( $result[ $key ] ) ) {
			$summary[ $key ] = array_map( 'absint', array_slice( $result[ $key ], 0, 64 ) );
		}
	}
	if ( isset( $result['widget_types'] ) && is_array( $result['widget_types'] ) ) {
		$summary['widget_types'] = array_values( array_slice( array_filter( $result['widget_types'], 'is_string' ), 0, 100 ) );
	}
	if ( isset( $result['page'] ) && is_array( $result['page'] ) ) {
		$summary['page'] = array(
			'kind' => 'elementor',
			'post_id' => absint( $result['page']['post_id'] ?? 0 ),
			'title' => wp_html_excerpt( sanitize_text_field( (string) ( $result['page']['title'] ?? '' ) ), 200, '' ),
			'edit_url' => (string) ( $result['page']['edit_url'] ?? '' ),
			'state_hash' => (string) ( $result['page']['state_hash'] ?? '' ),
			'elementor_version' => (string) ( $result['page']['elementor_version'] ?? '' ),
		);
	}
	return $summary;
}

/** @return array<string,mixed>|WP_Error */
function wpagent_companion_live_editor_dispatch_elementor( array $command ) {
	$args = is_array( $command['args'] ?? null ) ? $command['args'] : array();
	$operation = is_string( $args['operation'] ?? null ) ? $args['operation'] : '';
	$post_id = absint( $args['post_id'] ?? 0 );
	if ( ! in_array( $operation, wpagent_companion_live_editor_elementor_operations(), true ) || $post_id < 1 ) {
		return new WP_Error( 'wpagent_live_editor_elementor_operation', __( 'Die Elementor-Arbeitsfläche kennt diese Operation nicht.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	if ( 'open-document' === $operation ) {
		$page = wpagent_companion_live_editor_elementor_page_descriptor( $post_id );
		return is_wp_error( $page ) ? $page : array( 'post_id' => $post_id, 'hash' => $page['state_hash'], 'page' => $page );
	}
	$expected_hash = is_string( $args['expected_hash'] ?? null ) ? $args['expected_hash'] : '';
	if ( ! preg_match( '/^[a-f0-9]{64}$/D', $expected_hash ) ) {
		return new WP_Error( 'wpagent_live_editor_elementor_hash', __( 'Die Elementor-Operation besitzt keinen gültigen erwarteten Zustand.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$loaded = wpagent_elementor_editable_document( $post_id );
	if ( is_wp_error( $loaded ) ) {
		return $loaded;
	}
	$current = wpagent_elementor_document_state( $post_id, $loaded['document'] );
	if ( ! hash_equals( (string) $current['hash'], $expected_hash ) ) {
		return new WP_Error( 'wpagent_elementor_conflict', __( 'Das Elementor-Dokument wurde seit der Bestätigung verändert.', 'wp-agent-companion' ), array( 'status' => 409, 'current_hash' => $current['hash'] ) );
	}
	$input = $args;
	unset( $input['reason'], $input['operation'], $input['expected_post_id'] );
	$callbacks = array(
		'update-document' => 'wpagent_exec_update_elementor_document',
		'update-element'  => 'wpagent_exec_update_elementor_element',
		'create-element'  => 'wpagent_exec_create_elementor_element',
		'duplicate-element' => 'wpagent_exec_duplicate_elementor_element',
		'move-element'    => 'wpagent_exec_move_elementor_element',
		'delete-element'  => 'wpagent_exec_delete_elementor_element',
		'restore-revision' => 'wpagent_exec_restore_elementor_revision',
	);
	if ( ! isset( $callbacks[ $operation ] ) ) {
		return new WP_Error( 'wpagent_live_editor_elementor_operation', __( 'Die Elementor-Operation ist nicht ausführbar.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	if ( 'delete-element' === $operation ) {
		$input['confirm'] = true;
	}
	$result = $callbacks[ $operation ]( $input );
	if ( is_wp_error( $result ) ) {
		return $result;
	}
	$page = wpagent_companion_live_editor_elementor_page_descriptor( $post_id );
	if ( is_wp_error( $page ) ) {
		return $page;
	}
	$result['page'] = $page;
	return $result;
}

/** @return array<string,mixed> */
function wpagent_companion_live_editor_elementor_error_result( WP_Error $error ): array {
	return array(
		'code' => sanitize_key( $error->get_error_code() ),
		'status' => method_exists( $error, 'get_error_data' ) && is_array( $error->get_error_data() ) ? absint( $error->get_error_data()['status'] ?? 500 ) : 500,
	);
}

/** @return array<string,mixed>|WP_Error */
function wpagent_companion_live_editor_elementor_store_outcome( string $session_id, array $running, string $status, array $result, string $error, array $page = array() ) {
	$command_id = (string) ( $running['command_id'] ?? '' );
	$option = wpagent_companion_live_editor_command_option( $command_id );
	$completed = $running;
	$completed['status'] = $status;
	$completed['result'] = $result;
	$completed['error'] = wp_html_excerpt( wp_strip_all_tags( $error ), 2000, '' );
	$completed['completed_at'] = time();
	if ( ! wpagent_companion_live_editor_compare_and_store_record( $option, $running, $completed ) ) {
		$current = get_option( $option, null );
		if ( is_array( $current ) && in_array( (string) ( $current['status'] ?? '' ), array( 'completed', 'failed', 'denied', 'recovery_required' ), true ) ) {
			return wpagent_companion_live_editor_public_command( $current );
		}
		if ( is_array( $current ) && 'running' === (string) ( $current['status'] ?? '' ) ) {
			$recovery = $current;
			$recovery['status'] = 'recovery_required';
			$recovery['result'] = $result;
			$recovery['error'] = __( 'Die Elementor-Änderung wurde ausgeführt, ihr Ergebnis konnte aber nicht sicher gespeichert werden. Nicht erneut ausführen. Prüfe das Dokument und stelle bei Bedarf die Sicherheitsrevision wieder her.', 'wp-agent-companion' );
			$recovery['completed_at'] = time();
			if ( wpagent_companion_live_editor_compare_and_store_record( $option, $current, $recovery ) ) {
				return wpagent_companion_live_editor_public_command( $recovery );
			}
		}
		return new WP_Error( 'wpagent_live_editor_recovery_write', __( 'Das Elementor-Ergebnis konnte nicht sicher gespeichert werden. Nicht erneut ausführen.', 'wp-agent-companion' ), array( 'status' => 500 ) );
	}
	$lock = wpagent_companion_live_editor_acquire_lock( $session_id );
	if ( ! is_wp_error( $lock ) ) {
		try {
			$session = wpagent_companion_live_editor_get_session( $session_id );
			if ( ! is_wp_error( $session ) ) {
				if ( $page ) {
					$session['page'] = array(
						'kind' => 'elementor',
						'post_id' => absint( $page['post_id'] ?? 0 ),
						'title' => wp_html_excerpt( sanitize_text_field( (string) ( $page['title'] ?? '' ) ), 200, '' ),
						'path' => '',
						'ready' => false,
						'dirty' => false,
						'state_hash' => (string) ( $page['state_hash'] ?? '' ),
					);
				}
				$session = wpagent_companion_live_editor_archive_command( $session, $command_id );
				wpagent_companion_live_editor_store_record( wpagent_companion_live_editor_session_option( $session_id ), $session );
			}
		} finally {
			wpagent_companion_live_editor_release_lock( $session_id, $lock );
		}
	}
	return wpagent_companion_live_editor_public_command( $completed );
}

/** @return array<string,mixed>|WP_Error */
function wpagent_companion_live_editor_execute_elementor_command( string $session_id, string $command_id ) {
	$session = wpagent_companion_live_editor_get_session( $session_id );
	if ( is_wp_error( $session ) ) {
		return $session;
	}
	if ( ! current_user_can( 'manage_options' ) || get_current_user_id() !== absint( $session['owner_id'] ?? 0 ) ) {
		return new WP_Error( 'wpagent_live_editor_owner_required', __( 'Diese Live-Editor-Sitzung gehört zu einem anderen Administrator.', 'wp-agent-companion' ), array( 'status' => 403 ) );
	}
	if ( ! preg_match( '/^[a-f0-9]{24}$/D', $command_id ) ) {
		return new WP_Error( 'wpagent_live_editor_command_missing', __( 'Der Live-Editor-Befehl wurde nicht gefunden.', 'wp-agent-companion' ), array( 'status' => 404 ) );
	}
	$lock = wpagent_companion_live_editor_acquire_lock( $session_id );
	if ( is_wp_error( $lock ) ) {
		return $lock;
	}
	try {
		$session = wpagent_companion_live_editor_get_session( $session_id );
		if ( is_wp_error( $session ) ) {
			return $session;
		}
		if ( ! current_user_can( 'manage_options' ) || get_current_user_id() !== absint( $session['owner_id'] ?? 0 ) ) {
			return new WP_Error( 'wpagent_live_editor_owner_required', __( 'Diese Live-Editor-Sitzung gehört zu einem anderen Administrator.', 'wp-agent-companion' ), array( 'status' => 403 ) );
		}
		$option = wpagent_companion_live_editor_command_option( $command_id );
		$command = get_option( $option, null );
		if ( ! is_array( $command ) || ! hash_equals( $session_id, (string) ( $command['session_id'] ?? '' ) ) ) {
			return new WP_Error( 'wpagent_live_editor_command_missing', __( 'Der Live-Editor-Befehl wurde nicht gefunden.', 'wp-agent-companion' ), array( 'status' => 404 ) );
		}
		if ( in_array( (string) ( $command['status'] ?? '' ), array( 'completed', 'failed', 'denied', 'recovery_required' ), true ) ) {
			return wpagent_companion_live_editor_public_command( $command );
		}
		if ( 'awaiting_confirmation' !== (string) ( $command['status'] ?? '' ) || empty( $command['requires_confirmation'] ) || ! wpagent_companion_live_editor_is_elementor_action( (string) ( $command['action'] ?? '' ) ) ) {
			return new WP_Error( 'wpagent_live_editor_command_state', __( 'Der Live-Editor-Befehl kann nicht als Elementor-Aktion ausgeführt werden.', 'wp-agent-companion' ), array( 'status' => 409 ) );
		}
		if ( absint( $command['expires_at'] ?? 0 ) <= time() ) {
			return new WP_Error( 'wpagent_live_editor_command_expired', __( 'Der Live-Editor-Befehl ist abgelaufen.', 'wp-agent-companion' ), array( 'status' => 410 ) );
		}
		$access = wpagent_companion_live_editor_check_elementor_command_access( $session, (string) $command['action'], is_array( $command['args'] ?? null ) ? $command['args'] : array() );
		if ( is_wp_error( $access ) ) {
			return $access;
		}
		$running = $command;
		$running['status'] = 'running';
		$running['started_at'] = time();
		if ( ! wpagent_companion_live_editor_compare_and_store_record( $option, $command, $running ) ) {
			return new WP_Error( 'wpagent_live_editor_command_state', __( 'Der Live-Editor-Befehl wurde bereits anderweitig übernommen.', 'wp-agent-companion' ), array( 'status' => 409 ) );
		}
	} finally {
		wpagent_companion_live_editor_release_lock( $session_id, $lock );
	}

	$previous_user_id = get_current_user_id();
	wp_set_current_user( absint( $session['executor_id'] ?? 0 ) );
	try {
		$execution = wpagent_companion_live_editor_dispatch_elementor( $running );
	} finally {
		wp_set_current_user( $previous_user_id );
	}
	if ( is_wp_error( $execution ) ) {
		return wpagent_companion_live_editor_elementor_store_outcome(
			$session_id,
			$running,
			'failed',
			wpagent_companion_live_editor_elementor_error_result( $execution ),
			$execution->get_error_message()
		);
	}
	$page = is_array( $execution['page'] ?? null ) ? $execution['page'] : array();
	return wpagent_companion_live_editor_elementor_store_outcome(
		$session_id,
		$running,
		'completed',
		wpagent_companion_live_editor_elementor_result_summary( $execution ),
		'',
		$page
	);
}
