<?php
/** Shared contract for verified per-post OceanWP layout overrides. */

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

define( 'WPAGENT_OCEANWP_POST_LOCK_PREFIX', 'wp_agent_oceanwp_post_lock_' );

/** @return array<string,array{meta:string,values:list<string>}> */
function wpagent_oceanwp_post_field_catalog(): array {
	return array(
		'layout' => array(
			'meta'   => 'ocean_post_layout',
			'values' => array( 'inherit', 'right-sidebar', 'left-sidebar', 'full-width', 'full-screen', 'both-sidebars' ),
		),
		'both_sidebars_style' => array(
			'meta'   => 'ocean_both_sidebars_style',
			'values' => array( 'inherit', 'ssc-style', 'scs-style', 'css-style' ),
		),
	);
}

function wpagent_oceanwp_post_override_schema( bool $complete = false ): array {
	$properties = array();
	foreach ( wpagent_oceanwp_post_field_catalog() as $field => $definition ) {
		$properties[ $field ] = array( 'type' => 'string', 'enum' => $definition['values'] );
	}
	$schema = array(
		'type'                 => 'object',
		'properties'           => $properties,
		'additionalProperties' => false,
	);
	if ( $complete ) {
		$schema['required'] = array_keys( $properties );
	} else {
		$schema['minProperties'] = 1;
		$schema['maxProperties'] = count( $properties );
	}
	return $schema;
}

