<?php

declare(strict_types=1);

namespace Plugin\tnt_stabila_shop\src\Helper;

/**
 * Pure decision helper for sales-volume anomaly detection.
 *
 * Compares a recent order/sales figure against a historical baseline (e.g. the
 * average of prior equivalent weeks) and decides whether the recent value has
 * dropped far enough below that baseline to be flagged as an anomaly
 * ("orders 50% below the usual week").
 *
 * The threshold is expressed as a minimum percentage drop below the baseline.
 * A threshold of 0 (or below), or an unconfigured/non-integer setting, disables
 * detection entirely, preserving the historic behaviour of never raising a
 * sales-anomaly notification. Enabling the feature is therefore fully opt-in.
 */
class SalesAnomalyDetector
{
    /** Threshold value at (or below) which anomaly detection is switched off. */
    public const DISABLED = 0;

    /**
     * Average the historical baseline buckets.
     *
     * @param list<object{returnValue: int|float}> $totals Historical bucket totals (e.g. weekly order counts).
     * @return float Mean of the bucket values; 0.0 when the list is empty.
     */
    public static function baselineAverage(array $totals): float
    {
        if ($totals === []) {
            return 0.0;
        }
        $sum = 0.0;
        foreach ($totals as $total) {
            $sum += (float)$total->returnValue;
        }

        return $sum / \count($totals);
    }

    /**
     * Signed percentage by which the recent value sits below the baseline.
     *
     * Positive means a drop (recent below baseline), negative means growth
     * (recent above baseline). Returns 0.0 when no usable baseline exists.
     *
     * @param float $recent          The recent figure (e.g. orders in the last 7 days).
     * @param float $baselineAverage The historical baseline average.
     * @return float Percentage drop below baseline (100.0 = recent is zero).
     */
    public static function dropPercent(float $recent, float $baselineAverage): float
    {
        if ($baselineAverage <= 0.0) {
            return 0.0;
        }

        return (1.0 - $recent / $baselineAverage) * 100.0;
    }

    /**
     * Decide whether the recent figure is anomalously low versus the baseline.
     *
     * @param float    $recent               The recent figure.
     * @param float    $baselineAverage      The historical baseline average.
     * @param int|null $dropThresholdPercent Minimum drop (%) to flag; null or <= 0 disables detection.
     * @return bool True when detection is enabled, a baseline exists, and the drop meets the threshold.
     */
    public static function isAnomalous(float $recent, float $baselineAverage, ?int $dropThresholdPercent): bool
    {
        // Unconfigured or disabled threshold: preserve the historic "never flag" behaviour.
        if ($dropThresholdPercent === null || $dropThresholdPercent <= self::DISABLED) {
            return false;
        }
        // No usable baseline (no history, or non-positive average): cannot judge, so never flag.
        if ($baselineAverage <= 0.0) {
            return false;
        }

        return self::dropPercent($recent, $baselineAverage) >= (float)$dropThresholdPercent;
    }
}
