<?php
/**
 * Signed plugin advisory value object.
 *
 * @package LocalGuardScanner
 */

namespace LocalGuardScanner\Detection\Plugin;

use InvalidArgumentException;

/**
 * Describes one locally packaged and version-bounded plugin advisory.
 */
final class PluginAdvisory {
	/** @var array<string,mixed> */
	private $data;

	/** @param array<string,mixed> $data Validated advisory data. */
	public function __construct( array $data ) {
		$required = array( 'id', 'slug', 'plugin_file', 'affected_max', 'state', 'references', 'active_weight', 'inactive_weight', 'confidence', 'active_message_key', 'inactive_message_key' );
		foreach ( $required as $key ) {
			if ( ! array_key_exists( $key, $data ) ) {
				throw new InvalidArgumentException( 'Plugin advisory is missing a required field.' );
			}
		}
		if ( ! is_string( $data['id'] ) || ! preg_match( '/^[a-z0-9][a-z0-9._-]{2,127}$/', $data['id'] ) ) {
			throw new InvalidArgumentException( 'Plugin advisory ID is invalid.' );
		}
		if ( ! is_string( $data['slug'] ) || ! preg_match( '/^[a-z0-9][a-z0-9._-]{1,63}$/', $data['slug'] ) ) {
			throw new InvalidArgumentException( 'Plugin advisory slug is invalid.' );
		}
		if ( ! is_string( $data['plugin_file'] ) || ! preg_match( '#^[a-z0-9._-]+/[a-z0-9._-]+\.php$#', $data['plugin_file'] ) ) {
			throw new InvalidArgumentException( 'Plugin advisory file is invalid.' );
		}
		if ( ! is_string( $data['affected_max'] ) || ! preg_match( '/^[0-9][0-9A-Za-z.+_-]{0,31}$/', $data['affected_max'] ) || 'unpatched' !== $data['state'] ) {
			throw new InvalidArgumentException( 'Plugin advisory version range is invalid.' );
		}
		if ( ! is_array( $data['references'] ) || count( $data['references'] ) > 10 ) {
			throw new InvalidArgumentException( 'Plugin advisory references are invalid.' );
		}
		foreach ( $data['references'] as $reference ) {
			if ( ! is_string( $reference ) || ! preg_match( '/^[A-Z0-9._:-]{3,64}$/', $reference ) ) {
				throw new InvalidArgumentException( 'Plugin advisory reference is invalid.' );
			}
		}
		foreach ( array( 'active_message_key', 'inactive_message_key' ) as $key ) {
			if ( ! is_string( $data[ $key ] ) || ! preg_match( '/^[a-z0-9_]{3,80}$/', $data[ $key ] ) ) {
				throw new InvalidArgumentException( 'Plugin advisory message key is invalid.' );
			}
		}
		if ( ! is_int( $data['active_weight'] ) || $data['active_weight'] < 70 || $data['active_weight'] > 100 || ! is_int( $data['inactive_weight'] ) || $data['inactive_weight'] < 40 || $data['inactive_weight'] > 69 || ! is_int( $data['confidence'] ) || $data['confidence'] < 0 || $data['confidence'] > 100 ) {
			throw new InvalidArgumentException( 'Plugin advisory scores are invalid.' );
		}
		$this->data = $data;
	}

	/** @return string */
	public function id() {
		return $this->data['id'];
	}

	/** @return string */
	public function plugin_file() {
		return $this->data['plugin_file'];
	}

	/** @return string */
	public function affected_max() {
		return $this->data['affected_max'];
	}

	/** @return string[] */
	public function references() {
		return $this->data['references'];
	}

	/** @return int */
	public function confidence() {
		return $this->data['confidence'];
	}

	/**
	 * @param bool $active Whether the plugin is active anywhere.
	 * @return int
	 */
	public function weight( $active ) {
		return $active ? $this->data['active_weight'] : $this->data['inactive_weight'];
	}

	/**
	 * @param bool $active Whether the plugin is active anywhere.
	 * @return string
	 */
	public function message_key( $active ) {
		return $active ? $this->data['active_message_key'] : $this->data['inactive_message_key'];
	}
}
