<?php
/**
 * Explainable risk classification.
 *
 * @package LocalGuardScanner
 */

namespace LocalGuardScanner\Domain\Detection;

/**
 * Combines independent evidence with diminishing contributions.
 */
final class RiskClassifier {
	/**
	 * @param string     $object_type Object type.
	 * @param string     $locator     Stable locator.
	 * @param Evidence[] $evidence    Detector evidence.
	 * @return Finding|null
	 */
	public function classify( $object_type, $locator, array $evidence ) {
		$unique = array();
		foreach ( $evidence as $item ) {
			$id = $item->detector_id();
			if ( ! isset( $unique[ $id ] ) || $item->weight() > $unique[ $id ]->weight() ) {
				$unique[ $id ] = $item;
			}
		}
		if ( empty( $unique ) ) {
			return null;
		}
		$unique = array_values( $unique );
		usort(
			$unique,
			static function ( Evidence $left, Evidence $right ) {
				return $right->weight() <=> $left->weight();
			}
		);
		$score          = 0.0;
		$confidence_sum = 0;
		foreach ( $unique as $index => $item ) {
			if ( 0 === $index ) {
				$score = $item->weight();
			} else {
				$score += $item->weight() * ( 1.0 - $score / 100.0 ) * 0.5;
			}
			$confidence_sum += $item->confidence();
		}
		$confidence = (int) round( $confidence_sum / count( $unique ) );
		return new Finding( $object_type, $locator, (int) round( min( 100, $score ) ), $confidence, $unique );
	}
}
