<?php

namespace idoit\Module\UserSettings\Controller;

use Exception;
use idoit\Module\UserSettings\TfaService;
use isys_application;
use isys_auth;
use isys_component_session;
use isys_component_template_language_manager;
use isys_module_system as ModuleSystem;
use isys_module_user_settings;
use RobThree\Auth\Providers\Qr\BaconQrCodeProvider;
use RobThree\Auth\TwoFactorAuth;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Throwable;

/**
 * Controller for taking actions for TFA
 *
 * @package   Modules
 * @copyright synetics GmbH
 * @license   http://www.i-doit.com/license
 */
class TfaController
{
    private isys_component_session $session;
    private isys_component_template_language_manager $language;
    private TfaService $tfa;

    /**
     * @throws Exception
     */
    public function __construct()
    {
        $this->session = isys_application::instance()->container->get('session');
        $this->language = isys_application::instance()->container->get('language');
        $this->tfa = isys_application::instance()->container->get('tfa');
    }

    /**
     * @param Request $request
     *
     * @return JsonResponse
     */
    public function activate(Request $request): JsonResponse
    {
        try {
            $secretKey = $this->session->get('tmp_tfa');

            if (!$this->tfa->checkCode($request->get('code'), $secretKey)) {
                throw new Exception('Authentication code was invalid!');
            }

            if ($this->tfa->isActive()) {
                throw new Exception('TFA for user is already active and will be skipped!');
            }

            $this->tfa->activateTfa($secretKey);
            $this->tfa->setVerified();

            $this->session->unset('tmp_tfa');

            return new JsonResponse([
                'success' => true,
                'data'    => null,
                'message' => 'TFA was successfully activated for user!',
            ]);
        } catch (Throwable $e) {
            return new JsonResponse([
                'success' => false,
                'data'    => null,
                'message' => $e->getMessage()
            ]);
        }
    }

    /**
     * @return Response
     * @throws Exception
     */
    public function activationModal(): Response
    {
        $rules = [
            'tfa_code' => [
                'extra-params' => ['autocomplete' => 'off'],
                'disableInputGroup' => true,
                'p_strClass' => 'input-block',
                'p_bInfoIconSpacer' => 0,
                'p_strPlaceholder' => 'LC__USER_SETTINGS__TFA__PLACEHOLDER'
            ]
        ];

        $tfa = new TwoFactorAuth(new BaconQrCodeProvider(format: 'svg'), 'i-doit');

        $secret = $tfa->createSecret();
        $this->session->set('tmp_tfa', $secret);

        // @see ID-10882 Use 'BaconQrCode' provider with 'SVG' format, so we do not need any additional extension (imagick).
        $qrCodeDataUri = $tfa->getQRCodeImageAsDataUri(
            $this->session->get_mandator_name(),
            $secret,
            150
        );

        $templateContent = isys_application::instance()->container->get('template')
            ->activate_editmode()
            ->assign('tfa_secret', $secret)
            ->assign('tfa_qrcode', $qrCodeDataUri)
            ->smarty_tom_add_rules('tom.popup.tfa', $rules)
            ->fetch(isys_module_user_settings::getPath() . 'templates/popup/tfa_activate.tpl');

        return new Response($templateContent);
    }

    /**
     * @param Request $request
     *
     * @return Response
     */
    public function deactivate(Request $request): Response
    {
        try {
            if (!$this->tfa->isActive()) {
                throw new Exception('TFA for user is not active and will be skipped!');
            }

            if (!$this->tfa->checkCode($request->get('code'))) {
                throw new Exception($this->language->get('LC__USER_SETTINGS__TFA__CODE_INVALID'));
            }

            $this->tfa->deactivateTfa();

            return new JsonResponse([
                'success' => true,
                'data'    => null,
                'message' => 'TFA was successfully deactivated for user!',
            ]);
        } catch (Throwable $e) {
            return new JsonResponse([
                'success' => false,
                'data'    => null,
                'message' => $e->getMessage(),
            ]);
        }
    }

    /**
     * @return Response
     * @throws Exception
     */
    public function deactivationModal(): Response
    {
        $rules = [
            'tfa_code' => [
                'extra-params' => ['autocomplete' => 'off'],
                'disableInputGroup' => true,
                'p_strClass' => 'input-block',
                'p_bInfoIconSpacer' => 0,
                'p_strPlaceholder' => 'LC__USER_SETTINGS__TFA__PLACEHOLDER'
            ]
        ];

        $templateContent = isys_application::instance()->container->get('template')
            ->activate_editmode()
            ->smarty_tom_add_rules('tom.popup.tfa', $rules)
            ->fetch(isys_module_user_settings::getPath() . 'templates/popup/tfa_deactivate.tpl');

        return new Response($templateContent);
    }

    /**
     * @param int $userId
     *
     * @return JsonResponse
     */
    public function deactivateForUser(int $userId): JsonResponse
    {
        try {
            if (!ModuleSystem::getAuth()->is_allowed_to(isys_auth::SUPERVISOR, 'tfa-management')) {
                throw new Exception('You are not allowed to manage two-factor-authentication system!');
            }

            $this->tfa->deactivateTfaForUser($userId);

            return new JsonResponse([
                'success' => true,
                'data'    => null,
                'message' => '2-factor authentication successfully deactivated.'
            ]);
        } catch (Throwable $e) {
            return new JsonResponse([
                'success' => false,
                'data'    => null,
                'message' => $e->getMessage()
            ]);
        }
    }

    /**
     * @param Request $request
     *
     * @return Response
     * @throws Exception
     */
    public function deactivationModalForUser(Request $request): Response
    {
        $userId = (int)$request->query->get('userId');
        $db = isys_application::instance()->container->get('database');
        $userData = \isys_cmdb_dao_category_s_person_master::instance($db)->get_data(null, $userId)->get_row();

        $templateContent = isys_application::instance()->container->get('template')
            ->assign('username', $userData['isys_cats_person_list__title'])
            ->assign('userId', $userId)
            ->fetch(isys_module_user_settings::getPath() . 'templates/popup/tfa_management_deactivate.tpl');

        return new Response($templateContent);
    }

    /**
     * @param Request $request
     *
     * @return JsonResponse
     */
    public function verify(Request $request): JsonResponse
    {
        try {
            if (!$this->tfa->checkCode($request->get('code'))) {
                throw new Exception('Authentication code was invalid!');
            }

            $this->tfa->setVerified();

            return new JsonResponse([
                'success' => true,
                'data'    => null,
                'message' => 'Authentication code was valid!'
            ]);
        } catch (Throwable $e) {
            return new JsonResponse([
                'success' => false,
                'data'    => null,
                'message' => $e->getMessage()
            ], Response::HTTP_FORBIDDEN);
        }
    }
}
