<?php declare(strict_types=1);

namespace App\Engine\AdministratorUser;

class AdministratorUserController extends \App\Engine\Admin\Inertia\BaseInertiaAdminController
{

    public function getId(): string
    {
        return "AdministratorUser";
    }

    public function list(
        AdministratorUserRepository                                                    $repository,
        \Symfony\Contracts\Translation\TranslatorInterface                             $translator,
        \App\Engine\Admin\Inertia\SystemConfiguration\AdminSystemConfigurationProvider $adminSystemConfigurationProvider,
        AccessControl                                                                  $accessControl,
    ): \Symfony\Component\HttpFoundation\Response {
        $adminSystemConfigurationProvider->getConfiguration()->pageMeta->title = $translator->trans("admin.administrator-user.title");
        /** @var array<\App\Engine\AdministratorUser\AdministratorUser> $users */
        $users = $this->provideListRecords($repository);
        foreach ($users as $user) {
            $user->userAuthorizedToManageCredentials = $accessControl->isCurrentUserAuthorizedToManageAccessMethodsOfPassedUser($user->getId());
        }

        return $this->createList($repository, $users);
    }

    public function edit(
        AdministratorUserRepository                        $repository,
        \Twig\Environment                                  $twig,
        \Symfony\Component\HttpFoundation\Request          $request,
        \Symfony\Contracts\Translation\TranslatorInterface $translator,
        \Doctrine\ORM\EntityManagerInterface               $entityManager,
        AccessControl                                      $accessControl,
    ): \Symfony\Component\HttpFoundation\Response {
        $record = $repository->findOneBy(["id" => $request->attributes->get("id")]);
        $this->adminSystemConfigurationProvider->getConfiguration()->pageMeta->title = $translator->trans("admin.action.list.edit") . ": " . $record->getEmail();
        $edit = new \App\Engine\Inertia\Admin\ViewModels\EditViewModel(
            record: $record,
        );

        $form = $this->createEditForm($translator, $record, editableRoles: $accessControl->isCurrentUserAuthorizedToManageRoles());
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $entityManager->flush();
            $this->addFlash("success", $translator->trans("admin.action.edit.successfully-updated"));
        }

