<?php
/**
 * Context Serializer Class
 *
 * Handles validation, serialization, and deserialization of workflow
 * execution contexts. Extracted from QueueManager for independent testability.
 *
 * @package Sequensy
 * @since 2.0.0
 */

declare(strict_types=1);

namespace Sequensy\Engine;

use InvalidArgumentException;

// If this file is called directly, abort.
if ( ! defined( 'WPINC' ) ) {
	die;
}

/**
 * Class ContextSerializer
 *
 * Validates execution context for serializability and size, and provides
 * JSON serialization/deserialization for workflow context data.
 */
final class ContextSerializer {

	/**
	 * Maximum context size in KB.
	 *
	 * Contexts larger than this will be rejected to prevent database bloat.
	 *
	 * @var int
	 */
	private const MAX_CONTEXT_SIZE_KB = 1024; // 1MB

	/**
	 * Warning threshold for context size in KB.
	 *
	 * @var int
	 */
	private const CONTEXT_SIZE_WARNING_KB = 100;

	/**
	 * Validate execution context for serializability and size.
	 *
	 * @param array<string, mixed> $context Execution context data.
	 * @return ValidationResult Validation outcome with possible error or warning.
	 */
	public function validate( array $context ): ValidationResult {
		// Attempt JSON encoding to verify serializability.
		$json = wp_json_encode( $context );
		if ( false === $json ) {
			return ValidationResult::fail( 'Context contains unserializable data' );
		}

		$size_kb = strlen( $json ) / 1024;

		// Reject if context exceeds maximum size.
		if ( $size_kb > self::MAX_CONTEXT_SIZE_KB ) {
			return ValidationResult::fail(
				sprintf(
						/* translators: 1: current size in KB, 2: max size in KB */
					'Context size (%.2f KB) exceeds maximum allowed size (%d KB).',
					$size_kb,
					self::MAX_CONTEXT_SIZE_KB
				)
			);
		}

		// Warn if context is getting large.
		if ( $size_kb > self::CONTEXT_SIZE_WARNING_KB ) {
			return ValidationResult::ok(
				sprintf( 'Large context size (%.2f KB). Consider reducing context data.', $size_kb )
			);
		}

		return ValidationResult::ok();
	}

	/**
	 * Serialize context data to a JSON string.
	 *
	 * @param array<string, mixed> $context Execution context data.
	 * @return string JSON-encoded context.
	 */
	public function serialize( array $context ): string {
		$json = wp_json_encode( $context );
		if ( false === $json ) {
			return '{}';
		}
		return $json;
	}

	/**
	 * Deserialize a JSON string back to a context array.
	 *
	 * @param string $json JSON-encoded context.
	 * @return array<string, mixed> Deserialized context data.
	 *
	 * @throws InvalidArgumentException When the JSON string is invalid.
	 */
	public function deserialize( string $json ): array {
		$data = json_decode( $json, true );
		if ( null === $data && JSON_ERROR_NONE !== json_last_error() ) {
			throw new InvalidArgumentException(
				'Invalid JSON: ' . esc_html( json_last_error_msg() )
			);
		}

		return is_array( $data ) ? $data : array();
	}
}
