<?php
/**
 * @package Hafenstudios\Wellenbrecher
 */

namespace Hafenstudios\Wellenbrecher\Pro\Bayes;

defined( 'ABSPATH' ) || exit;

/**
 * Naive-Bayes-Klassifikator in reinem PHP (Technik A6, Graham-Degeneration
 * light). Rein und ohne WordPress: bekommt die Token-Statistik (ham/spam je
 * Token) sowie die Gesamtzahl trainierter Ham-/Spam-Nachrichten und liefert
 * die Spam-Wahrscheinlichkeit im Bereich 0..1.
 *
 * Graham-Formel je Token: g = min(1, 2*ham/ham_gesamt), b = min(1, spam/spam_
 * gesamt), p = b / (b + g), geklemmt auf 0,01..0,99. Die interessantesten
 * Tokens (groesster Abstand zu 0,5) werden per Bayes kombiniert.
 */
class Classifier {

	/**
	 * Wie viele der aussagekraeftigsten Tokens kombiniert werden (Graham: 15).
	 */
	public const MAX_TOKENS = 15;

	/**
	 * Klassifiziert einen Token-Satz.
	 *
	 * @param array<string, array{ham?: int, spam?: int}> $stats      Token => {ham, spam}.
	 * @param int                                          $ham_total  Trainierte Ham-Nachrichten.
	 * @param int                                          $spam_total Trainierte Spam-Nachrichten.
	 * @return float Spam-Wahrscheinlichkeit 0..1 (0,5 = neutral/keine Aussage).
	 */
	public function classify( array $stats, int $ham_total, int $spam_total ): float {
		$ham_total  = max( 1, $ham_total );
		$spam_total = max( 1, $spam_total );

		$ratings = array();
		foreach ( $stats as $counts ) {
			$ham  = (int) ( $counts['ham'] ?? 0 );
			$spam = (int) ( $counts['spam'] ?? 0 );
			if ( $ham + $spam <= 0 ) {
				continue;
			}

			$g = min( 1.0, ( $ham * 2 ) / $ham_total );
			$b = min( 1.0, $spam / $spam_total );
			if ( $g + $b <= 0 ) {
				continue;
			}

			$p         = $b / ( $b + $g );
			$ratings[] = max( 0.01, min( 0.99, $p ) );
		}

		if ( array() === $ratings ) {
			return 0.5;
		}

		// Aussagekraeftigste Tokens zuerst (groesster Abstand zu 0,5), Deckel.
		usort(
			$ratings,
			static function ( $a, $b ) {
				return abs( $b - 0.5 ) <=> abs( $a - 0.5 );
			}
		);
		$ratings = array_slice( $ratings, 0, self::MAX_TOKENS );

		$prod    = 1.0;
		$prodinv = 1.0;
		foreach ( $ratings as $p ) {
			$prod    *= $p;
			$prodinv *= ( 1 - $p );
		}

		$denom = $prod + $prodinv;
		return $denom <= 0 ? 0.5 : $prod / $denom;
	}
}
