<?php

declare(strict_types=1);

namespace App\Framework\Http\Middlewares;

use App\Framework\Config\SecurityConfig;
use App\Framework\Http\HttpMiddleware;
use App\Framework\Http\MiddlewareContext;
use App\Framework\Http\MiddlewarePriority;
use App\Framework\Http\MiddlewarePriorityAttribute;
use App\Framework\Http\Next;
use App\Framework\Http\RequestStateManager;
use App\Framework\Http\ResponseManipulator;

#[MiddlewarePriorityAttribute(MiddlewarePriority::SECURITY)]
final readonly class SecurityHeaderMiddleware implements HttpMiddleware
{
    public function __construct(
        private ResponseManipulator $manipulator,
        private SecurityConfig $securityConfig
    ) {
    }

    public function __invoke(MiddlewareContext $context, Next $next, RequestStateManager $stateManager): MiddlewareContext
    {
        $this->removePoweredByHeader();

        // Nächste Middleware aufrufen
        $resultContext = $next($context);

        // Security-Header IMMER hinzufügen (auch in Development)
        if ($resultContext->hasResponse()) {
            $response = $resultContext->response;
            $updatedHeaders = $response->headers;

            // Environment-spezifische Security-Header hinzufügen
            foreach ($this->getSecurityHeaders() as $name => $value) {
                if ($this->shouldAddHeader($name, $updatedHeaders)) {
                    $updatedHeaders = $updatedHeaders->with($name, $value);
                }
            }

            // Neue Response mit aktualisierten Headers erstellen
            $updatedResponse = $this->manipulator->withHeaders($response, $updatedHeaders);

            return $resultContext->withResponse($updatedResponse);
        }

        return $resultContext;
    }

    private function getSecurityHeaders(): array
    {
        // Environment-spezifische Header-Konfiguration
        $config = $this->securityConfig->enableStrictMode
            ? SecurityHeaderConfig::forProduction()
            : SecurityHeaderConfig::forDevelopment();

        return [
            'Strict-Transport-Security' => $config->hstsHeader,
            'X-Frame-Options' => $config->frameOptions,
            'X-Content-Type-Options' => 'nosniff',
            'Referrer-Policy' => $config->referrerPolicy,
            'Content-Security-Policy' => $config->contentSecurityPolicy,
            'Permissions-Policy' => $config->permissionsPolicy,
            'X-Permitted-Cross-Domain-Policies' => 'none',
            'Cross-Origin-Embedder-Policy' => $config->crossOriginEmbedderPolicy,
            'Cross-Origin-Opener-Policy' => $config->crossOriginOpenerPolicy,
            'Cross-Origin-Resource-Policy' => $config->crossOriginResourcePolicy,
        ];
    }

    private function shouldAddHeader(string $headerName, $currentHeaders): bool
    {
        // Header nur hinzufügen, wenn er noch nicht gesetzt ist
        return ! $currentHeaders->has($headerName);
    }

    private function removePoweredByHeader(): void
    {
        if (! headers_sent()) {
            header_remove('X-Powered-By');
            header_remove('Server');
        }
    }
}
