<?php
/** Shared contract for verified per-post Astra design overrides. */

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

/** @return array<string,array{meta:string,values:list<string>}> */
function wpagent_astra_post_field_catalog(): array {
	$inherit_disabled = array( 'inherit', 'disabled' );
	return array(
		'sidebar_layout'     => array( 'meta' => 'site-sidebar-layout', 'values' => array( 'inherit', 'no-sidebar', 'left-sidebar', 'right-sidebar' ) ),
		'content_layout'     => array( 'meta' => 'ast-site-content-layout', 'values' => array( 'inherit', 'normal-width-container', 'narrow-width-container', 'full-width-container' ) ),
		'content_style'      => array( 'meta' => 'site-content-style', 'values' => array( 'inherit', 'unboxed', 'boxed' ) ),
		'sidebar_style'      => array( 'meta' => 'site-sidebar-style', 'values' => array( 'inherit', 'unboxed', 'boxed' ) ),
		'header'             => array( 'meta' => 'ast-global-header-display', 'values' => $inherit_disabled ),
		'above_header'       => array( 'meta' => 'ast-hfb-above-header-display', 'values' => $inherit_disabled ),
		'primary_header'     => array( 'meta' => 'ast-main-header-display', 'values' => $inherit_disabled ),
		'below_header'       => array( 'meta' => 'ast-hfb-below-header-display', 'values' => $inherit_disabled ),
		'mobile_header'      => array( 'meta' => 'ast-hfb-mobile-header-display', 'values' => $inherit_disabled ),
		'footer'             => array( 'meta' => 'footer-sml-layout', 'values' => $inherit_disabled ),
		'title'              => array( 'meta' => 'site-post-title', 'values' => $inherit_disabled ),
		'banner'             => array( 'meta' => 'ast-banner-title-visibility', 'values' => $inherit_disabled ),
		'breadcrumbs'        => array( 'meta' => 'ast-breadcrumbs-content', 'values' => $inherit_disabled ),
		'featured_image'     => array( 'meta' => 'ast-featured-img', 'values' => $inherit_disabled ),
		'related_posts'      => array( 'meta' => 'ast-disable-related-posts', 'values' => $inherit_disabled ),
		'transparent_header' => array( 'meta' => 'theme-transparent-header-meta', 'values' => array( 'inherit', 'enabled', 'disabled' ) ),
	);
}

