<?php

declare(strict_types=1);

namespace App\Services\Sitemaps;

use Illuminate\Support\Facades\Cache;

final class PublishedSitemapResolver
{
    public function __construct(private readonly SitemapReleaseManager $releases)
    {
    }

    /**
     * @return array{content: string, release_id: string, document_name: string}|null
     */
    public function resolveIndex(): ?array
    {
        return $this->resolveDocumentName(SitemapCacheService::INDEX_DOCUMENT);
    }

    /**
     * @return array{content: string, release_id: string, document_name: string}|null
     */
    public function resolveNamed(string $requestedName): ?array
    {
        $releaseId = Cache::remember(
            'sitemaps:active-release-id',
            60,
            fn (): ?string => $this->releases->activeReleaseId(),
        );

        if (! is_string($releaseId) || $releaseId === '') {
            return null;
        }

        $manifest = Cache::remember(
            'sitemaps:manifest:' . $releaseId,
            3600,
            fn (): ?array => $this->releases->readManifest($releaseId),
        );

        if (! is_array($manifest)) {
            return null;
        }

        $documentName = $this->canonicalDocumentName($requestedName, $manifest);

        return $documentName !== null ? $this->resolveDocumentName($documentName) : null;
    }

    private function resolveDocumentName(string $documentName): ?array
    {
        $releaseId = Cache::remember(
            'sitemaps:active-release-id',
            60,
            fn (): ?string => $this->releases->activeReleaseId(),
        );

        if (! is_string($releaseId) || $releaseId === '') {
            return null;
        }

        $ttl = max((int) config('sitemaps.cache_ttl_seconds', 900), 3600);
        $cacheKey = 'sitemaps:doc:' . $releaseId . ':' . $documentName;

        $content = Cache::get($cacheKey);

        if (! is_string($content) || $content === '') {
            $content = $this->releases->getDocument($releaseId, $documentName);
            if (is_string($content) && $content !== '') {
                Cache::put($cacheKey, $content, $ttl);
            }
        }

        return is_string($content) && $content !== ''
            ? ['content' => $content, 'release_id' => $releaseId, 'document_name' => $documentName]
            : null;
    }

    private function canonicalDocumentName(string $requestedName, array $manifest): ?string
    {
        $documents = (array) ($manifest['documents'] ?? []);

        if (isset($documents[$requestedName])) {
            return $requestedName;
        }

        foreach ((array) ($manifest['families'] ?? []) as $familyName => $family) {
            $entryName = (string) ($family['entry_name'] ?? '');
            if ($requestedName === $familyName && $entryName !== '') {
                return $entryName;
            }

            if (preg_match('/^' . preg_quote((string) $familyName, '/') . '-([0-9]+)$/', $requestedName, $matches)) {
                $number = (int) $matches[1];
                $candidate = sprintf('%s-%04d', $familyName, $number);
                if (in_array($candidate, (array) ($family['shards'] ?? []), true)) {
                    return $candidate;
                }
            }
        }

        return null;
    }
}