<?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\Controller\Page;

use Contao\CoreBundle\DependencyInjection\Attribute\AsPage;
use Contao\CoreBundle\Exception\PageNotFoundException;
use Ferienpass\CmsBundle\Controller\AbstractController;
use Ferienpass\CmsBundle\Fragment\FragmentReference;
use Ferienpass\CmsBundle\UserAccount\UserAccountFragments;
use Ferienpass\CmsBundle\UserAccount\UserAccountFragmentValueHolder;
use Ferienpass\CoreBundle\Entity\User;
use Ferienpass\CoreBundle\HttpCache\CacheTag;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

#[AsPage('user_account', path: '{alias}', defaults: ['alias' => 'account'], contentComposition: false)]
class UserAccountPage extends AbstractController
{
    public function __construct(private readonly UserAccountFragments $fragments)
    {
    }

    public function __invoke(string $alias, Request $request): Response
    {
        $this->initializeContaoFramework();

        $fragments = array_filter($this->fragments->all(), static fn (UserAccountFragmentValueHolder $vh) => $alias === $vh->getAlias());

        if (empty($fragments)) {
            throw new PageNotFoundException();
        }

        $this->checkToken();

        // Tag the account page with the current user's UUID and all their participants.
        // Any change to the user or any of their participants invalidates this page.
        $tags = [];
        $user = $this->getUser();
        if ($user instanceof User) {
            $tags[] = CacheTag::user($user);
            foreach ($user->getParticipants() as $participant) {
                $tags[] = CacheTag::participant($participant);
            }
        }
        if ($tags) {
            $this->tagResponse($tags);
        }

        $builder = $this->createPageBuilder($request->attributes->get('pageModel'));

        $builder->addFragment('main', new FragmentReference('ferienpass.fragment.user_account_navigation'));

        foreach ($fragments as $fragment) {
            $builder->addFragment('main', new FragmentReference('ferienpass.fragment.'.$fragment->getKey()));
        }

        // /account is always per-user. Force private regardless of whether
        // the embedded fragments correctly stamped the merge sentinel —
        // belt-and-braces against the role-bucket cache leak. See
        // AbstractController::markPageAsPrivate().
        return $this->markPageAsPrivate($builder->getResponse());
    }
}
