<?php

declare(strict_types=1);

namespace ShieldX\Security;

defined('ABSPATH') || exit;

final class WafTrendClassifier
{
    /**
     * @param array<string,mixed> $context
     */
    public static function action(string $event, array $context): string
    {
        $action = strtolower(trim((string) ($context['action'] ?? '')));
        if ($event === 'waf.block' || $action === 'block') {
            return 'blocked';
        }

        if ($action === 'would_block' || !empty($context['would_block'])) {
            return 'would_block';
        }

        return 'logged';
    }

    /**
     * @param array<string,mixed> $context
     */
    public static function severity(string $event, array $context): string
    {
        $action = self::action($event, $context);
        $score = max(0, (int) ($context['score'] ?? 0));

        if ($action !== 'logged' || $score >= 60) {
            return 'critical';
        }

        if ($score >= 30) {
            return 'high';
        }

        if ($score > 0) {
            return 'medium';
        }

        return 'low';
    }

    /**
     * @param array<string,mixed> $context
     */
    public static function category(string $event, array $context): string
    {
        $reason = strtolower(trim((string) ($context['reason'] ?? '')));
        if (strpos($reason, 'reputation') !== false) {
            return 'reputation';
        }

        if (preg_match('/(?:ip_block|temporary_block|blocklist)/', $reason) === 1) {
            return 'ip_block';
        }

        if (preg_match('/(?:budget|pcre|engine|timeout|body_)/', $reason) === 1) {
            return 'engine_safeguard';
        }

        if ($reason === 'score_threshold') {
            return 'score_threshold';
        }

        return 'rule_match';
    }

    /**
     * A rule-enforced request records the original match and a follow-up block
     * event. The follow-up remains in the audit log, but must not become a
     * second hit or action in durable trend counters.
     *
     * @param array<string,mixed> $context
     */
    public static function isFollowupBlock(string $event, array $context): bool
    {
        if ($event !== 'waf.block') {
            return false;
        }

        $reason = strtolower(trim((string) ($context['reason'] ?? '')));

        return in_array($reason, ['rule_match', 'temporary_rule_match'], true)
            && !empty($context['rules']);
    }
}
