<?php

namespace apexl\Io\modules\userDisplay\controllers;

use apexl\Io\includes\HookManager;
use apexl\Io\includes\RouteManager;
use apexl\Io\modules\display\components\BasicLink;
use apexl\Io\modules\display\components\ComponentWrapper;
use apexl\Io\modules\display\components\ContentTitle;
use apexl\Io\modules\display\components\ImageTile;
use apexl\Io\modules\display\Controllers\DisplayController;
use apexl\Io\modules\user\entities\userEntity;
use apexl\Io\modules\user\exceptions\UserAlreadyLoggedInException;
use apexl\Io\modules\user\services\CurrentUserFactory;
use apexl\Io\modules\userDisplay\FormBuilders\LoginWithNfcFormBuilder;
use apexl\Io\modules\userDisplay\Request\LoginWithNfcDisplayRequest;
use apexl\Io\services\VariableManager;
use JsonException;
use Psr\Http\Message\ResponseInterface;
use function apexl\Io\config;

final readonly class LoginWithNfcDisplayController extends DisplayController
{
    /**
     * @throws JsonException
     */
    public function __invoke(
        VariableManager $variableManager,
        RouteManager $routeManager,
        CurrentUserFactory $currentUserFactory,
        LoginWithNfcFormBuilder $loginFormBuilder,
        HookManager $hookManager,
        LoginWithNfcDisplayRequest $request,
        ResponseInterface $response,
        ?string $loginMessageType = null
    ): ResponseInterface {
        try {
            $this->assertNotLoggedIn($currentUserFactory->get());
        } catch (UserAlreadyLoggedInException) {
            $this->output->addRedirect('user.login.redirect', $request->redirect());

            return $this->json($response);
        }

        $this->render->setActive('noUI');
        $this->render->setPageTitle('Login by NFC');
        $components = $hookManager->processHook('login_page_components_before_form', []);

        if ($loginMessageType && $message = config(sprintf('auth.login_messages.%s', $loginMessageType))) {
            $components[] = $this->component(ContentTitle::class)
                ->addContent($message)
                ->addClass('text-light');
        }

        $components[] = $this->component(ImageTile::class)
            ->src($variableManager->get('user_login_nfc_icon') ?? '/assets/icons/nfc.svg')
            ->addClass('nfc-logo w-100');

        $contentText = $variableManager->get(
            'user_login_nfc_description_text'
        ) ?? 'Tap your Access card on the reader to enable login.';
        $form = null;

        if ($request->nfcKey()) {
            $contentText = $variableManager->get(
                'user_login_nfc_detected_text'
            ) ?? 'Valid NFC card detected. Please tap the login button below to continue.';

            $form = $loginFormBuilder->build([
                'redirect' => htmlentities($request->redirect()),
                'nfc_key' => htmlentities($request->nfcKey()),
            ])->addClass('d-flex flex-column align-items-center');
        }
        $components[] = $this->component(ContentTitle::class)
            ->addContent($contentText)
            ->addClass('text-light')
            ->addClass('text-center');

        if ($form) {
            $components[] = $form;
        }

        $components[] = $this->component(BasicLink::class)
            ->addClass('forgottenPasswordLink')
            ->addRoute($routeManager->getRoutePattern('user.display.login'))
            ->addText($variableManager->get('user_login_text') ?? 'Go to User Login');

        $components = $hookManager->processHook('login_page_components_after_form', $components);

        $wrapper = $this->component(ComponentWrapper::class)
            ->addClass('d-flex flex-column align-items-center')
            ->addComponents($components);

        return $this->json($response, $this->render->build($wrapper));
    }

    /**
     * @throws UserAlreadyLoggedInException
     */
    private function assertNotLoggedIn(userEntity $user): void
    {
        if ($user->isLoggedIn()) {
            throw new UserAlreadyLoggedInException($user->id);
        }
    }
}
