<?php

declare(strict_types=1);

final class MyronDownloadPageMarkupAction implements MyronAction
{
    public function __construct(
        private readonly MyronContentRepository $repository,
    ) {
    }

    public function metadata(): MyronActionMetadata
    {
        return new MyronActionMetadata(
            uri: '/api/v1/content/pages/{pageId}/markup',
            method: 'GET',
            domain: 'content',
            resource: 'page-markup',
            verb: 'downloadMarkup',
            inputSchema: [
                'type' => 'object',
                'properties' => ['pageId' => ['type' => 'string']],
                'required' => ['pageId'],
            ],
            outputSchema: [
                'type' => 'object',
                'properties' => [
                    'filename' => ['type' => 'string'],
                    'contentType' => ['type' => 'string'],
                    'body' => ['type' => 'string'],
                ],
            ],
            requiredScope: MyronApiScopes::CONTENT_READ,
            summary: 'Download a published page as rendered HTML markup for SEO analysis or AI agent consumption.',
            sideEffects: [],
            preconditions: ['page exists', 'page is published', 'effective indexability is true'],
            postconditions: ['text/html body returned as downloadable markup'],
            audienceClass: 3,
            adminAliases: ['pages.downloadMarkup'],
            snapshotInclude: false,
            exposeToMcp: true,
        );
    }

    public function execute(array $input, MyronActionCallerContext $caller): MyronActionResult
    {
        $pageId = trim((string) ($input['pageId'] ?? ''));
        if ($pageId === '') {
            return MyronActionResult::error('input_invalid', 'pageId is required.');
        }

        $page = $this->repository->getPublishedPageById($pageId);
        if (!is_array($page)) {
            return MyronActionResult::error('not_found', 'Published page not found.');
        }

        if (!$this->repository->isPageMarkupDownloadable($page)) {
            return MyronActionResult::error(
                'not_indexable',
                'This page type is not available for markup download. Specialty content like funnels is excluded by site policy.'
            );
        }

        $navigationByPlacement = $this->repository->listPublishedMenuNavigationByPlacements(['primary'], ['footer']);
        $navigation = $navigationByPlacement['trees']['primary'] ?? [];
        $footerNavigation = $navigationByPlacement['flat']['footer'] ?? [];
        $resolvedPath = (string) ($page['path'] ?? '/');
        $headerContext = myronPublicHeaderContextResolver()->resolve($page, $resolvedPath, $navigation);
        $html = myronPublishedPageHtmlAssembler()->assemble($page, [
            'basePath' => myronPublicBasePath(),
            'requestUri' => myronBuildPublicPageUrl($resolvedPath),
            'resolvedPath' => $resolvedPath,
            'navigation' => is_array($navigation) ? $navigation : [],
            'footerNavigation' => is_array($footerNavigation) ? $footerNavigation : [],
            'headerContext' => $headerContext,
            'headMetadata' => myronPublicHeadMetadataResolver()->resolvePublishedPage($page),
            'currentUser' => null,
            'channel' => 'admin-preview',
        ]);

        return MyronActionResult::ok([
            'filename' => $this->filenameForPage($page),
            'contentType' => 'text/html; charset=utf-8',
            'body' => $html,
        ]);
    }

    /**
     * @param array<string, mixed> $page
     */
    private function filenameForPage(array $page): string
    {
        $slug = trim((string) ($page['slug'] ?? ''));
        if ((string) ($page['path'] ?? '') === '/' || $slug === '' || $slug === 'home') {
            return 'index.html';
        }

        $safe = preg_replace('/[^a-z0-9._-]+/i', '-', $slug) ?: 'page';
        return trim($safe, '.-') . '.html';
    }
}
