<?php

declare(strict_types=1);

namespace App\Framework\Waf\Rules;

/**
 * Actions that can be taken when a rule matches
 */
enum RuleAction: string
{
    case ALLOW = 'allow';
    case BLOCK = 'block';
    case LOG = 'log';
    case WARN = 'warn';
    case CHALLENGE = 'challenge';
    case RATE_LIMIT = 'rate_limit';
    case REDIRECT = 'redirect';
    case SANITIZE = 'sanitize';
    case SCORE = 'score';
    case CHAIN = 'chain';
    case SKIP = 'skip';
    case DENY_WITH_STATUS = 'deny_with_status';

    /**
     * Get action description
     */
    public function getDescription(): string
    {
        return match ($this) {
            self::ALLOW => 'Allow request to proceed',
            self::BLOCK => 'Block request with 403 Forbidden',
            self::LOG => 'Log detection but allow request',
            self::WARN => 'Log warning and allow request',
            self::CHALLENGE => 'Present CAPTCHA or similar challenge',
            self::RATE_LIMIT => 'Apply rate limiting to client',
            self::REDIRECT => 'Redirect to different URL',
            self::SANITIZE => 'Clean/sanitize input and continue',
            self::SCORE => 'Add to anomaly score',
            self::CHAIN => 'Chain to next rule for combined evaluation',
            self::SKIP => 'Skip next N rules',
            self::DENY_WITH_STATUS => 'Deny with custom HTTP status code'
        };
    }

    /**
     * Get default HTTP status code for action
     */
    public function getDefaultHttpStatus(): int
    {
        return match ($this) {
            self::ALLOW, self::LOG, self::WARN, self::SANITIZE,
            self::SCORE, self::CHAIN, self::SKIP => 200,
            self::BLOCK => 403,
            self::CHALLENGE => 429,
            self::RATE_LIMIT => 429,
            self::REDIRECT => 302,
            self::DENY_WITH_STATUS => 403
        };
    }

    /**
     * Check if action blocks request processing
     */
    public function blocksRequest(): bool
    {
        return match ($this) {
            self::BLOCK, self::CHALLENGE, self::RATE_LIMIT,
            self::REDIRECT, self::DENY_WITH_STATUS => true,
            default => false
        };
    }

    /**
     * Check if action allows request to continue
     */
    public function allowsContinuation(): bool
    {
        return ! $this->blocksRequest();
    }

    /**
     * Check if action requires logging
     */
    public function requiresLogging(): bool
    {
        return match ($this) {
            self::ALLOW => false,
            default => true
        };
    }

    /**
     * Get logging severity level
     */
    public function getLogLevel(): string
    {
        return match ($this) {
            self::ALLOW, self::SKIP => 'debug',
            self::LOG, self::SANITIZE, self::SCORE => 'info',
            self::WARN, self::CHAIN => 'warning',
            self::CHALLENGE, self::RATE_LIMIT, self::REDIRECT => 'notice',
            self::BLOCK, self::DENY_WITH_STATUS => 'error'
        };
    }

    /**
     * Check if action affects anomaly score
     */
    public function affectsAnomalyScore(): bool
    {
        return match ($this) {
            self::SCORE, self::WARN, self::BLOCK, self::CHALLENGE => true,
            default => false
        };
    }

    /**
     * Get default anomaly score impact
     */
    public function getAnomalyScoreImpact(): int
    {
        return match ($this) {
            self::SCORE => 5,
            self::WARN => 3,
            self::CHALLENGE => 8,
            self::BLOCK => 10,
            default => 0
        };
    }

    /**
     * Check if action can be chained
     */
    public function canBeChained(): bool
    {
        return match ($this) {
            self::SCORE, self::LOG, self::WARN, self::CHAIN => true,
            default => false
        };
    }

    /**
     * Check if action requires additional parameters
     */
    public function requiresParameters(): bool
    {
        return match ($this) {
            self::REDIRECT, self::DENY_WITH_STATUS, self::SKIP => true,
            default => false
        };
    }

    /**
     * Get required parameter names
     */
    public function getRequiredParameters(): array
    {
        return match ($this) {
            self::REDIRECT => ['url'],
            self::DENY_WITH_STATUS => ['status_code'],
            self::SKIP => ['count'],
            default => []
        };
    }
}
