<?php
/** Verified persistence and mutation locking for license state. */

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

/**
 * Return the stored license state without exposing it through public APIs.
 *
 * @return array<string,mixed>
 */
function wpagent_companion_license_state(): array {
	$state = get_option( WPAGENT_LICENSE_OPTION, array() );
	if ( ! is_array( $state ) ) {
		return array();
	}
	if ( isset( $state['key_encrypted'] ) && is_string( $state['key_encrypted'] ) ) {
		$key = wpagent_companion_license_decrypt_key( $state['key_encrypted'] );
		unset( $state['key_encrypted'], $state['key'] );
		if ( ! is_wp_error( $key ) ) {
			// Preserve the logical field order used by build_state(), because save()
			// deliberately verifies the exact value after WordPress filters ran.
			$state = array( 'key' => $key ) + $state;
		}
	}
	return $state;
}

function wpagent_companion_license_persist_error(): WP_Error {
	return new WP_Error(
		'wpagent_license_persist_failed',
		__( 'Der Lizenzstatus konnte nicht sicher gespeichert werden.', 'wp-agent-companion' ),
		array( 'status' => 500 )
	);
}

/**
 * Persist only the fields needed to validate the site license.
 *
 * @param array<string,mixed> $state License state.
 * @return true|WP_Error
 */
function wpagent_companion_license_save( array $state ) {
	if ( ! isset( $state['key'] ) || ! is_string( $state['key'] ) ) {
		return wpagent_companion_license_persist_error();
	}
	$encrypted = wpagent_companion_license_encrypt_key( $state['key'] );
	if ( is_wp_error( $encrypted ) ) {
		return $encrypted;
	}
	// Der nicht geheime Fingerabdruck ermöglicht nach einer WordPress-Salt-
	// Rotation die sichere Zuordnung eines erneut eingegebenen, hochentropischen
	// Polar-Schlüssels. Ohne ihn wäre der alte Aktivierungsslot nicht mehr
	// freigebbar, weil das verschlüsselte Original absichtlich unlesbar wird.
	$state['key_hash']        = hash( 'sha256', $state['key'] );
	$stored                  = $state;
	$stored['key_encrypted'] = $encrypted;
	unset( $stored['key'] );
	update_option( WPAGENT_LICENSE_OPTION, $stored, false );
	$raw = wpagent_companion_license_option_snapshot( WPAGENT_LICENSE_OPTION );
	if ( ! $raw['exists'] || $stored !== $raw['value'] || $state !== wpagent_companion_license_state() ) {
		return wpagent_companion_license_persist_error();
	}
	return true;
}

/** @return array{exists:bool,value:mixed} */
function wpagent_companion_license_option_snapshot( string $option ): array {
	$missing = new stdClass();
	$value   = get_option( $option, $missing );
	return array(
		'exists' => $value !== $missing,
		'value'  => $value === $missing ? null : $value,
	);
}

/** Persist one option and verify its exact value after WordPress filters ran. */
function wpagent_companion_license_option_write( string $option, $value ): bool {
	update_option( $option, $value, false );
	$snapshot = wpagent_companion_license_option_snapshot( $option );
	return $snapshot['exists'] && $value === $snapshot['value'];
}

/** Remove one option and verify that no filtered or stale value remains. */
function wpagent_companion_license_option_delete( string $option ): bool {
	delete_option( $option );
	return ! wpagent_companion_license_option_snapshot( $option )['exists'];
}

/** @param array{exists:bool,value:mixed} $snapshot */
function wpagent_companion_license_option_restore( string $option, array $snapshot ): bool {
	return $snapshot['exists']
		? wpagent_companion_license_option_write( $option, $snapshot['value'] )
		: wpagent_companion_license_option_delete( $option );
}

function wpagent_companion_license_lock_storage_error(): WP_Error {
	return new WP_Error(
		'wpagent_license_lock_storage_failed',
		__( 'Die Lizenzänderung konnte wegen eines Datenbankfehlers nicht sicher gestartet werden.', 'wp-agent-companion' ),
		array( 'status' => 500 )
	);
}

/** @return string|WP_Error */
function wpagent_companion_license_acquire_lock() {
	global $wpdb;
	$token = wpagent_companion_acquire_option_lock( WPAGENT_LICENSE_LOCK_OPTION, WPAGENT_LICENSE_LOCK_TTL );
	if ( is_string( $token ) ) {
		return $token;
	}
	if ( '' !== $wpdb->last_error ) {
		return wpagent_companion_license_lock_storage_error();
	}
	return new WP_Error(
		'wpagent_license_locked',
		__( 'Eine andere Lizenzänderung läuft bereits. Versuche es gleich erneut.', 'wp-agent-companion' ),
		array( 'status' => 409 )
	);
}

function wpagent_companion_license_release_lock( string $token ): void {
	wpagent_companion_release_option_lock( WPAGENT_LICENSE_LOCK_OPTION, $token );
}
