<?php
/**
 * Bounded custom JSON-LD syntax parser.
 *
 * @package SEOvaultSEO\Schema\Validation
 */

namespace SEOvaultSEO\Schema\Validation;

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

/**
 * Parses raw custom JSON-LD without exposing parser warnings to users.
 */
class JsonSyntaxValidator {

	/**
	 * Parse one raw custom JSON-LD document.
	 *
	 * @param mixed $json   Raw JSON-LD document.
	 * @param array $limits Effective validation limits.
	 * @return array
	 */
	public function parse( $json, $limits = array() ) {
		$limits = ValidationLimits::get( $limits );

		if ( ! is_string( $json ) ) {
			return $this->failure( 'json.root.invalid_type', 'json.root_invalid_type', array() );
		}

		if ( strlen( $json ) > $limits['max_json_bytes'] ) {
			return $this->failure(
				'json.input.too_large',
				'json.input_too_large',
				array( 'max_bytes' => $limits['max_json_bytes'] )
			);
		}

		$decoded = json_decode( $json, true );
		if ( JSON_ERROR_NONE !== json_last_error() ) {
			return $this->failure(
				'json.syntax.invalid',
				'json.syntax_invalid',
				array( 'json_error' => json_last_error() )
			);
		}

		if ( ! is_array( $decoded ) ) {
			return $this->failure( 'json.root.invalid_type', 'json.root_invalid_type', array() );
		}

		if ( ValueInspector::is_list( $decoded ) ) {
			foreach ( $decoded as $item ) {
				if ( ! is_array( $item ) || ValueInspector::is_list( $item ) ) {
					return $this->failure( 'json.root.invalid_type', 'json.root_list_invalid_item', array() );
				}
			}
		}

		return array(
			'is_valid' => true,
			'data'     => $decoded,
			'issues'   => array(),
		);
	}

	/**
	 * Build a controlled parse failure response.
	 *
	 * @param string $code        Stable issue code.
	 * @param string $message_key Presentation message key suffix.
	 * @param array  $message_args Presentation message values.
	 * @return array
	 */
	private function failure( $code, $message_key, $message_args ) {
		return array(
			'is_valid' => false,
			'data'     => array(),
			'issues'   => array(
				new ValidationIssue(
					array(
						'code'         => $code,
						'severity'     => Severity::ERROR,
						'category'     => 'core',
						'source'       => 'custom',
						'title_key'    => $code . '.title',
						'message_key'  => $message_key,
						'message_args' => $message_args,
					)
				),
			),
		);
	}
}