function wpagent_astra_post_override_schema( bool $complete = false ): array {
	$properties = array();
	foreach ( wpagent_astra_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_astra_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_astra_post_missing', __( 'Der Beitrag wurde nicht gefunden.', 'wp-agent-companion' ), array( 'status' => 404 ) );
	}
	$post_type = get_post_type_object( $post->post_type );
	$excluded  = class_exists( 'Astra_Meta_Boxes' ) ? Astra_Meta_Boxes::get_excluded_meta_post_types() : array( 'sureforms_form' );
	if ( 'attachment' === $post->post_type || 'fl-theme-layout' === $post->post_type || ! $post_type || ! $post_type->public || in_array( $post->post_type, $excluded, true ) ) {
		return new WP_Error( 'wpagent_astra_post_unsupported', __( 'Astra unterstützt für diesen Inhaltstyp keine individuellen Designvorgaben.', '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_astra_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_astra_post_changed', __( 'Der Astra-Beitrag ist nicht mehr im gelesenen Zustand vorhanden.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	$allowed = array();
	foreach ( wpagent_astra_post_field_catalog() as $definition ) {
		$provider_values = array_values( array_diff( $definition['values'], array( 'inherit' ) ) );
		$allowed[ $definition['meta'] ] = array_merge( array( '', 'default' ), $provider_values );
	}
	$allowed['astra-migrate-meta-layouts'] = array( '', 'default', 'set' );
	$allowed['site-content-layout']        = array( '', 'default', 'boxed-container', 'content-boxed-container', 'plain-container', 'page-builder', 'narrow-container' );

	$meta = array();
	foreach ( $allowed as $key => $values ) {
		$raw  = get_metadata_raw( 'post', $post->ID, $key, false );
		$rows = null === $raw ? array() : ( is_array( $raw ) ? $raw : array( $raw ) );
		if ( count( $rows ) > 1 ) {
			return new WP_Error( 'wpagent_astra_post_duplicate_state', __( 'Der Beitrag enthält doppelte Astra-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 || ! in_array( $value, $values, true ) ) ) {
			return new WP_Error( 'wpagent_astra_post_invalid_state', __( 'Der Beitrag enthält einen ungültigen Astra-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 );
}

/**
 * Calculate the exact persisted state expected after a validated partial update.
 *
 * @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_astra_post_expected_snapshot( array $snapshot, array $settings ): array {
	$expected = $snapshot;
	$catalog  = wpagent_astra_post_field_catalog();
	foreach ( $settings as $field => $value ) {
		$key = $catalog[ $field ]['meta'];
		if ( 'content_layout' === $field ) {
			$expected['meta']['site-content-layout'] = array( 'exists' => false, 'value' => '' );
		}
		$expected['meta'][ $key ] = 'inherit' === $value
			? array( 'exists' => false, 'value' => '' )
			: array( 'exists' => true, 'value' => $value );
	}
	if ( array_key_exists( 'content_layout', $settings ) ) {
		$expected['meta']['astra-migrate-meta-layouts'] = 'inherit' === $settings['content_layout']
			? array( 'exists' => false, 'value' => '' )
			: array( 'exists' => true, 'value' => 'set' );
	}
	return $expected;
}

function wpagent_astra_post_legacy_layout_to_modern( string $value ): string {
	$layouts = array(
		'boxed-container'         => 'normal-width-container',
		'content-boxed-container' => 'normal-width-container',
		'plain-container'         => 'normal-width-container',
		'page-builder'            => 'full-width-container',
		'narrow-container'        => 'narrow-width-container',
	);
	return $layouts[ $value ] ?? 'inherit';
}

/** @param array{post_id:int,post_type:string,meta:array<string,array{exists:bool,value:string}>} $snapshot */
function wpagent_astra_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_astra_post_normalize( array $snapshot ): array {
	$overrides = array();
	foreach ( wpagent_astra_post_field_catalog() as $field => $definition ) {
		if ( 'content_layout' === $field ) {
			$legacy    = $snapshot['meta']['site-content-layout'];
			$migration = $snapshot['meta']['astra-migrate-meta-layouts'];
			if ( $legacy['exists'] && 'set' !== $migration['value'] ) {
				$legacy_value = wpagent_astra_post_legacy_layout_to_modern( $legacy['value'] );
				if ( 'inherit' !== $legacy_value ) {
					$overrides[ $field ] = $legacy_value;
					continue;
				}
			}
		}
		$entry = $snapshot['meta'][ $definition['meta'] ];
		$value = $entry['exists'] ? $entry['value'] : '';
		$overrides[ $field ] = '' === $value || 'default' === $value ? 'inherit' : $value;
	}
	return $overrides;
}

/** @param array{post_id:int,post_type:string,meta:array<string,array{exists:bool,value:string}>} $snapshot @return true|WP_Error */
function wpagent_astra_post_rollback( array $snapshot, string $expected_hash ) {
	foreach ( $snapshot['meta'] as $key => $entry ) {
		try {
			if ( $entry['exists'] ) {
				update_post_meta( $snapshot['post_id'], $key, $entry['value'] );
			} else {
				delete_post_meta( $snapshot['post_id'], $key );
			}
		} catch ( Throwable $error ) {
			// Verify the complete persisted state below instead of trusting hooks.
		}
	}
	$post  = get_post( $snapshot['post_id'] );
	$fresh = $post ? wpagent_astra_post_snapshot( $post ) : null;
	if ( ! is_array( $fresh ) || ! hash_equals( $expected_hash, wpagent_astra_post_state_hash( $fresh ) ) ) {
		return new WP_Error( 'wpagent_astra_post_rollback_unverified', __( 'Das Astra-Beitrags-Rollback konnte nicht verifiziert werden. Prüfe den Beitrag sofort manuell.', 'wp-agent-companion' ), array( 'status' => 500, 'rollback_verified' => false ) );
	}
	return true;
}

/** @return WP_Error */
function wpagent_astra_post_fail_after_rollback( array $snapshot, string $previous_hash ) {
	$rollback = wpagent_astra_post_rollback( $snapshot, $previous_hash );
	if ( is_wp_error( $rollback ) ) {
		return $rollback;
	}
	return new WP_Error( 'wpagent_astra_post_write_unverified', __( 'Astra hat die Beitragsänderung nicht exakt bestätigt. Der vorherige Zustand wurde verifiziert wiederhergestellt.', 'wp-agent-companion' ), array( 'status' => 502, 'rollback_verified' => true ) );
}
