<?php

declare(strict_types=1);

namespace App\Application\Security;

use App\Application\Security\Events\Auth\{
    AuthenticationFailedEvent
};
use App\Application\Security\Events\Input\{
    InputValidationFailureEvent,
    MaliciousInputDetectedEvent,
    SqlInjectionAttemptEvent,
    XssAttemptEvent
};
use App\Application\Security\Events\Network\SuspiciousNetworkActivityEvent;
use App\Application\Security\Events\System\SystemAnomalyEvent;
use App\Application\Security\ValueObjects\{
    OWASPEventIdentifier,
    OWASPLogLevel,
    RequestContext,
    SecurityContext
};
use App\Framework\Waf\DetectionCategory;
use App\Framework\Waf\DetectionSeverity;
use App\Framework\Waf\ValueObjects\Detection;

/**
 * WAF-OWASP Event Bridge
 *
 * Consolidates the WAF Detection system with the existing OWASP Security Event framework
 * to eliminate duplication and provide unified security event handling.
 */
final class WafOWASPEventBridge
{
    public function __construct(
        private readonly OWASPSecurityEventFactory $eventFactory,
        private readonly OWASPSecurityEventLogger $eventLogger
    ) {
    }

    /**
     * Convert WAF Detection to OWASP Security Event and log it
     */
    public function processWafDetection(
        Detection $detection,
        SecurityContext $securityContext,
        RequestContext $requestContext
    ): OWASPSecurityEvent {
        $owaspEvent = $this->convertDetectionToOWASPEvent($detection, $requestContext);

        // Log using existing OWASP logger
        $logFormat = $this->eventFactory->createFromDetection(
            $detection,
            $owaspEvent,
            $securityContext,
            $requestContext
        );

        $this->eventLogger->log($logFormat);

        return $owaspEvent;
    }

    /**
     * Convert WAF Detection to appropriate OWASP Security Event
     */
    public function convertDetectionToOWASPEvent(
        Detection $detection,
        RequestContext $requestContext
    ): OWASPSecurityEvent {
        return match ($detection->category) {
            DetectionCategory::SQL_INJECTION => $this->createSqlInjectionEvent($detection, $requestContext),
            DetectionCategory::XSS => $this->createXssEvent($detection, $requestContext),
            DetectionCategory::INJECTION,
            DetectionCategory::COMMAND_INJECTION,
            DetectionCategory::LDAP_INJECTION,
            DetectionCategory::XPATH_INJECTION,
            DetectionCategory::NOSQL_INJECTION => $this->createMaliciousInputEvent($detection, $requestContext),
            DetectionCategory::BRUTE_FORCE,
            DetectionCategory::CREDENTIAL_STUFFING,
            DetectionCategory::AUTHENTICATION_BYPASS => $this->createAuthenticationFailedEvent($detection, $requestContext),
            DetectionCategory::SUSPICIOUS_IP,
            DetectionCategory::MALICIOUS_BOT,
            DetectionCategory::DOS_ATTACK,
            DetectionCategory::DDOS_ATTACK => $this->createSuspiciousNetworkActivityEvent($detection, $requestContext),
            DetectionCategory::RATE_LIMIT_VIOLATION,
            DetectionCategory::ANOMALOUS_BEHAVIOR,
            DetectionCategory::SUSPICIOUS_USER_AGENT => $this->createSystemAnomalyEvent($detection, $requestContext),
            default => $this->createGenericInputValidationEvent($detection, $requestContext)
        };
    }

    /**
     * Create SQL Injection OWASP event from WAF detection
     */
    private function createSqlInjectionEvent(Detection $detection, RequestContext $requestContext): SqlInjectionAttemptEvent
    {
        $payload = $detection->payload?->getSample() ?? $detection->message;
        $targetField = $detection->location ?? 'unknown_field';
        $detectionMethod = "WAF Rule {($detection->ruleId?->value) ?? 'generic'}";

        return new SqlInjectionAttemptEvent(
            attackPayload: $payload,
            targetField: $targetField,
            detectionMethod: $detectionMethod,
            email: $requestContext->getUserEmail()
        );
    }

    /**
     * Create XSS OWASP event from WAF detection
     */
    private function createXssEvent(Detection $detection, RequestContext $requestContext): XssAttemptEvent
    {
        $payload = $detection->payload?->getSample() ?? $detection->message;
        $targetField = $detection->location ?? 'unknown_field';
        $xssType = $this->determineXssType($payload);

        return new XssAttemptEvent(
            attackPayload: $payload,
            targetField: $targetField,
            xssType: $xssType,
            email: $requestContext->getUserEmail()
        );
    }

