<?php
/**
 * Registered custom metadata lifecycle behavior.
 *
 * @package ScheduledChanges
 */

namespace ScheduledChanges\WordPressContent;

use ScheduledChanges\Field\FieldDefinition;

/**
 * Normalizes, validates, reads, writes, and verifies allowlisted post metadata.
 */
final class RegisteredMetaService {
	private WordPressMetaFieldRegistry $registry;

	/** Creates the service over an explicit allowlist registry. */
	public function __construct( ?WordPressMetaFieldRegistry $registry = null ) {
		$this->registry = $registry ?? new WordPressMetaFieldRegistry();
	}

	/**
	 * @param mixed $value Candidate metadata value.
	 * @return mixed
	 */
	public function normalize( FieldDefinition $field, $value ) {
		$meta_key  = (string) ( $field->validationRules()['meta_key'] ?? '' );
		$post_type = (string) ( $field->scope()[0] ?? '' );
		$single    = (bool) ( $field->validationRules()['single'] ?? false );

		if ( ! $single && is_array( $value ) ) {
			return array_map(
				static fn ( $item ) => sanitize_meta( $meta_key, $item, 'post', $post_type ),
				$value
			);
		}

		return sanitize_meta( $meta_key, $value, 'post', $post_type );
	}

	/** @return mixed */
	public function read( int $post_id, FieldDefinition $field ) {
		return get_post_meta(
			$post_id,
			(string) ( $field->validationRules()['meta_key'] ?? '' ),
			(bool) ( $field->validationRules()['single'] ?? false )
		);
	}

	/** @return array{code:string,message:string}|null */
	public function validationError( string $post_type, FieldDefinition $field ): ?array {
		$meta_key = (string) ( $field->validationRules()['meta_key'] ?? '' );

		return null === $this->registry->get( $post_type, $meta_key )
			? array(
				'code'    => 'metadata_not_allowlisted',
				'message' => 'Registered metadata must remain explicitly allowlisted.',
			)
			: null;
	}

	/**
	 * @param mixed $value Canonical value.
	 * @return true|\WP_Error
	 */
	public function write( int $post_id, FieldDefinition $field, $value ) {
		$meta_key = (string) ( $field->validationRules()['meta_key'] ?? '' );

		if ( (bool) ( $field->validationRules()['single'] ?? false ) ) {
			$updated = update_post_meta( $post_id, $meta_key, $value );

			return false === $updated && $this->read( $post_id, $field ) !== $value
				? new \WP_Error( 'meta_write_failed', 'WordPress could not update the registered metadata.' )
				: true;
		}

		delete_post_meta( $post_id, $meta_key );
		foreach ( (array) $value as $item ) {
			if ( false === add_post_meta( $post_id, $meta_key, $item, false ) ) {
				return new \WP_Error( 'meta_write_failed', 'WordPress could not update the registered metadata.' );
			}
		}

		return $this->read( $post_id, $field ) === $value
			? true
			: new \WP_Error( 'meta_readback_failed', 'Registered metadata readback did not match.' );
	}
}