        return $this->createEditResponse($twig, $form, $edit);
    }

    public function new(
        \Twig\Environment                                  $twig,
        \Symfony\Component\HttpFoundation\Request          $request,
        \Symfony\Contracts\Translation\TranslatorInterface $translator,
        \Doctrine\ORM\EntityManagerInterface               $entityManager,
    ): \Symfony\Component\HttpFoundation\Response {
        $record = new AdministratorUser();
        $this->adminSystemConfigurationProvider->getConfiguration()->pageMeta->title = $translator->trans("admin.action.list.new");
        $edit = new \App\Engine\Inertia\Admin\ViewModels\EditViewModel(
            record: $record,
        );

        $form = $this->createEditForm($translator, $record)
            ->remove("id")
            ->remove("submit")
            ->add("submit", \Symfony\Component\Form\Extension\Core\Type\SubmitType::class, [
                "label" => $translator->trans("admin.action.edit.create"),
            ]);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $entityManager->persist($record);
            $entityManager->flush();
            $this->addFlash("success", $translator->trans("admin.action.new.successfully-created"));
            return $this->redirectToRoute("AdminAdministratorUserList");
        }

        return $this->createEditResponse($twig, $form, $edit);
    }

    public function delete(
        AdministratorUserRepository                        $repository,
        \Doctrine\ORM\EntityManagerInterface               $entityManager,
        \Symfony\Contracts\Translation\TranslatorInterface $translator,
        \Symfony\Component\HttpFoundation\Request          $request,
    ): \Symfony\Component\HttpFoundation\RedirectResponse {
        $redirectRoute = "AdminAdministratorUserList";
        $recordId = $request->attributes->get("id");
        $entity = $repository->findOneBy(["id" => $recordId]);
        if (!$entity) {
            $this->addFlash("danger", $translator->trans("admin.action.delete.unable-to-delete-record"));
            return $this->redirectToRoute($redirectRoute);
        }

        return $this->createDelete(
            entity: $entity,
            redirectRoute: $redirectRoute,
            entityManager: $entityManager,
            translator: $translator
        );
    }

    public function profile(): \Symfony\Component\HttpFoundation\Response
    {
        return $this->inertia->render(
            component: "{$this->getVueComponent()}/Profile",
            props: $this->getInertiaProps(),
        );
    }

    public function accessMethods(
        AdministratorUserRepository                                             $repository,
        \Twig\Environment                                                       $twig,
        \Symfony\Component\HttpFoundation\Request                               $request,
        \Symfony\Contracts\Translation\TranslatorInterface                      $translator,
        \Doctrine\ORM\EntityManagerInterface                                    $entityManager,
        \Symfony\Component\Routing\RouterInterface                              $router,
        WebauthnCredentialProvider                                              $webauthnCredentialProvider,
        \Symfony\Component\Form\FormFactoryInterface                            $formFactory,
        \Symfony\Component\PasswordHasher\Hasher\PasswordHasherFactoryInterface $hasherFactory,
        AccessControl                                                           $accessControl,
    ): \Symfony\Component\HttpFoundation\Response {
        $record = $repository->findOneBy(["id" => $request->attributes->get("id")]);
        $this->adminSystemConfigurationProvider->getConfiguration()->pageMeta->title = $translator->trans("admin.administrator-user.actions.access-methods.title") . ": " . $record->getEmail();

        $data = new \App\Engine\AdministratorUser\Forms\ChangePasswordFormDTO();
        $form = $formFactory->create(type: \App\Engine\AdministratorUser\Forms\ChangePasswordForm::class, data: $data);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $hasher = $hasherFactory->getPasswordHasher(\App\Engine\AdministratorUser\AdministratorUser::class);
            $record->setPassword($hasher->hash($data->newPassword));

            $entityManager->persist($record);
            $entityManager->flush();
            $this->addFlash("success", $translator->trans("admin.administrator-user.actions.access-methods.password-successfuly-changed"));
        }

        $renderedForm = $twig->render('form/form.html.twig', ['form' => $form->createView()]);

        $webauthnForm = new \App\Engine\Inertia\Admin\ViewModels\WebauthnFormViewModel();
        $webauthnForm->optionsUrl = $router->generate(\App\Engine\Admin\Auth\BundleDefinedRouteIdentifiers::WEBAUTHN_ADD_CREDENTIAL_TO_USER_OPTIONS);
        $webauthnForm->resultUrl = $router->generate(\App\Engine\Admin\Auth\BundleDefinedRouteIdentifiers::WEBAUTHN_ADD_CREDENTIAL_TO_USER);

        $managePasskeys = new \App\Engine\Inertia\Admin\ViewModels\Passkeys\ManagePasskeysViewModel();
        $managePasskeys->userUuid = $record->getUuid();
        $managePasskeys->userId = $record->getId();
        $managePasskeys->webauthnForm = $webauthnForm;
        $managePasskeys->registeredPasskeys = $webauthnCredentialProvider->provideAllCredentialsOrderedByCreationForAdministration(adminUserUuid: $record->getUuid());

        $props = new \App\Engine\Inertia\Admin\Props\Actions\AdministratorUserAccessMethodsProps();
        $props->passwordForm = new \App\Engine\Inertia\ViewModels\Form\FormViewModel(
            renderedForm: $renderedForm,
        );
        $props->passkeys = $managePasskeys;
        $props->userAuthorizedToManage = $accessControl->isCurrentUserAuthorizedToManageAccessMethodsOfPassedUser($record->getId());

        return $this->inertia->render(
            component: "{$this->getVueComponent()}/AccessMethods",
            props: $this->getInertiaProps($props),
        );
    }

    public function deleteStoredPasskey(
        AdministratorUserRepository                         $repository,
        \Symfony\Component\HttpFoundation\Request           $request,
        \Symfony\Contracts\Translation\TranslatorInterface  $translator,
        \Doctrine\ORM\EntityManagerInterface                $entityManager,
        AccessControl                                       $accessControl,
        \App\Engine\Admin\Auth\WebauthnCredentialRepository $webauthnCredentialRepository,
    ): \Symfony\Component\HttpFoundation\Response {
        $record = $repository->findOneBy(["id" => $id = $request->attributes->get("id")]);
        $credential = $webauthnCredentialRepository->findOneBy(["id" => $request->query->get("credentialId")]);
        $redirect = $this->redirectToRoute("AdminAdministratorUserAccessMethods", ["id" => $id]);
        if (!($record && $credential)) {
            $this->addFlash("danger", $translator->trans("admin.administrator-user.actions.access-methods.passkey-unable-to-delete"));
            return $redirect;
        }

        if (!$accessControl->isCurrentUserAuthorizedToManageAccessMethodsOfPassedUser($record->getId())) {
            $this->addFlash("danger", $translator->trans("admin.administrator-user.actions.access-methods.unauthorized-user"));
            return $redirect;
        }

        $entityManager->remove($credential);
        $entityManager->flush();

        $this->addFlash("success", $translator->trans("admin.administrator-user.actions.access-methods.passkey-deleted"));
        return $redirect;
    }

    private function createEditForm(\Symfony\Contracts\Translation\TranslatorInterface $translator, ?AdministratorUser $administratorUser = null, bool $editableRoles = true): \Symfony\Component\Form\FormInterface
    {
        return $this->createFormBuilder($administratorUser, ["attr" => ["class" => "row"]])
            ->add("id", \Symfony\Component\Form\Extension\Core\Type\TextType::class, [
                "label" => $translator->trans("admin.administrator-user.id"),
                "disabled" => true,
            ])
            ->add("email", \Symfony\Component\Form\Extension\Core\Type\EmailType::class, [
                "row_attr" => ["class" => "col-md-6 mb-3"],
                "label" => $translator->trans("admin.administrator-user.email"),
                "required" => true,
            ])
            ->add("status", \Symfony\Component\Form\Extension\Core\Type\EnumType::class, [
                "class" => StatusEnum::class,
                "row_attr" => ["class" => "col-md-6 mb-3"],
                "label" => $translator->trans("admin.administrator-user.status"),
                "choice_label" => fn(?StatusEnum $choice) => $translator->trans("admin.administrator-user.statusValues.$choice->value"),
                "required" => true,
            ])
            ->add("firstName", \Symfony\Component\Form\Extension\Core\Type\TextType::class, [
                "row_attr" => ["class" => "col-md-6 mb-3"],
                "label" => $translator->trans("admin.administrator-user.first-name"),
                "required" => true,
                "constraints" => [
                    new \Symfony\Component\Validator\Constraints\Length(min: 2, max: 10),
                ],
            ])
            ->add("lastName", \Symfony\Component\Form\Extension\Core\Type\TextType::class, [
                "row_attr" => ["class" => "col-md-6 mb-3"],
                "label" => $translator->trans("admin.administrator-user.last-name"),
                "required" => true,
            ])
            ->add("roles", \Symfony\Component\Form\Extension\Core\Type\ChoiceType::class, [
                "row_attr" => ["class" => "col-md-6 mb-3"],
                "label" => $translator->trans("admin.administrator-user.roles"),
                "choices" => array_combine(
                    $roles = array_map(fn(\App\Engine\Security\Role $role) => $role->value, \App\Engine\Security\Role::cases()),
                    $roles,
                ),
                "multiple" => true,
                "disabled" => !$editableRoles,
                "required" => true,
            ])
            ->add("about_section_title", \Symfony\Component\Form\Extension\Core\Type\FormType::class, [
                "label" => $translator->trans("admin.administrator-user.about.section-title"),
                "mapped" => false,
                "row_attr" => ["class" => "FormSectionTitle"],
            ])
            ->add("contactAddress", \Symfony\Component\Form\Extension\Core\Type\TextType::class, [
                "row_attr" => ["class" => "col-md-6 mb-3"],
                "label" => $translator->trans("admin.administrator-user.about.contact-address"),
                "required" => false,
            ])
            ->add("employer", \Symfony\Component\Form\Extension\Core\Type\TextType::class, [
                "row_attr" => ["class" => "col-md-6 mb-3"],
                "label" => $translator->trans("admin.administrator-user.about.employer"),
                "required" => false,
            ])
            ->add("jobPosition", \Symfony\Component\Form\Extension\Core\Type\TextType::class, [
                "row_attr" => ["class" => "col-md-6 mb-3"],
                "label" => $translator->trans("admin.administrator-user.about.job-position"),
                "required" => false,
            ])
            ->add("socials_section_title", \Symfony\Component\Form\Extension\Core\Type\FormType::class, [
                "label" => $translator->trans("admin.administrator-user.socials.section-title"),
                "mapped" => false,
                "row_attr" => ["class" => "FormSectionTitle"],
                "help" => $translator->trans("admin.administrator-user.socials.section-title-help"),
            ])
            ->add("socialsWebsite", \Symfony\Component\Form\Extension\Core\Type\TextType::class, [
                "row_attr" => ["class" => "col-md-6 mb-3"],
                "label" => $translator->trans("admin.administrator-user.socials.website"),
                "required" => false,
            ])
            ->add("socialsPlatformX", \Symfony\Component\Form\Extension\Core\Type\TextType::class, [
                "row_attr" => ["class" => "col-md-6 mb-3"],
                "label" => $translator->trans("admin.administrator-user.socials.platform-x"),
                "required" => false,
            ])
            ->add("socialsFacebook", \Symfony\Component\Form\Extension\Core\Type\TextType::class, [
                "row_attr" => ["class" => "col-md-6 mb-3"],
                "label" => $translator->trans("admin.administrator-user.socials.facebook"),
                "required" => false,
            ])
            ->add("socialsInstagram", \Symfony\Component\Form\Extension\Core\Type\TextType::class, [
                "row_attr" => ["class" => "col-md-6 mb-3"],
                "label" => $translator->trans("admin.administrator-user.socials.instagram"),
                "required" => false,
            ])
            ->add("socialsLinkedIn", \Symfony\Component\Form\Extension\Core\Type\TextType::class, [
                "row_attr" => ["class" => "col-md-6 mb-3"],
                "label" => $translator->trans("admin.administrator-user.socials.linked-in"),
                "required" => false,
            ])
            ->add("submit", \Symfony\Component\Form\Extension\Core\Type\SubmitType::class, [
                "label" => $translator->trans("admin.action.edit.save"),
            ])
            ->getForm();
    }

}
