<?php
/** Verified application of native WordPress Global Style Variations. */

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

function wpagent_ability_apply_global_style_variation(): array {
	return array(
		'label'               => __( 'Native Stilvariante anwenden', 'wp-agent-companion' ),
		'description'         => __( 'Wendet eine Theme-Stilvariante mit Konfliktschutz, gemeinsamer Sperre, Read-back und bytegenauem Rollback an. Vollvarianten erhalten vorhandenes freies CSS wie der WordPress-Site-Editor.', 'wp-agent-companion' ),
		'category'            => 'wp-agent',
		'input_schema'        => array(
			'type'       => 'object',
			'properties' => array(
				'variation_id' => wpagent_gs_hash_schema(),
				'expected_hash' => array_merge( wpagent_gs_hash_schema(), array( 'description' => __( 'Exakter state_hash aus get-global-styles oder list-global-style-variations.', 'wp-agent-companion' ) ) ),
				'confirm'       => array( 'type' => 'boolean', 'description' => __( 'Muss true sein, weil die Variante vorhandene Designanpassungen ersetzen kann.', 'wp-agent-companion' ) ),
			),
			'required'             => array( 'variation_id', 'expected_hash', 'confirm' ),
			'additionalProperties' => false,
			'maxProperties'        => 3,
		),
		'output_schema'       => array(
			'type'       => 'object',
			'properties' => array(
				'post_id'             => array( 'type' => 'integer', 'minimum' => 1 ),
				'theme'               => array( 'type' => 'string', 'minLength' => 1, 'maxLength' => 200 ),
				'variation_id'        => wpagent_gs_hash_schema(),
				'title'               => array( 'type' => 'string', 'minLength' => 1, 'maxLength' => 200 ),
				'scope'               => array( 'type' => 'string', 'enum' => array( 'full', 'color', 'typography' ) ),
				'previous_state_hash' => wpagent_gs_hash_schema(),
				'state_hash'          => wpagent_gs_hash_schema(),
				'verified'            => array( 'type' => 'boolean' ),
			),
			'required'             => array( 'post_id', 'theme', 'variation_id', 'title', 'scope', 'previous_state_hash', 'state_hash', 'verified' ),
			'additionalProperties' => false,
			'maxProperties'        => 8,
		),
		'execute_callback'    => 'wpagent_exec_apply_global_style_variation',
		'permission_callback' => 'wpagent_perm_edit_theme_options',
		'meta'                => array( 'show_in_rest' => true, 'annotations' => array( 'readonly' => false, 'destructive' => true, 'idempotent' => false ) ),
	);
}

/** @return array<string,mixed>|WP_Error */
function wpagent_exec_apply_global_style_variation( $input ) {
	$input = wpagent_gs_validate_variation_apply_input( $input );
	if ( is_wp_error( $input ) ) {
		return $input;
	}
	$hash         = $input['expected_hash'];
	$variation_id = $input['variation_id'];
	$lock = wpagent_gs_acquire_lock();
	if ( is_wp_error( $lock ) ) {
		return $lock;
	}
	try {
		return wpagent_exec_apply_global_style_variation_locked( $variation_id, $hash, $lock );
	} finally {
		wpagent_gs_release_lock( $lock );
	}
}

