<?php

declare(strict_types=1);

/*
 * This file is part of the Ferienpass package.
 *
 * (c) Richard Henkenjohann <richard@ferienpass.online>
 *
 * For more information visit the project website <https://ferienpass.online>
 * or the documentation under <https://docs.ferienpass.online>.
 */

namespace Ferienpass\CmsBundle\Page;

use Contao\CoreBundle\Exception\NoRootPageFoundException;
use Contao\CoreBundle\Framework\ContaoFramework;
use Contao\CoreBundle\Routing\PageFinder;
use Contao\PageModel;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpKernel\Fragment\FragmentHandler;
use Symfony\Contracts\Translation\TranslatorInterface;

class PageBuilderFactory
{
    public function __construct(private readonly FragmentHandler $fragmentHandler, private readonly TranslatorInterface $translator, private readonly ContaoFramework $framework, private readonly RequestStack $requestStack, private readonly PageFinder $pageFinder)
    {
    }

    /**
     * @throws NoRootPageFoundException if no page model is given and the installation has no published root page to fall back to
     */
    public function create(?PageModel $pageModel = null): PageBuilder
    {
        $this->framework->initialize();

        $pageModel ??= $this->findRootPage();

        if (!$pageModel instanceof PageModel) {
            throw new NoRootPageFoundException('No published root page found to build the page with.');
        }

        return new PageBuilder($pageModel, $this->fragmentHandler, $this->translator, $this->framework, $this->requestStack);
    }

    /**
     * Routes that are not Contao pages (login, registration, error screens, …)
     * still need a root page to pull the layout and the page metadata from.
     *
     * Prefer the root page of the current host so a multi-domain installation
     * doesn't render another domain's layout, and fall back to the first
     * published root page for hosts that no DNS entry matches (local dev
     * domains, for instance).
     */
    private function findRootPage(): ?PageModel
    {
        $request = $this->requestStack->getCurrentRequest();

        if (null !== $request) {
            $rootPage = $this->pageFinder->findRootPageForHostAndLanguage($request->getHost(), $request->headers->get('Accept-Language'));

            if ($rootPage instanceof PageModel) {
                return $rootPage;
            }
        }

        $rootPages = $this->framework->getAdapter(PageModel::class)->findPublishedRootPages();

        return $rootPages?->getModels()[0] ?? null;
    }
}
