<?php
/**
 * Validates entity @type values.
 *
 * @package SEOvaultSEO\Schema\Validation\Rules\Core
 */

namespace SEOvaultSEO\Schema\Validation\Rules\Core;

use SEOvaultSEO\Schema\Validation\RuleInterface;
use SEOvaultSEO\Schema\Validation\Severity;
use SEOvaultSEO\Schema\Validation\ValidationContext;
use SEOvaultSEO\Schema\Validation\ValidationIssue;

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

/**
 * Requires each normalized entity to carry a valid @type value.
 */
class TypeRule implements RuleInterface {

	/**
	 * Get the stable rule code.
	 *
	 * @return string
	 */
	public function get_code() {
		return 'schema.type';
	}

	/**
	 * Type checks apply to every graph entity.
	 *
	 * @param ValidationContext $context Validation context.
	 * @return bool
	 */
	public function supports( ValidationContext $context ) {
		return true;
	}

	/**
	 * Validate each entity's @type shape.
	 *
	 * @param ValidationContext $context Validation context.
	 * @return ValidationIssue[]
	 */
	public function evaluate( ValidationContext $context ) {
		$issues = array();
		foreach ( $context->get_entities() as $entity ) {
			$data        = $entity['data'] ?? array();
			$raw_type    = $data['@type'] ?? null;
			$entity_id   = $entity['id'] ?? '';
			$entity_path = $entity['path'] ?? '';
			$code        = '';

			if ( ! array_key_exists( '@type', $data ) || '' === $raw_type || array() === $raw_type ) {
				$code = 'schema.type.missing';
			} elseif ( ! is_string( $raw_type ) && ! is_array( $raw_type ) ) {
				$code = 'schema.type.invalid';
			} elseif ( is_array( $raw_type ) ) {
				foreach ( $raw_type as $type ) {
					if ( ! is_string( $type ) || '' === trim( $type ) ) {
						$code = 'schema.type.invalid';
						break;
					}
				}
			}

			if ( '' === $code ) {
				continue;
			}

			$issues[] = new ValidationIssue(
				array(
					'code'        => $code,
					'severity'    => Severity::ERROR,
					'category'    => 'core',
					'entity_id'   => $entity_id,
					'path'        => $entity_path . '.@type',
					'source'      => $context->get_source(),
					'title_key'   => $code . '.title',
					'message_key' => $code . '.message',
				)
			);
		}

		return $issues;
	}
}
