<?php
declare(strict_types=1);

namespace App\Application\Security\Services;

use App\Application\Security\Events\File\SuspiciousFileUploadEvent;
use App\Framework\Core\Events\EventDispatcher;

final class FileUploadSecurityService
{
    private const ALLOWED_MIME_TYPES = [
        'image/jpeg', 'image/png', 'image/gif', 'image/webp',
        'application/pdf', 'text/plain', 'text/csv',
        'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
    ];

    private const MAX_FILE_SIZE = 10 * 1024 * 1024; // 10MB

    private const DANGEROUS_EXTENSIONS = [
        'php', 'phtml', 'php3', 'php4', 'php5', 'pl', 'py', 'jsp', 'asp', 'sh', 'cgi',
        'exe', 'bat', 'com', 'scr', 'vbs', 'js', 'jar', 'war'
    ];

    private const MALWARE_SIGNATURES = [
        'eval(', 'base64_decode(', 'system(', 'exec(', 'shell_exec(',
        '<?php', '<%', '<script', 'javascript:'
    ];

    public function __construct(
        private EventDispatcher $eventDispatcher
    ) {}

    public function validateUpload(array $file): bool
    {
        $userEmail = $_SESSION['user_email'] ?? null;
        $filename = $file['name'] ?? '';
        $tmpName = $file['tmp_name'] ?? '';
        $size = $file['size'] ?? 0;
        $error = $file['error'] ?? UPLOAD_ERR_NO_FILE;

        // Upload-Fehler prüfen
        if ($error !== UPLOAD_ERR_OK) {
            $this->dispatchSuspiciousUpload($filename, 'unknown', $size, 'upload_error', $userEmail);
            return false;
        }

        // Dateigröße prüfen
        if ($size > self::MAX_FILE_SIZE) {
            $this->dispatchSuspiciousUpload($filename, 'unknown', $size, 'file_too_large', $userEmail);
            return false;
        }

        // Dateiendung prüfen
        $extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
        if (in_array($extension, self::DANGEROUS_EXTENSIONS)) {
            $this->dispatchSuspiciousUpload($filename, 'unknown', $size, 'dangerous_extension', $userEmail);
            return false;
        }

        // MIME-Type prüfen
        $mimeType = mime_content_type($tmpName);
        if (!in_array($mimeType, self::ALLOWED_MIME_TYPES)) {
            $this->dispatchSuspiciousUpload($filename, $mimeType, $size, 'forbidden_mime_type', $userEmail);
            return false;
        }

        // Dateiinhalt auf Malware-Signaturen prüfen
        if ($this->containsMalwareSignatures($tmpName)) {
            $this->dispatchSuspiciousUpload($filename, $mimeType, $size, 'malware_signatures_detected', $userEmail);
            return false;
        }

        // Double-Extension prüfen (z.B. file.jpg.php)
        if ($this->hasDoubleExtension($filename)) {
            $this->dispatchSuspiciousUpload($filename, $mimeType, $size, 'double_extension', $userEmail);
            return false;
        }

        return true;
    }

    private function containsMalwareSignatures(string $filePath): bool
    {
        $content = file_get_contents($filePath);
        if ($content === false) {
            return false;
        }

        foreach (self::MALWARE_SIGNATURES as $signature) {
            if (stripos($content, $signature) !== false) {
                return true;
            }
        }

        return false;
    }

    private function hasDoubleExtension(string $filename): bool
    {
        $parts = explode('.', $filename);
        if (count($parts) < 3) {
            return false;
        }

        // Prüfe ob vorletzte "Extension" gefährlich ist
        $secondLastExtension = strtolower($parts[count($parts) - 2]);
        return in_array($secondLastExtension, self::DANGEROUS_EXTENSIONS);
    }

    private function dispatchSuspiciousUpload(
        string $filename,
        string $mimeType,
        int $size,
        string $reason,
        ?string $userEmail
    ): void {
        $this->eventDispatcher->dispatch(new SuspiciousFileUploadEvent(
            filename: $filename,
            mimeType: $mimeType,
            fileSize: $size,
            suspicionReason: $reason,
            email: $userEmail
        ));
    }
}
