<?php

namespace apexl\Io\modules\userDisplay\controllers;

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

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

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

        $this->render->setActive('noUI');
        $this->render->setPageTitle('Login');
        $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');
        }

        $form = $loginFormBuilder->build([
            'redirect' => $request->redirect(),
        ]);

        $components = [
            ...$components,
            $form,
            $this->component(BasicLink::class)
                ->addClass('forgottenPasswordLink')
                ->addRoute($routeManager->getRoutePattern('user.display.forgot-password'))
                ->addText($variableManager->get('user_login_forgot_password_text') ?? 'Forgot password?'),
        ];

        if (config('auth.users_can_register')) {
            $components[] = $this->component(BasicLink::class)
                ->addClass('registerLink')
                ->addRoute($routeManager->getRoutePattern('user.display.register'))
                ->addText($variableManager->get('user_login_register_text') ?? 'No account? Register.');
        }


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

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

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

}