/** @return array<string,mixed>|WP_Error */
function wpagent_gs_validate_variation_apply_input( $input ) {
	if ( ! is_array( $input ) || array_is_list( $input ) || array_diff( array_keys( $input ), array( 'variation_id', 'expected_hash', 'confirm' ) ) ) {
		return new WP_Error( 'wpagent_gs_variation_input', __( 'Die Stilvarianten-Eingabe enthält unbekannte oder ungültige Felder.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	if ( ! array_key_exists( 'variation_id', $input ) || ! array_key_exists( 'expected_hash', $input ) || ! array_key_exists( 'confirm', $input ) ) {
		return new WP_Error( 'wpagent_gs_variation_input', __( 'variation_id, expected_hash und confirm müssen gesetzt sein.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	if ( true !== $input['confirm'] ) {
		return new WP_Error( 'wpagent_gs_variation_confirmation', __( 'Das Anwenden einer Stilvariante muss ausdrücklich mit confirm=true bestätigt werden.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$hash = wpagent_gs_expected_hash( $input['expected_hash'] );
	if ( is_wp_error( $hash ) ) {
		return $hash;
	}
	$variation_id = is_string( $input['variation_id'] ) ? strtolower( $input['variation_id'] ) : '';
	if ( ! preg_match( '/^[a-f0-9]{64}$/', $variation_id ) ) {
		return new WP_Error( 'wpagent_gs_variation_id', __( 'variation_id muss eine vollständige Stilvarianten-ID sein.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	return array(
		'variation_id'  => $variation_id,
		'expected_hash' => $hash,
		'confirm'       => true,
	);
}

/** @return array<string,mixed>|WP_Error */
function wpagent_exec_apply_global_style_variation_locked( string $variation_id, string $expected_hash, string $lock ) {
	$state = wpagent_gs_state();
	if ( is_wp_error( $state ) ) {
		return $state;
	}
	if ( ! hash_equals( (string) $state['state_hash'], $expected_hash ) ) {
		return new WP_Error( 'wpagent_gs_conflict', __( 'Die Global Styles wurden seit dem Lesen verändert.', 'wp-agent-companion' ), array( 'status' => 409, 'current_hash' => $state['state_hash'] ) );
	}
	$record = wpagent_gs_find_variation( $variation_id );
	if ( is_wp_error( $record ) ) {
		return $record;
	}
	if ( (string) $state['theme'] !== (string) get_stylesheet() ) {
		return new WP_Error( 'wpagent_gs_variation_theme_changed', __( 'Das aktive Theme wurde während der Vorbereitung gewechselt. Lies die Stilvarianten erneut.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}

	$planned = wpagent_gs_plan_style_variation( $state, $record );
	if ( is_wp_error( $planned ) ) {
		return $planned;
	}
	$json = wpagent_gs_encode_user_config( $planned );
	if ( is_wp_error( $json ) ) {
		return $json;
	}
	if ( strlen( $json ) > WPAGENT_GLOBAL_STYLES_MAX_BYTES ) {
		return new WP_Error( 'wpagent_gs_variation_result_too_large', __( 'Der resultierende Global-Styles-Datensatz wäre größer als 512 KiB und wurde nicht gespeichert.', 'wp-agent-companion' ), array( 'status' => 413 ) );
	}
	if ( (string) get_stylesheet() !== (string) $state['theme'] ) {
		return new WP_Error( 'wpagent_gs_variation_theme_changed', __( 'Das aktive Theme wurde während der Vorbereitung gewechselt. Lies die Stilvarianten erneut.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	if ( ! current_user_can( 'edit_theme_options' ) || ! wpagent_gs_refresh_lock( $lock ) || ! wpagent_gs_lock_is_owned( $lock ) ) {
		return new WP_Error( 'wpagent_gs_variation_write_precondition_changed', __( 'Berechtigung oder exklusive Global-Styles-Sperre ging vor dem Schreiben verloren. Es wurde nichts geändert.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	$prewrite = wpagent_gs_state();
	if ( is_wp_error( $prewrite ) ) {
		return $prewrite;
	}
	if ( ! hash_equals( (string) $state['state_hash'], (string) $prewrite['state_hash'] ) || (string) $prewrite['theme'] !== (string) $state['theme'] ) {
		return new WP_Error( 'wpagent_gs_conflict', __( 'Die Global Styles wurden während der Vorbereitung verändert. Lies sie neu und wiederhole den Vorgang.', 'wp-agent-companion' ), array( 'status' => 409, 'current_hash' => $prewrite['state_hash'] ) );
	}
	$candidate = wpagent_gs_write_if_current( $prewrite, $json );
	if ( is_wp_error( $candidate ) ) {
		return $candidate;
	}
	if ( ! current_user_can( 'edit_theme_options' ) || ! wpagent_gs_refresh_lock( $lock ) || ! wpagent_gs_lock_is_owned( $lock ) ) {
		return wpagent_gs_fail_after_rollback( $state, $candidate, $lock, new WP_Error( 'wpagent_gs_variation_write_precondition_changed', __( 'Berechtigung oder exklusive Global-Styles-Sperre ging nach dem Schreiben verloren. Ein fremder Zwischenstand wird nicht überschrieben.', 'wp-agent-companion' ), array( 'status' => 500 ) ) );
	}
	clean_post_cache( (int) $state['post_id'] );
	$post   = get_post( (int) $state['post_id'] );
	$reread = $post ? json_decode( (string) $post->post_content, true ) : null;
	if ( ! is_array( $reread ) || $planned !== $reread ) {
		return wpagent_gs_fail_after_rollback(
			$state,
			$candidate,
			$lock,
			new WP_Error( 'wpagent_gs_variation_verify', __( 'Die Stilvariante wurde nicht exakt wie geplant gespeichert.', 'wp-agent-companion' ), array( 'status' => 500 ) )
		);
	}
	$fresh = wpagent_gs_state();
	if ( is_wp_error( $fresh ) ) {
		return $fresh;
	}
	if ( (string) $fresh['theme'] !== (string) $state['theme'] ) {
		return new WP_Error( 'wpagent_gs_variation_theme_changed', __( 'Das aktive Theme wurde während des Schreibens gewechselt.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	if ( ! current_user_can( 'edit_theme_options' ) || ! wpagent_gs_refresh_lock( $lock ) || ! wpagent_gs_lock_is_owned( $lock ) ) {
		return wpagent_gs_fail_after_rollback( $state, $candidate, $lock, new WP_Error( 'wpagent_gs_variation_write_precondition_changed', __( 'Berechtigung oder exklusive Global-Styles-Sperre ging während der Rückleseprüfung verloren. Ein fremder Zwischenstand wird nicht überschrieben.', 'wp-agent-companion' ), array( 'status' => 500 ) ) );
	}
	if ( ! wpagent_gs_final_state_matches( $fresh, $state, $planned, $candidate ) ) {
		// The first read-back already matched our plan. A later mismatch is an
		// external concurrent write and must never be overwritten by rollback.
		return new WP_Error( 'wpagent_gs_state_changed', __( 'Der aktive Global-Styles-Zustand wurde während des Schreibens erneut verändert.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}

	return array(
		'post_id'             => (int) $fresh['post_id'],
		'theme'               => (string) $fresh['theme'],
		'variation_id'        => $record['variation_id'],
		'title'               => $record['title'],
		'scope'               => $record['scope'],
		'previous_state_hash' => (string) $state['state_hash'],
		'state_hash'          => (string) $fresh['state_hash'],
		'verified'            => true,
	);
}

/** @return array<string,mixed>|WP_Error */
function wpagent_gs_plan_style_variation( array $state, array $record ) {
	$variation = $record['variation'];
	$settings  = isset( $variation['settings'] ) && is_array( $variation['settings'] ) ? $variation['settings'] : array();
	$styles    = isset( $variation['styles'] ) && is_array( $variation['styles'] ) ? $variation['styles'] : array();
	$user      = $state['snapshot'];

	if ( 'full' === $record['scope'] ) {
		$user_styles = isset( $user['styles'] ) && is_array( $user['styles'] ) ? $user['styles'] : array();
		$theme_css   = wpagent_gs_variation_css( $styles['css'] ?? null, 'styles.css' );
		$user_css    = wpagent_gs_variation_css( $user_styles['css'] ?? null, 'styles.css' );
		if ( is_wp_error( $theme_css ) || is_wp_error( $user_css ) ) {
			return is_wp_error( $theme_css ) ? $theme_css : $user_css;
		}
		if ( '' !== $theme_css || '' !== $user_css ) {
			$styles['css'] = wpagent_gs_variation_combine_css( $theme_css, $user_css );
		}
		$user_blocks = isset( $user_styles['blocks'] ) && is_array( $user_styles['blocks'] ) ? $user_styles['blocks'] : array();
		foreach ( $user_blocks as $block_name => $block_styles ) {
			if ( ! is_string( $block_name ) || ! is_array( $block_styles ) || ! array_key_exists( 'css', $block_styles ) ) {
				continue;
			}
			$user_block_css = wpagent_gs_variation_css( $block_styles['css'], 'styles.blocks.' . $block_name . '.css' );
			$theme_block_css = wpagent_gs_variation_css( $styles['blocks'][ $block_name ]['css'] ?? null, 'styles.blocks.' . $block_name . '.css' );
			if ( is_wp_error( $user_block_css ) || is_wp_error( $theme_block_css ) ) {
				return is_wp_error( $user_block_css ) ? $user_block_css : $theme_block_css;
			}
			$user_block_css = trim( $user_block_css );
			if ( ! isset( $styles['blocks'] ) || ! is_array( $styles['blocks'] ) ) {
				$styles['blocks'] = array();
			}
			if ( ! isset( $styles['blocks'][ $block_name ] ) || ! is_array( $styles['blocks'][ $block_name ] ) ) {
				$styles['blocks'][ $block_name ] = array();
			}
			$styles['blocks'][ $block_name ]['css'] = wpagent_gs_variation_combine_css( $theme_block_css, $user_block_css );
		}
	} else {
		$config = array(
			'settings' => isset( $user['settings'] ) && is_array( $user['settings'] ) ? $user['settings'] : array(),
			'styles'   => isset( $user['styles'] ) && is_array( $user['styles'] ) ? $user['styles'] : array(),
		);
		$properties = 'color' === $record['scope'] ? array( 'color' ) : array( 'typography', 'spacing' );
		$config     = wpagent_gs_variation_remove_properties( $config, $properties );
		$config     = wpagent_gs_variation_merge( $config, array( 'settings' => $settings, 'styles' => $styles ) );
		$settings   = $config['settings'];
		$styles     = $config['styles'];
	}

	return array(
		'version'                     => defined( 'WP_Theme_JSON::LATEST_SCHEMA' ) ? WP_Theme_JSON::LATEST_SCHEMA : 3,
		'isGlobalStylesUserThemeJSON' => true,
		'settings'                    => $settings,
		'styles'                      => $styles,
	);
}
