<?php
/**
 * Structured validation issue.
 *
 * @package ScheduledChanges
 */

namespace ScheduledChanges\Validation;

/**
 * One machine-readable validation result.
 */
final class ValidationIssue {
	private string $code;
	private string $message;
	private string $level;
	private string $path = '';
	/**
	 * @var array<string, mixed>
	 */
	private array $context = array();
	/**
	 * @param array<string,mixed> $context Redacted issue context.
	 */
	public function __construct(
		string $code,
		string $message,
		string $level,
		string $path = '',
		array $context = array()
	) {
		$this->code    = $code;
		$this->message = $message;
		$this->level   = $level;
		$this->path    = $path;
		$this->context = $context;
		if ( 1 !== preg_match( '/^[a-z][a-z0-9_.-]*$/', $this->code ) ) {
			throw new \InvalidArgumentException( 'Validation issue codes must be stable lowercase identifiers.' );
		}

		if ( '' === trim( $this->message ) ) {
			throw new \InvalidArgumentException( 'Validation issue messages are required.' );
		}
	}

	public function code(): string {
		return $this->code;
	}

	public function message(): string {
		return $this->message;
	}

	public function level(): string {
		return $this->level;
	}

	public function path(): string {
		return $this->path;
	}

	/**
	 * @return array<string,mixed>
	 */
	public function context(): array {
		return $this->context;
	}

	/**
	 * @return array<string,mixed>
	 */
	public function toArray(): array {
		return array(
			'code'    => $this->code,
			'message' => $this->message,
			'level'   => $this->level,
			'path'    => $this->path,
			'context' => $this->context,
		);
	}

	/**
	 * @param array<string,mixed> $data Serialized issue.
	 */
	public static function fromArray( array $data ): self {
		return new self(
			(string) ( $data['code'] ?? '' ),
			(string) ( $data['message'] ?? '' ),
			\ScheduledChanges\Support\EnumValue::from( \ScheduledChanges\Validation\ValidationLevel::class, (string) ( $data['level'] ?? ValidationLevel::BLOCKING_ERROR ) ),
			(string) ( $data['path'] ?? '' ),
			is_array( $data['context'] ?? null ) ? $data['context'] : array()
		);
	}
}
