<?php
/** Atomic lock, provider write and rollback for GeneratePress settings. */

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

/** @return string|WP_Error */
function wpagent_generatepress_acquire_lock() {
	$token = wpagent_companion_acquire_option_lock( WPAGENT_GENERATEPRESS_LOCK_OPTION, WPAGENT_GENERATEPRESS_LOCK_TTL );
	if ( is_string( $token ) ) {
		return $token;
	}
	return new WP_Error( 'wpagent_generatepress_locked', __( 'Die GeneratePress-Einstellungen werden gerade durch einen anderen Vorgang geändert.', 'wp-agent-companion' ), array( 'status' => 409 ) );
}

function wpagent_generatepress_release_lock( string $token ): void {
	wpagent_companion_release_option_lock( WPAGENT_GENERATEPRESS_LOCK_OPTION, $token );
}

/** @param array{settings:array{exists:bool,value:array},cache:array<string,array{exists:bool,value:mixed}>} $snapshot @return true|WP_Error */
function wpagent_generatepress_rollback( array $snapshot, string $expected_hash ) {
	try {
		if ( $snapshot['settings']['exists'] ) {
			update_option( 'generate_settings', $snapshot['settings']['value'], false );
		} else {
			delete_option( 'generate_settings' );
		}
	} catch ( Throwable $error ) {
		// Verify the database state below because third-party option hooks can
		// throw after WordPress has already persisted the rollback value.
	}
	wp_cache_delete( 'generate_settings', 'options' );
	foreach ( $snapshot['cache'] as $name => $state ) {
		try {
			if ( $state['exists'] ) {
				update_option( $name, $state['value'], false );
			} else {
				delete_option( $name );
			}
		} catch ( Throwable $error ) {
			// The exact readback below covers every cached value as well.
		}
		wp_cache_delete( $name, 'options' );
	}
	$fresh = wpagent_generatepress_snapshot();
	if ( is_wp_error( $fresh ) || ! hash_equals( $expected_hash, wpagent_generatepress_state_hash( $fresh ) ) || maybe_serialize( $fresh['cache'] ) !== maybe_serialize( $snapshot['cache'] ) ) {
		return new WP_Error(
			'wpagent_generatepress_rollback_unverified',
			__( 'Das GeneratePress-Rollback konnte nicht verifiziert werden. Prüfe die Theme-Einstellungen sofort manuell.', 'wp-agent-companion' ),
			array( 'status' => 500, 'rollback_verified' => false )
		);
	}
	return true;
}

/** @return WP_Error */
function wpagent_generatepress_fail_after_rollback( array $snapshot, string $previous_hash ) {
	$rollback = wpagent_generatepress_rollback( $snapshot, $previous_hash );
	if ( is_wp_error( $rollback ) ) {
		return $rollback;
	}
	return new WP_Error(
		'wpagent_generatepress_write_unverified',
		__( 'GeneratePress hat die Änderung nicht exakt bestätigt. Der vorherige Zustand und der CSS-Cache wurden verifiziert wiederhergestellt.', 'wp-agent-companion' ),
		array( 'status' => 502, 'rollback_verified' => true )
	);
}

/** @return true|WP_Error */
function wpagent_generatepress_write_and_refresh( array $settings ) {
	try {
		update_option( 'generate_settings', $settings, false );
		wp_cache_delete( 'generate_settings', 'options' );
		generate_update_dynamic_css_cache();
		wp_cache_delete( 'generate_dynamic_css_output', 'options' );
		wp_cache_delete( 'generate_dynamic_css_cached_version', 'options' );
		if ( generate_get_option( 'dynamic_css_cache' ) ) {
			$expected_css = wp_strip_all_tags( generate_get_dynamic_css() );
			$actual_css   = get_option( 'generate_dynamic_css_output', null );
			if ( ! is_string( $actual_css ) || ! hash_equals( $expected_css, $actual_css ) ) {
				return new WP_Error( 'wpagent_generatepress_cache_unverified', __( 'GeneratePress hat den neu erzeugten CSS-Cache nicht exakt bestätigt.', 'wp-agent-companion' ), array( 'status' => 502 ) );
			}
		}
	} catch ( Throwable $error ) {
		return new WP_Error( 'wpagent_generatepress_provider_failed', __( 'GeneratePress ist beim Speichern oder Erzeugen des CSS-Caches fehlgeschlagen.', 'wp-agent-companion' ), array( 'status' => 502 ) );
	}
	return true;
}
