<?php

declare( strict_types=1 );

namespace Brightfern\Validation;

/**
 * Aggregated result of one or more checks. The pre-flight gate merges several
 * of these; "valid" means no ERROR-severity issues (warnings do not block).
 */
final class ValidationResult {

	/** @var ValidationIssue[] */
	private array $issues = array();

	public function add( string $severity, string $code, string $message, string $location = '' ): void {
		$this->issues[] = new ValidationIssue( $severity, $code, $message, $location );
	}

	public function error( string $code, string $message, string $location = '' ): void {
		$this->add( ValidationIssue::ERROR, $code, $message, $location );
	}

	public function warning( string $code, string $message, string $location = '' ): void {
		$this->add( ValidationIssue::WARNING, $code, $message, $location );
	}

	public function info( string $code, string $message, string $location = '' ): void {
		$this->add( ValidationIssue::INFO, $code, $message, $location );
	}

	public function merge( ValidationResult $other ): void {
		foreach ( $other->issues as $issue ) {
			$this->issues[] = $issue;
		}
	}

	/** @return ValidationIssue[] */
	public function issues(): array {
		return $this->issues;
	}

	/** @return ValidationIssue[] */
	public function errors(): array {
		return array_values( array_filter( $this->issues, static fn ( $i ) => ValidationIssue::ERROR === $i->severity ) );
	}

	/** @return ValidationIssue[] */
	public function warnings(): array {
		return array_values( array_filter( $this->issues, static fn ( $i ) => ValidationIssue::WARNING === $i->severity ) );
	}

	public function hasErrors(): bool {
		foreach ( $this->issues as $issue ) {
			if ( ValidationIssue::ERROR === $issue->severity ) {
				return true;
			}
		}
		return false;
	}

	/** No blocking errors → safe to transmit. */
	public function isValid(): bool {
		return ! $this->hasErrors();
	}

	public function hasCode( string $code ): bool {
		foreach ( $this->issues as $issue ) {
			if ( $issue->code === $code ) {
				return true;
			}
		}
		return false;
	}
}
