<?php

namespace idoit\Module\UserSettings\Controller;

use Exception;
use idoit\Component\PasswordReset\PasswordResetService;
use isys_application;
use isys_component_template;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

/**
 * Password reset controller.
 *
 * @package   Modules
 * @copyright synetics GmbH
 * @license   http://www.i-doit.com/license
 */
class PasswordResetController
{
    private isys_component_template $template;
    private string $templatePath;

    /**
     * @throws Exception
     */
    public function __construct()
    {
        $this->template = isys_application::instance()->container->get('template');
        $this->templatePath = \isys_module_user_settings::getPath() . '/templates/integration/password-reset/';
        /** @var PasswordResetService passwordService */
        $this->passwordService = isys_application::instance()->container->get('reset_password');
        $this->template
            ->assign('www_path', isys_application::instance()->www_path)
            ->assign('assets_dir', \isys_module_user_settings::getWwwPath() . '/assets/');
    }

    /**
     * @param Request $request
     *
     * @return Response
     */
    public function resetPasswordScreen(Request $request): Response
    {
        try {
            $templateContent = $this->template
                ->assign('isExpired', $request->query->get('expired'))
                ->fetch("{$this->templatePath}1-request-password-form.tpl");
        } catch (\Throwable $e) {
            return $this->showError($request, $e);
        }

        return new Response($templateContent);
    }

    /**
     * @param Request $request
     *
     * @return Response
     */
    public function sendResetPasswordRequest(Request $request): Response
    {
        $emailAddress = $request->request->get('email');
        $emailValid = $emailAddress !== null && filter_var($emailAddress, FILTER_VALIDATE_EMAIL) !== false;

        if (!$emailValid) {
            $templateContent = $this->template
                ->assign('emailInvalid', true)
                ->assign('email', $emailAddress)
                ->fetch("{$this->templatePath}1-request-password-form.tpl");

            return new Response($templateContent);
        }

        try {
            $this->passwordService->requestForgottenPassword($emailAddress);

            $templateContent = $this->template
                ->fetch("{$this->templatePath}2-request-password-success.tpl");
        } catch (\Throwable $e) {
            return $this->showError($request, $e);
        }

        return new Response($templateContent);
    }

    /**
     * @param Request $request
     *
     * @return Response
     */
    public function setNewPasswordScreen(Request $request): Response
    {
        try {
            $token = $request->query->get('token');

            if (!$token || !$this->passwordService->tokenExists($token)) {
                return new RedirectResponse('forgot-password?expired=true');
            }
            $templateContent = $this->template
                ->fetch("{$this->templatePath}3-set-new-password.tpl");

            return new Response($templateContent);
        } catch (\Throwable $e) {
            return $this->showError($request, $e);
        }
    }

    /**
     * @param Request $request
     *
     * @return Response
     */
    public function setNewPassword(Request $request): Response
    {
        try {
            $token = $request->query->get('token');

            if (!$token || !$this->passwordService->tokenExists($token)) {
                return new RedirectResponse('forgot-password?expired=true');
            }

            $password = $request->request->get('password');
            $passwordRepeat = $request->request->get('passwordRepeat');
            $this->template->assign('password', $password)
                ->assign('passwordRepeat', $passwordRepeat);
            if (empty($password)) {
                $templateContent = $this->template
                    ->assign('passwordInvalid', true)
                    ->assign('passwordError', 'Please provide a valid password.')
                    ->fetch("{$this->templatePath}3-set-new-password.tpl");

                return new Response($templateContent);
            }

            if (empty($passwordRepeat)) {
                $templateContent = $this->template
                    ->assign('passwordRepeatInvalid', true)
                    ->assign('passwordRepeatError', 'Please repeat the password.')
                    ->fetch("{$this->templatePath}3-set-new-password.tpl");

                return new Response($templateContent);
            }

            if ($password !== $passwordRepeat) {
                $templateContent = $this->template
                    ->assign('passwordRepeatInvalid', true)
                    ->assign('passwordRepeatError', 'Passwords do not match.')
                    ->fetch("{$this->templatePath}3-set-new-password.tpl");

                return new Response($templateContent);
            }

            if (!$this->passwordService->hasPasswordCorrectLength($password)) {
                $templateContent = $this->template
                    ->assign('passwordInvalid', true)
                    ->assign('passwordRepeatInvalid', true)
                    ->assign('passwordError', 'Password must be between 8 and 64 characters.')
                    ->assign('passwordRepeatError', 'Password must be between 8 and 64 characters.')
                    ->fetch("{$this->templatePath}3-set-new-password.tpl");
                return new Response($templateContent);
            }

            if (!$this->passwordService->hasPasswordCorrectDisposition($password)) {
                $templateContent = $this->template
                    ->assign('passwordInvalid', true)
                    ->assign('passwordRepeatInvalid', true)
                    ->assign('passwordError', 'Password must include at least one lower- and uppercase character and at least one number.')
                    ->assign('passwordRepeatError', 'Password must include at least one lower- and uppercase character and at least one number.')
                    ->fetch("{$this->templatePath}3-set-new-password.tpl");
                return new Response($templateContent);
            }

            if ($this->passwordService->resetPassword($token, $password)) {
                $templateContent = $this->template->fetch("{$this->templatePath}4-password-reset-success.tpl");

                return new Response($templateContent);
            }

            return $this->showError($request, new \Exception('Unable to reset password.'));
        } catch (\Throwable $e) {
            return $this->showError($request, $e);
        }
    }

    /**
     * @param Request $request
     *
     * @return Response
     */
    public function showError(Request $request, \Throwable $exception): Response
    {
        $templateContent = $this->template
            ->fetch("{$this->templatePath}main.tpl");

        return new Response($templateContent);
    }

    /**
     * @param Request $request
     *
     * @return Response
     */
    public function showSessionActiveError(Request $request): Response
    {
        $templateContent = $this->template
            ->fetch("{$this->templatePath}error-active-session.tpl");

        return new Response($templateContent);
    }
}