    /**
     * Create Malicious Input OWASP event from WAF detection
     */
    private function createMaliciousInputEvent(Detection $detection, RequestContext $requestContext): MaliciousInputDetectedEvent
    {
        $payload = $detection->payload?->getSample() ?? $detection->message;
        $inputType = $this->mapDetectionCategoryToInputType($detection->category);

        return new MaliciousInputDetectedEvent(
            inputPayload: $payload,
            inputType: $inputType,
            detectionMethod: "WAF Rule {($detection->ruleId?->value) ?? 'generic'}",
            email: $requestContext->getUserEmail()
        );
    }

    /**
     * Create Authentication Failed OWASP event from WAF detection
     */
    private function createAuthenticationFailedEvent(Detection $detection, RequestContext $requestContext): AuthenticationFailedEvent
    {
        $attackType = $this->mapDetectionCategoryToAttackType($detection->category);
        $email = $requestContext->getUserEmail() ?? 'anonymous@waf.detection';

        return new AuthenticationFailedEvent(
            email: $email,
            reason: $attackType,
            failedAttempts: 1
        );
    }

    /**
     * Create Suspicious Network Activity OWASP event from WAF detection
     */
    private function createSuspiciousNetworkActivityEvent(Detection $detection, RequestContext $requestContext): SuspiciousNetworkActivityEvent
    {
        $activityType = $this->mapDetectionCategoryToActivityType($detection->category);

        return new SuspiciousNetworkActivityEvent(
            sourceIp: $requestContext->getClientIp(),
            activityType: $activityType,
            requestCount: 1, // WAF detections are typically single requests
            timeWindow: '1 minute',
            email: $requestContext->getUserEmail()
        );
    }

    /**
     * Create System Anomaly OWASP event from WAF detection
     */
    private function createSystemAnomalyEvent(Detection $detection, RequestContext $requestContext): SystemAnomalyEvent
    {
        $anomalyType = $this->mapDetectionCategoryToAnomalyType($detection->category);
        $metrics = [
            'threat_score' => $detection->getThreatScore()->getValue(),
            'confidence' => $detection->confidence?->getValue(),
            'location' => $detection->location,
            'client_ip' => $requestContext->getClientIp(),
            'rule_id' => $detection->ruleId?->value,
        ];

        return new SystemAnomalyEvent(
            anomalyType: $anomalyType,
            description: $detection->message,
            metrics: array_filter($metrics),
            severity: $this->mapSeverityToString($detection->severity)
        );
    }

    /**
     * Create generic Input Validation OWASP event from WAF detection
     */
    private function createGenericInputValidationEvent(Detection $detection, RequestContext $requestContext): InputValidationFailureEvent
    {
        $field = $detection->location ?? 'unknown_field';
        $reason = $detection->category->getDescription();

        return new InputValidationFailureEvent(
            field: $field,
            reason: $reason,
            attemptedValue: $detection->payload?->getSample() ?? '',
            email: $requestContext->getUserEmail()
        );
    }

    /**
     * Map WAF Detection Category to Input Type
     */
    private function mapDetectionCategoryToInputType(DetectionCategory $category): string
    {
        return match ($category) {
            DetectionCategory::COMMAND_INJECTION => 'command_injection',
            DetectionCategory::LDAP_INJECTION => 'ldap_injection',
            DetectionCategory::XPATH_INJECTION => 'xpath_injection',
            DetectionCategory::NOSQL_INJECTION => 'nosql_injection',
            DetectionCategory::XXE => 'xml_external_entity',
            DetectionCategory::PATH_TRAVERSAL => 'path_traversal',
            DetectionCategory::DESERIALIZATION => 'unsafe_deserialization',
            default => 'generic_injection'
        };
    }

    /**
     * Map WAF Detection Category to Attack Type
     */
    private function mapDetectionCategoryToAttackType(DetectionCategory $category): string
    {
        return match ($category) {
            DetectionCategory::BRUTE_FORCE => 'brute_force',
            DetectionCategory::CREDENTIAL_STUFFING => 'credential_stuffing',
            DetectionCategory::AUTHENTICATION_BYPASS => 'authentication_bypass',
            DetectionCategory::SESSION_FIXATION => 'session_fixation',
            DetectionCategory::SESSION_HIJACKING => 'session_hijacking',
            default => 'authentication_attack'
        };
    }