/** @return WP_Post|WP_Error */
function wpagent_oceanwp_post_target( int $post_id ) {
	$post = get_post( $post_id );
	if ( ! $post || wp_is_post_revision( $post_id ) || wp_is_post_autosave( $post_id ) ) {
		return new WP_Error( 'wpagent_oceanwp_post_missing', __( 'Der Beitrag wurde nicht gefunden.', 'wp-agent-companion' ), array( 'status' => 404 ) );
	}
	$post_type = get_post_type_object( $post->post_type );
	if ( 'attachment' === $post->post_type || ! $post_type || ! $post_type->public ) {
		return new WP_Error( 'wpagent_oceanwp_post_unsupported', __( 'OceanWP unterstützt für diesen Inhaltstyp keine individuellen Layoutvorgaben.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	if ( ! current_user_can( 'edit_post', $post_id ) ) {
		return new WP_Error( 'wpagent_forbidden', __( 'Keine Berechtigung.', 'wp-agent-companion' ), array( 'status' => 403 ) );
	}
	return $post;
}

/**
 * @return array{post_id:int,post_type:string,meta:array<string,array{exists:bool,value:string}>}|WP_Error
 */
function wpagent_oceanwp_post_snapshot( WP_Post $post ) {
	$fresh_post = get_post( $post->ID );
	if ( ! $fresh_post instanceof WP_Post || $fresh_post->post_type !== $post->post_type ) {
		return new WP_Error( 'wpagent_oceanwp_post_changed', __( 'Der OceanWP-Beitrag ist nicht mehr im gelesenen Zustand vorhanden.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	$meta = array();
	foreach ( wpagent_oceanwp_post_field_catalog() as $definition ) {
		$key    = $definition['meta'];
		$raw    = get_metadata_raw( 'post', $post->ID, $key, false );
		$rows   = null === $raw ? array() : ( is_array( $raw ) ? $raw : array( $raw ) );
		$values = array_values( array_diff( $definition['values'], array( 'inherit' ) ) );
		if ( count( $rows ) > 1 ) {
			return new WP_Error( 'wpagent_oceanwp_post_duplicate_state', __( 'Der Beitrag enthält doppelte OceanWP-Einzelmetadaten und kann nicht sicher bearbeitet werden.', 'wp-agent-companion' ), array( 'status' => 502 ) );
		}
		$exists = 1 === count( $rows );
		$value  = $exists ? $rows[0] : '';
		if ( $exists && ( ! is_string( $value ) || strlen( $value ) > 64 || ( '' !== $value && ! in_array( $value, $values, true ) ) ) ) {
			return new WP_Error( 'wpagent_oceanwp_post_invalid_state', __( 'Der Beitrag enthält einen ungültigen OceanWP-Einstellungsstand.', 'wp-agent-companion' ), array( 'status' => 502 ) );
		}
		$meta[ $key ] = array( 'exists' => $exists, 'value' => (string) $value );
	}
	return array( 'post_id' => (int) $fresh_post->ID, 'post_type' => $fresh_post->post_type, 'meta' => $meta );
}

/**
 * @param array{post_id:int,post_type:string,meta:array<string,array{exists:bool,value:string}>} $snapshot
 * @param array<string,string> $settings
 * @return array{post_id:int,post_type:string,meta:array<string,array{exists:bool,value:string}>}
 */
function wpagent_oceanwp_post_expected_snapshot( array $snapshot, array $settings ): array {
	$expected = $snapshot;
	$catalog  = wpagent_oceanwp_post_field_catalog();
	foreach ( $settings as $field => $value ) {
		$key = $catalog[ $field ]['meta'];
		$expected['meta'][ $key ] = 'inherit' === $value
			? array( 'exists' => false, 'value' => '' )
			: array( 'exists' => true, 'value' => $value );
	}
	return $expected;
}

/** @param array{post_id:int,post_type:string,meta:array<string,array{exists:bool,value:string}>} $snapshot */
function wpagent_oceanwp_post_state_hash( array $snapshot ): string {
	$parent = wp_get_theme( get_template() );
	$child  = wp_get_theme( get_stylesheet() );
	$state  = get_template() . '@' . $parent->get( 'Version' ) . '|' . get_stylesheet() . '@' . $child->get( 'Version' );
	$state .= "\0" . $snapshot['post_id'] . "\0" . $snapshot['post_type'];
	foreach ( $snapshot['meta'] as $key => $entry ) {
		$state .= "\0" . $key . "\0" . ( $entry['exists'] ? '1' : '0' ) . "\0" . $entry['value'];
	}
	return hash( 'sha256', $state );
}

/**
 * @param array{post_id:int,post_type:string,meta:array<string,array{exists:bool,value:string}>} $snapshot
 * @return array<string,string>
 */
function wpagent_oceanwp_post_normalize( array $snapshot ): array {
	$overrides = array();
	foreach ( wpagent_oceanwp_post_field_catalog() as $field => $definition ) {
		$entry = $snapshot['meta'][ $definition['meta'] ];
		$overrides[ $field ] = $entry['exists'] && '' !== $entry['value'] ? $entry['value'] : 'inherit';
	}
	return $overrides;
}

/** @return array{layout:string,both_sidebars_style:string}|WP_Error */
function wpagent_oceanwp_post_runtime_state( int $post_id ) {
	if ( ! function_exists( 'oceanwp_post_layout' ) || ! function_exists( 'oceanwp_both_sidebars_style' ) ) {
		return new WP_Error( 'wpagent_oceanwp_runtime_missing', __( 'Die aktive OceanWP-Version stellt den geprüften Beitragslayout-Weg nicht bereit.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	$target = static fn( $current_id = null ) => $post_id;
	add_filter( 'ocean_post_id', $target, PHP_INT_MAX );
	try {
		return array(
			'layout'                => (string) oceanwp_post_layout(),
			'both_sidebars_style' => (string) oceanwp_both_sidebars_style(),
		);
	} catch ( Throwable $error ) {
		return new WP_Error( 'wpagent_oceanwp_post_runtime_failed', __( 'OceanWP konnte das individuelle Beitragslayout nicht auswerten.', 'wp-agent-companion' ), array( 'status' => 502 ) );
	} finally {
		remove_filter( 'ocean_post_id', $target, PHP_INT_MAX );
	}
}

/** @return string|WP_Error */
function wpagent_oceanwp_post_acquire_lock( int $post_id ) {
	$option = WPAGENT_OCEANWP_POST_LOCK_PREFIX . $post_id;
	$token  = wpagent_companion_acquire_option_lock( $option, WPAGENT_OCEANWP_LOCK_TTL );
	if ( is_string( $token ) ) {
		return $token;
	}
	return new WP_Error( 'wpagent_oceanwp_post_locked', __( 'Das OceanWP-Beitragslayout wird gerade durch einen anderen Vorgang geändert.', 'wp-agent-companion' ), array( 'status' => 409 ) );
}

function wpagent_oceanwp_post_release_lock( int $post_id, string $token ): void {
	wpagent_companion_release_option_lock( WPAGENT_OCEANWP_POST_LOCK_PREFIX . $post_id, $token );
}

function wpagent_oceanwp_post_refresh_lock( int $post_id, string $token ): bool {
	return wpagent_companion_refresh_option_lock(
		WPAGENT_OCEANWP_POST_LOCK_PREFIX . $post_id,
		$token,
		WPAGENT_OCEANWP_LOCK_TTL
	);
}

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

/** @return WP_Error */
function wpagent_oceanwp_post_persist_failed( bool $write_started ): WP_Error {
	return new WP_Error(
		'wpagent_oceanwp_post_write_failed',
		__( 'OceanWP konnte die Beitragsvorgaben nicht sicher speichern.', 'wp-agent-companion' ),
		array( 'status' => $write_started ? 500 : 502, 'write_started' => $write_started )
	);
}

/** @return WP_Error */
function wpagent_oceanwp_post_recovery_required( int $post_id ) {
	$post     = get_post( $post_id );
	$snapshot = $post instanceof WP_Post ? wpagent_oceanwp_post_snapshot( $post ) : null;
	$data     = array( 'status' => 500, 'rollback_verified' => false, 'recovery_required' => true );
	if ( is_array( $snapshot ) ) {
		$data['current_hash']      = wpagent_oceanwp_post_state_hash( $snapshot );
		$data['current_overrides'] = wpagent_oceanwp_post_normalize( $snapshot );
	}
	return new WP_Error( 'wpagent_oceanwp_post_recovery_required', __( 'Die OceanWP-Beitragsä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 );
}
