<?php
/** Atomic lock and fail-closed persistence for OceanWP theme mods. */

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

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

function wpagent_oceanwp_release_lock( string $token ): void {
	wpagent_companion_release_option_lock( WPAGENT_OCEANWP_LOCK_OPTION, $token );
}

function wpagent_oceanwp_refresh_lock( string $token ): bool {
	return wpagent_companion_refresh_option_lock(
		WPAGENT_OCEANWP_LOCK_OPTION,
		$token,
		WPAGENT_OCEANWP_LOCK_TTL
	);
}

/** @return true|WP_Error */
function wpagent_oceanwp_assert_writable_mode( array $mods ) {
	$mode = $mods['ocean_customzer_styling'] ?? 'head';
	if ( 'file' === $mode ) {
		return new WP_Error(
			'wpagent_oceanwp_file_css_mode',
			__( 'OceanWP schreibt Customizer-CSS derzeit in eine Datei. Stelle unter OceanWP > Customizer > Performance die Customizer-Stile auf den Head-Modus, damit wpagently Änderungen sicher verifizieren kann.', 'wp-agent-companion' ),
			array( 'status' => 409 )
		);
	}
	if ( 'head' !== $mode ) {
		return new WP_Error( 'wpagent_oceanwp_invalid_css_mode', __( 'OceanWP verwendet einen unbekannten Customizer-CSS-Modus.', 'wp-agent-companion' ), array( 'status' => 502 ) );
	}
	return true;
}

/** @return WP_Error */
function wpagent_oceanwp_write_lock_lost( bool $write_started ): WP_Error {
	return new WP_Error(
		$write_started ? 'wpagent_oceanwp_lock_lost_after_write' : 'wpagent_oceanwp_lock_lost',
		__( 'Die OceanWP-Änderung hat ihre exklusive Sperre verloren.', 'wp-agent-companion' ),
		array( 'status' => $write_started ? 500 : 409, 'write_started' => $write_started )
	);
}

/** @return true|WP_Error */
function wpagent_oceanwp_write( string $option_name, array $mods, string $lock ) {
	if ( ! wpagent_oceanwp_refresh_lock( $lock ) ) {
		return wpagent_oceanwp_write_lock_lost( false );
	}
	$write_started = false;
	try {
		// This is the provider mutation. Renew and prove lock ownership directly
		// before it, instead of relying on a prior validation phase.
		$write_started = true;
		update_option( $option_name, $mods, false );
		if ( ! wpagent_oceanwp_refresh_lock( $lock ) ) {
			return wpagent_oceanwp_write_lock_lost( true );
		}
		wp_cache_delete( $option_name, 'options' );
		$stored = get_option( $option_name, null );
		if ( ! wpagent_oceanwp_refresh_lock( $lock ) ) {
			return wpagent_oceanwp_write_lock_lost( true );
		}
		if ( ! is_array( $stored ) || maybe_serialize( $stored ) !== maybe_serialize( $mods ) ) {
			return new WP_Error( 'wpagent_oceanwp_write_mismatch', __( 'OceanWP hat die angeforderten Einstellungen nicht vollständig gespeichert.', 'wp-agent-companion' ), array( 'status' => 502, 'write_started' => true ) );
		}
		return true;
	} catch ( Throwable $error ) {
		return new WP_Error( 'wpagent_oceanwp_write_failed', __( 'OceanWP konnte die Einstellungen nicht sicher speichern.', 'wp-agent-companion' ), array( 'status' => $write_started ? 500 : 502, 'write_started' => $write_started ) );
	}
}

/**
 * Returns a manual-recovery error without writing a possibly stale snapshot.
 *
 * A theme-mod bundle has no portable compare-and-swap primitive. After the
 * first provider write, a Customizer request may change an unrelated key
 * between any check and a restoration. Replaying a previous full option would
 * therefore risk erasing that third-party change. Keep every observed state
 * intact and provide only bounded, validated diagnostic state.
 *
 * @return WP_Error
 */
function wpagent_oceanwp_recovery_required(): WP_Error {
	$data     = array( 'status' => 500, 'rollback_verified' => false, 'recovery_required' => true );
	$snapshot = wpagent_oceanwp_snapshot();
	if ( is_array( $snapshot ) ) {
		$data['current_hash'] = wpagent_oceanwp_state_hash( $snapshot );
		$sections             = array();
		foreach ( array_keys( wpagent_oceanwp_section_schemas() ) as $section ) {
			$current = wpagent_oceanwp_read_section( $section, $snapshot['mods']['value'] );
			if ( is_wp_error( $current ) ) {
				$sections = array();
				break;
			}
			$sections[ $section ] = $current;
		}
		if ( $sections ) {
			$data['current_sections'] = $sections;
		}
	}
	return new WP_Error(
		'wpagent_oceanwp_recovery_required',
		__( 'Die OceanWP-Änderung wurde nicht vollständig verifiziert. Es wurde kein automatisches Rollback ausgeführt. Wiederhole den Vorgang nicht automatisch und prüfe den aktuellen Zustand manuell.', 'wp-agent-companion' ),
		$data
	);
}
