<?php

declare(strict_types=1);

namespace App\Framework\Sitemap;

use App\Framework\Attributes\Singleton;
use App\Framework\Core\Route;
use App\Framework\Http\Method;
use App\Framework\Router\CompiledRoutes;
use App\Framework\Router\UrlGenerator;
use Generator;

#[Singleton]
final readonly class SitemapGenerator
{
    public function __construct(
        private CompiledRoutes $routes,
        private UrlGenerator $urlGenerator
    ) {
    }

    /**
     * Generiert Sitemap-URLs aus allen verfügbaren Named Routes
     *
     * @return Generator<SitemapEntry>
     */
    public function generateFromRoutes(): Generator
    {
        foreach ($this->getPublicRoutes() as $route) {
            if ($this->isStaticRoute($route)) {
                yield new SitemapEntry(
                    url: $this->urlGenerator->absoluteRoute($route->name),
                    lastmod: new \DateTimeImmutable(),
                    changefreq: $this->determineChangeFreq($route),
                    priority: $this->determinePriority($route)
                );
            }
        }
    }

    /**
     * Holt alle öffentlichen Named Routes
     */
    private function getPublicRoutes(): Generator
    {
        // Verwende Generator für memory-effiziente Iteration
        foreach ($this->routes->getAllNamedRoutesGenerator() as $name => $route) {

            // Nur GET-Routen für Sitemap: Named Routes sind aktuell immer nur Routes mit GET Methode
            if (/*$this->supportsMethod($route, Method::GET) &&*/
                ! $this->isExcludedFromSitemap($route)) {
                yield $route;
            }
        }
    }

    private function isStaticRoute(Route $route): bool
    {
        // Prüft ob Route keine Parameter benötigt
        return ! str_contains($route->path, '{');
    }

    private function supportsMethod(Route $route, Method $method): bool
    {
        return in_array($method->value, $route->method->value ?? [], true);
    }

    private function isExcludedFromSitemap(Route $route): bool
    {
        // Admin/API-Routen ausschließen
        $excludePatterns = ['/admin', '/api', '/auth'];

        return array_any($excludePatterns, fn($pattern) => str_starts_with($route->path, $pattern));

    }

    private function determineChangeFreq(Route $route): string
    {
        // Basierend auf Route-Name oder Pfad
        return match (true) {
            str_contains($route->path, '/blog') => 'weekly',
            str_contains($route->path, '/news') => 'daily',
            $route->name === 'home' => 'weekly',
            default => 'monthly'
        };
    }

    private function determinePriority(Route $route): float
    {
        return match ($route->name) {
            'home' => 1.0,
            'about', 'contact' => 0.8,
            default => 0.5
        };
    }
}