    /**
     * Map WAF Detection Category to Activity Type
     */
    private function mapDetectionCategoryToActivityType(DetectionCategory $category): string
    {
        return match ($category) {
            DetectionCategory::SUSPICIOUS_IP => 'suspicious_ip_activity',
            DetectionCategory::MALICIOUS_BOT => 'malicious_bot_activity',
            DetectionCategory::DOS_ATTACK => 'denial_of_service',
            DetectionCategory::DDOS_ATTACK => 'distributed_denial_of_service',
            DetectionCategory::SCRAPING_BOT => 'web_scraping',
            DetectionCategory::SPAM_BOT => 'spam_activity',
            DetectionCategory::AUTOMATED_ATTACK => 'automated_attack',
            DetectionCategory::TOR_EXIT_NODE => 'tor_network_activity',
            DetectionCategory::PROXY_DETECTION => 'proxy_usage',
            default => 'suspicious_network_activity'
        };
    }

    /**
     * Map WAF Detection Category to Anomaly Type
     */
    private function mapDetectionCategoryToAnomalyType(DetectionCategory $category): string
    {
        return match ($category) {
            DetectionCategory::RATE_LIMIT_VIOLATION => 'rate_limit_anomaly',
            DetectionCategory::ANOMALOUS_BEHAVIOR => 'behavioral_anomaly',
            DetectionCategory::SUSPICIOUS_USER_AGENT => 'user_agent_anomaly',
            DetectionCategory::FINGERPRINTING_ATTEMPT => 'fingerprinting_anomaly',
            DetectionCategory::RECONNAISSANCE => 'reconnaissance_anomaly',
            DetectionCategory::POLICY_VIOLATION => 'policy_violation_anomaly',
            default => 'system_anomaly'
        };
    }

    /**
     * Map WAF Detection Severity to String
     */
    private function mapSeverityToString(DetectionSeverity $severity): string
    {
        return match ($severity) {
            DetectionSeverity::CRITICAL => 'critical',
            DetectionSeverity::HIGH => 'high',
            DetectionSeverity::MEDIUM => 'medium',
            DetectionSeverity::LOW => 'low',
            DetectionSeverity::INFO => 'info'
        };
    }

    /**
     * Create OWASP Event Identifier from WAF Detection
     */
    public function createOWASPEventIdentifier(Detection $detection): OWASPEventIdentifier
    {
        return match ($detection->category) {
            DetectionCategory::SQL_INJECTION => OWASPEventIdentifier::maliciousInput('sql_injection'),
            DetectionCategory::XSS => OWASPEventIdentifier::maliciousInput('xss'),
            DetectionCategory::COMMAND_INJECTION => OWASPEventIdentifier::maliciousInput('command_injection'),
            DetectionCategory::AUTHENTICATION_BYPASS,
            DetectionCategory::BRUTE_FORCE => OWASPEventIdentifier::authenticationFailure('anonymous'),
            DetectionCategory::SESSION_HIJACKING => OWASPEventIdentifier::sessionHijacking('anonymous'),
            DetectionCategory::PRIVILEGE_ESCALATION => OWASPEventIdentifier::privilegeEscalation('anonymous', 'user', 'admin'),
            DetectionCategory::MALICIOUS_FILE_UPLOAD => OWASPEventIdentifier::fileUploadFailure('suspicious_file'),
            DetectionCategory::DOS_ATTACK,
            DetectionCategory::DDOS_ATTACK => OWASPEventIdentifier::systemAnomaly('denial_of_service'),
            default => OWASPEventIdentifier::systemAnomaly($detection->category->value)
        };
    }

    /**
     * Map WAF Detection Severity to OWASP Log Level
     */
    public function mapToOWASPLogLevel(Detection $detection): OWASPLogLevel
    {
        return match ($detection->severity) {
            DetectionSeverity::CRITICAL => OWASPLogLevel::FATAL,
            DetectionSeverity::HIGH => OWASPLogLevel::ERROR,
            DetectionSeverity::MEDIUM => OWASPLogLevel::WARN,
            DetectionSeverity::LOW => OWASPLogLevel::INFO,
            DetectionSeverity::INFO => OWASPLogLevel::DEBUG
        };
    }

    /**
     * Determine XSS type from payload
     */
    private function determineXssType(string $payload): string
    {
        $payload = strtolower($payload);

        if (str_contains($payload, '<script') || str_contains($payload, 'javascript:')) {
            return 'stored_xss';
        } elseif (str_contains($payload, 'onload=') || str_contains($payload, 'onerror=') ||
                  str_contains($payload, 'onclick=') || str_contains($payload, 'onmouse')) {
            return 'reflected_xss';
        } elseif (str_contains($payload, 'document.') || str_contains($payload, 'window.')) {
            return 'dom_xss';
        }

        return 'generic_xss';
    }
}
