<?php

declare(strict_types=1);

namespace App\Domain\Meta\Http\Middleware;

use App\Domain\Meta\Service\MetaManager;
use App\Framework\Http\Request;
use App\Framework\Http\Response;
use App\Framework\View\RenderContext;

final readonly class MetaMiddleware
{
    public function __construct(
        private MetaManager $metaManager,
        private ?RenderContext $renderContext = null,
    ) {
    }

    public function handle(Request $request, callable $next): Response
    {
        // Meta-Daten automatisch für Request laden
        $context = $this->extractContextFromRequest($request);
        $meta = $this->metaManager->resolveForRequest($request, $context);

        // In RenderContext injizieren (falls verfügbar)
        if ($this->renderContext && ! $meta->isEmpty()) {
            $this->renderContext->setMeta($meta);
        }

        // Meta-Daten für späteren Zugriff am Request speichern
        $request->setAttribute('meta', $meta);

        $response = $next($request);

        // Für HTML-Responses: Meta-Tags automatisch in <head> injizieren
        if ($this->shouldInjectMeta($response)) {
            $this->injectMetaIntoResponse($response, $meta);
        }

        return $response;
    }

    private function extractContextFromRequest(Request $request): array
    {
        $context = [];

        // Route-Parameter hinzufügen
        if ($params = $request->getRouteParameters()) {
            $context = array_merge($context, $params);
        }

        // Query-Parameter hinzufügen
        if ($query = $request->getQueryParams()) {
            $context['query'] = $query;
        }

        // User-Info hinzufügen (falls verfügbar)
        if ($user = $request->getAttribute('user')) {
            $context['user'] = $user;
        }

        return $context;
    }

    private function shouldInjectMeta(Response $response): bool
    {
        $contentType = $response->getHeader('Content-Type') ?? '';

        return str_contains($contentType, 'text/html') ||
               (empty($contentType) && $this->isHtmlContent($response->getBody()));
    }

    private function isHtmlContent(string $content): bool
    {
        return str_contains($content, '<html') || str_contains($content, '<head');
    }

    private function injectMetaIntoResponse(Response $response, \App\Domain\Meta\ValueObject\MetaData $meta): void
    {
        $content = $response->getBody();
        $metaHtml = $meta->render();

        if (empty($metaHtml)) {
            return;
        }

        // Versuche Meta-Tags in <head> zu injizieren
        if (preg_match('/<head[^>]*>/i', $content, $matches, PREG_OFFSET_CAPTURE)) {
            $headStart = $matches[0][1] + strlen($matches[0][0]);
            $newContent = substr_replace($content, "\n" . $metaHtml . "\n", $headStart, 0);
            $response->setBody($newContent);
        }
        // Fallback: Vor </head> einfügen
        elseif (stripos($content, '</head>') !== false) {
            $newContent = str_ireplace('</head>', $metaHtml . "\n</head>", $content);
            $response->setBody($newContent);
        }
        // Letzter Fallback: Nach <html> einfügen
        elseif (preg_match('/<html[^>]*>/i', $content)) {
            $newContent = preg_replace('/(<html[^>]*>)/i', '$1' . "\n<head>\n" . $metaHtml . "\n</head>", $content);
            $response->setBody($newContent);
        }
    }
}
