<?php
/**
 * Default detector factory.
 *
 * @package LocalGuardScanner
 */

namespace LocalGuardScanner\Detection;

use LocalGuardScanner\Detection\File\FilenameDetector;
use LocalGuardScanner\Detection\File\PermissionDetector;
use LocalGuardScanner\Detection\File\SignatureDetector;
use LocalGuardScanner\Detection\File\UploadPhpDetector;
use LocalGuardScanner\Detection\Integrity\CoreIntegrityDetector;
use LocalGuardScanner\Detection\Integrity\CoreManifestRepository;
use LocalGuardScanner\Detection\Php\ObfuscationDetector;
use LocalGuardScanner\Detection\Php\PhpDataFlowAnalyzer;
use LocalGuardScanner\Detection\Php\PhpDataFlowDetector;
use LocalGuardScanner\Detection\Rules\RuleLoader;
use LocalGuardScanner\Detection\Rules\RuleVerifier;

/**
 * Builds the local engine exclusively from packaged rules and manifests.
 */
final class DetectorFactory {
	/** @var string */
	private $plugin_directory;

	/** @param string $plugin_directory Plugin root. */
	public function __construct( $plugin_directory ) {
		$this->plugin_directory = rtrim( $plugin_directory, '/\\' );
	}

	/**
	 * @param string $wordpress_version Exact WordPress version.
	 * @return DetectorBundle
	 */
	public function create( $wordpress_version ) {
		$rules_directory = $this->plugin_directory . '/rules';
		$rules           = ( new RuleLoader( new RuleVerifier() ) )->load(
			$rules_directory . '/manifest.json',
			$rules_directory . '/manifest.sig',
			$rules_directory . '/public-key.txt'
		);
		if ( empty( $rules->core_catalog() ) ) {
			throw new \RuntimeException( 'Signed core integrity catalog is unavailable.' );
		}
		$core_manifest = ( new CoreManifestRepository( $rules_directory . '/core', $rules->core_catalog() ) )->for_version( $wordpress_version );
		$detectors     = array(
			new UploadPhpDetector(),
			new FilenameDetector(),
			new PermissionDetector(),
			new SignatureDetector( $rules ),
			new PhpDataFlowDetector( new PhpDataFlowAnalyzer(), $rules ),
			new ObfuscationDetector(),
		);
		if ( null !== $core_manifest ) {
			$detectors[] = new CoreIntegrityDetector( $core_manifest );
		}

		return new DetectorBundle( new DetectorEngine( $detectors ), $rules->version(), null !== $core_manifest, $core_manifest, $rules->advisories(), $rules->advisory_date() );
	}
}
