<?php
/**
 * Offline installed-plugin advisory matching.
 *
 * @package LocalGuardScanner
 */

namespace LocalGuardScanner\Detection\Plugin;

use LocalGuardScanner\Domain\Detection\Evidence;

/**
 * Matches exact installed plugin files and versions against signed advisories.
 */
final class PluginAdvisoryDetector {
	/** @var PluginAdvisory[] */
	private $advisories;

	/** @param PluginAdvisory[] $advisories Signed advisories. */
	public function __construct( array $advisories ) {
		$this->advisories = $advisories;
	}

	/**
	 * @param array<string,array<string,mixed>> $installed Installed plugin headers by main file.
	 * @param array<string,bool>                $active    Network or per-site active plugin files.
	 * @return array<string,Evidence[]>
	 */
	public function inspect( array $installed, array $active ) {
		$matches = array();
		foreach ( $this->advisories as $advisory ) {
			$plugin_file = $advisory->plugin_file();
			if ( ! isset( $installed[ $plugin_file ] ) ) {
				continue;
			}
			$version = isset( $installed[ $plugin_file ]['Version'] ) && is_string( $installed[ $plugin_file ]['Version'] ) ? trim( $installed[ $plugin_file ]['Version'] ) : '';
			if ( '' === $version || version_compare( $version, $advisory->affected_max(), '>' ) ) {
				continue;
			}
			$is_active               = ! empty( $active[ $plugin_file ] );
			$fragment                = sprintf( 'version=%s;state=%s;refs=%s', $version, $is_active ? 'active' : 'inactive', implode( ',', $advisory->references() ) );
			$matches[ $plugin_file ] = array(
				new Evidence( $advisory->id(), $advisory->weight( $is_active ), $advisory->confidence(), $advisory->message_key( $is_active ), $fragment ),
			);
		}
		return $matches;
	}
}
