<?php

declare(strict_types=1);

namespace App\Domain\Meta\Service;

use App\Domain\Meta\Repository\MetaRepositoryInterface;
use App\Domain\Meta\ValueObject\MetaData;
use App\Framework\Cache\CacheInterface;
use App\Framework\Http\Request;

final readonly class MetaManager
{
    public function __construct(
        private MetaRepositoryInterface $repository,
        private ?CacheInterface $cache = null,
        private ?MetaTemplateResolver $templateResolver = null,
    ) {
    }

    /**
     * Löst Meta-Daten für einen Request auf
     */
    public function resolveForRequest(Request $request, array $context = []): MetaData
    {
        $route = $this->extractRoute($request);
        $cacheKey = "meta:{$route}:" . md5(serialize($context));

        // Cache-Check
        if ($this->cache && ($cached = $this->cache->get($cacheKey))) {
            return $cached;
        }

        $meta = new MetaData();

        // 1. Route-basierte Meta-Daten
        if ($routeMeta = $this->repository->findByRoute($route)) {
            $meta = $meta->merge($routeMeta->metaData);
        }

        // 2. Entity-basierte Meta-Daten
        if ($entityMeta = $this->resolveEntityMeta($request)) {
            $meta = $meta->merge($entityMeta->metaData);
        }

        // 3. Template-Verarbeitung
        if ($this->templateResolver && ! empty($context)) {
            $meta = $this->templateResolver->resolve($meta, $context);
        }

        // 4. Cache speichern
        if ($this->cache) {
            $this->cache->set($cacheKey, $meta, 3600);
        }

        return $meta;
    }

    /**
     * Löst Meta-Daten für eine spezifische Route auf
     */
    public function resolveForRoute(string $route, array $context = []): MetaData
    {
        $meta = new MetaData();

        if ($routeMeta = $this->repository->findByRoute($route)) {
            $meta = $meta->merge($routeMeta->metaData);
        }

        if ($this->templateResolver && ! empty($context)) {
            $meta = $this->templateResolver->resolve($meta, $context);
        }

        return $meta;
    }

    /**
     * Löst Meta-Daten für eine Entity auf
     */
    public function resolveForEntity(string $entityType, int $entityId, array $context = []): MetaData
    {
        $meta = new MetaData();

        if ($entityMeta = $this->repository->findByEntity($entityType, $entityId)) {
            $meta = $meta->merge($entityMeta->metaData);
        }

        if ($this->templateResolver && ! empty($context)) {
            $meta = $this->templateResolver->resolve($meta, $context);
        }

        return $meta;
    }

    /**
     * Invalidiert den Cache für eine Route
     */
    public function invalidateCache(string $route): void
    {
        if (! $this->cache) {
            return;
        }

        // Alle Cache-Keys für diese Route löschen
        $pattern = "meta:{$route}:*";
        $this->cache->deleteByPattern($pattern);
    }

    /**
     * Invalidiert den gesamten Meta-Cache
     */
    public function invalidateAllCache(): void
    {
        if (! $this->cache) {
            return;
        }

        $this->cache->deleteByPattern('meta:*');
    }

    private function extractRoute(Request $request): string
    {
        // Extrahiert die Route aus dem Request
        $uri = $request->getUri();
        $path = parse_url($uri, PHP_URL_PATH) ?: '/';

        // Query-Parameter entfernen für einheitliche Cache-Keys
        return rtrim($path, '/') ?: '/';
    }

    private function resolveEntityMeta(Request $request): ?\App\Domain\Meta\Entity\MetaEntry
    {
        // Versuche Entity-Typ und ID aus der Route zu extrahieren
        $routeParams = $request->getRouteParameters() ?? [];

        if (isset($routeParams['id'])) {
            $entityType = $this->extractEntityTypeFromRoute($this->extractRoute($request));
            if ($entityType) {
                return $this->repository->findByEntity($entityType, (int)$routeParams['id']);
            }
        }

        return null;
    }

    private function extractEntityTypeFromRoute(string $route): ?string
    {
        // Einfache Heuristik: /products/123 -> entityType = "product"
        // /blog/456 -> entityType = "blog"
        $parts = explode('/', trim($route, '/'));

        if (count($parts) >= 2 && is_numeric($parts[1])) {
            $entityType = rtrim($parts[0], 's'); // Plural zu Singular

            return $entityType;
        }

        return null;
    }

    /**
     * Erstellt Standard-Meta-Daten basierend auf dem Request
     */
    public function createDefaultMeta(Request $request): MetaData
    {
        $route = $this->extractRoute($request);
        $title = $this->generateDefaultTitle($route);

        return new MetaData(
            title: $title,
            description: "Seite: {$route}",
            ogTitle: $title,
            ogType: 'website',
        );
    }

    private function generateDefaultTitle(string $route): string
    {
        if ($route === '/') {
            return 'Startseite';
        }

        $parts = explode('/', trim($route, '/'));
        $title = ucfirst(str_replace(['-', '_'], ' ', end($parts)));

        return $title;
    }
}
