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

use Ferienpass\AdminBundle\Form\UserLoginType;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\UriSigner;
use Symfony\Component\Routing\Attribute\Route;

#[Route('/login', name: 'admin_login')]
final class LoginController extends AbstractController
{
    public function __construct(private readonly UriSigner $uriSigner)
    {
    }

    public function __invoke(Request $request): Response
    {
        $targetPath = $this->targetPath($request);
        $form = $this->createForm(UserLoginType::class, null, ['target_path' => base64_encode($targetPath)]);

        // A failed login is surfaced as a flash toast by
        // AuthenticationFailureHandler, not rendered inline here — that keeps
        // this page free of per-user state and therefore publicly cacheable.
        //
        // The form unconditionally exposes the magic-link button. Role-based
        // disabling of magic links lives on the request endpoint instead — we
        // can't gate the UI here without leaking, per email typed, whether
        // that account is a ROLE_ADMIN (timing + element presence both leak).
        /** @noinspection FormViewTemplate `createView()` messes ups error handling/redirect */
        return $this->render('@FerienpassAdmin/page/login/index.html.twig', [
            'login' => $form,
            // Where the JS passkey flow sends the user after a successful
            // /admin/assertion/result POST. Symfony's form_login does this
            // automatically for password login via the _target_path field —
            // for passkey we have to do it client-side ourselves.
            'successRedirect' => $targetPath,
        ]);
    }

    private function targetPath(Request $request): string
    {
        // If the form was submitted and the credentials were wrong, take the target
        // path from the submitted data as otherwise it would take the current page
        if ($request->isMethod('POST')) {
            return base64_decode((string) $request->request->get('_target_path'), true);
        }

        if ($request->query->has('redirect') && $this->uriSigner->checkRequest($request)) {
            return (string) $request->query->get('redirect');
        }

        return $this->generateUrl('admin_index');
    }
}
