<?php

namespace App\Controller;

use App\Form\LoginFormType;
use App\Form\PasswordChangeFormType;
use App\Form\PasswordResetFormType;
use App\Form\PasswordResetSetFormType;
use App\Form\RegistrationFormType;
use App\Model\DataObject\User;
use App\Service\MailManager;
use App\Service\UserManager;
use App\Tool\Utils;
use Pimcore\Logger;
use Pimcore\Model\DataObject\ClassDefinition\Data\Password;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormError;
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;

class UserController extends BaseController
{
	const PATH_LOGIN = '/prihlaseni';
	const PATH_ACCOUNT = '/ucet';

	/*						DOCUMENT ROUTED ACTIONS							*/

	/**
	 * @return Response
	 */
	public function loginAction(
		AuthenticationUtils $authenticationUtils,
		MailManager $mailManager,
		Request $request,
		UserManager $userManager
	) {
		// set login error msg
		$lastAuthError = $authenticationUtils->getLastAuthenticationError();
		if (null !== $lastAuthError) {
			$this->addErrorMsg($this->translate('msg_authentication_error'), true);
		}
		// pre-set login form data
		$defaultLoginFormData = [
			'email' => $authenticationUtils->getLastUsername(),
			'target' => $this->docUrl(self::PATH_ACCOUNT),
		];
		// login form submission is handled by symfony's security system
		// via the registered /login-check route (it's pure magic ;)
		$loginForm = $this->createForm(LoginFormType::class, $defaultLoginFormData, ['action' => '/login-check']);

		$registrationForm = $this->createForm(RegistrationFormType::class);
		$registrationForm->handleRequest($request);
		if ($registrationForm->isSubmitted()) {
			if ($this->handleRegistrationForm($registrationForm, $userManager)) {
				return $this->gotoUrl($this->docUrl(self::PATH_LOGIN));
			}
		}

		$passwordResetForm = $this->createForm(PasswordResetFormType::class);
		$passwordResetForm->handleRequest($request);
		if ($passwordResetForm->isSubmitted()) {
			if ($this->handlePasswordResetForm($passwordResetForm, $mailManager)) {
				return $this->gotoUrl($this->docUrl(self::PATH_LOGIN));
			}
		}

		return $this->render('user/login.html.twig', [
			'loginForm' => $loginForm->createView(),
			'registrationForm' => $registrationForm->createView(),
			'passwordResetForm' => $passwordResetForm->createView()
		]);
	}

	/**
	 * @return Response
	 */
	public function accountAction()
	{
		$authCheckResponse = $this->checkAuth();
		if (null !== $authCheckResponse) {
			return $authCheckResponse;
		}

		return $this->render('user/account.html.twig');
	}

	/**
	 * @param Request $request
	 *
	 * @return Response
	 */
	public function changePasswordAction(Request $request)
	{
		$authCheckResponse = $this->checkAuth();
		if (null !== $authCheckResponse) {
			return $authCheckResponse;
		}

		$passwordChangeForm = $this->createForm(PasswordChangeFormType::class);
		$passwordChangeForm->handleRequest($request);
		if ($passwordChangeForm->isSubmitted()) {
			if ($this->handlePasswordChangeForm($passwordChangeForm)) {
				return $this->gotoUrl($this->docUrl(self::PATH_ACCOUNT));
			}
		}

		return $this->render('user/changePassword.html.twig', [
			'passwordChangeForm' => $passwordChangeForm->createView()
		]);
	}

	/**
	 * @param Request $request
	 *
	 * @return Response
	 */
	public function profileAction(Request $request)
	{
		$authCheckResponse = $this->checkAuth();
		if (null !== $authCheckResponse) {
			return $authCheckResponse;
		}

		$user = $this->getCurrentUser();

		$registrationForm = $this->createForm(
			RegistrationFormType::class,
			$user,
			['forProfile' => true]
		);

		$registrationForm->handleRequest($request);
		if ($registrationForm->isSubmitted()) {
			if ($this->handleProfileForm($registrationForm)) {
				return $this->gotoUrl($this->docUrl('/ucet/profil'));
			}
		}

		return $this->render('user/profile.html.twig', [
			'profileForm' => $registrationForm->createView()
		]);
	}

	/*						STATIC-ROUTE ROUTED ACTIONS						*/

	/**
	 * #[Route("/login-check")]
	 *
	 * @return Response
	 */
	public function loginCheckAction()
	{
		return $this->render('user/login.html.twig');
	}

	/**
	 * #[Route("/logout")]
	 *
	 * @return Response
	 */
	public function logoutAction()
	{
		return $this->render('user/logout.html.twig');
	}

	/**
	 * @param Request $request
	 * @param string  $token
	 *
	 * @return Response
	 */
	public function passwordResetAction(Request $request, $token)
	{
		/* @var $user User */
		$user = User::getByPasswordResetToken($token, ['limit' => 1, 'unpublished' => true]);
		if (null === $user) {
			$this->addErrorMsg($this->translate('msg_invalid_token'));

			return $this->gotoUrl($this->docUrl(self::PATH_LOGIN));
		}

		$passwordResetSetForm = $this->createForm(PasswordResetSetFormType::class, [
			'token' => $token,
		]);
		$passwordResetSetForm->handleRequest($request);
		if ($passwordResetSetForm->isSubmitted()) {
			if ($this->handlePasswordResetSetForm($passwordResetSetForm)) {
				return $this->gotoUrl($this->docUrl(self::PATH_LOGIN));
			}
		}

		return $this->render('user/passwordReset.html.twig', [
			'passwordResetSetForm' => $passwordResetSetForm->createView()
		]);
	}

	/*				VIEW-LESS ACTIONS (ALLWAYS REDIRECT)					*/

	/**
	 * @param string $code
	 *
	 * @return response
	 */
	public function activationAction($code)
	{
		/* @var $user User */
		$user = User::getByActivationCode($code, ['limit' => 1, 'unpublished' => true]);
		if (null !== $user) {
			try {
				$user->setPublished(true);
				$user->save();
				$this->addSuccessMsg(sprintf($this->translate('msg_account_activated'), $user->getEmail()));
			} catch (\Exception $e) {
				Logger::error('ACCOUNT ACTIVATION - '.$e->getMessage()."\n".$e->getTraceAsString());
				$this->addErrorMsg($this->translate('msg_unknown_error'));
			}
		} else {
			$this->addErrorMsg($this->translate('msg_activation_code_invalid'));
		}

		return $this->gotoUrl($this->docUrl(self::PATH_LOGIN));
	}

	/*							FORM HANDLERS								*/

	/**
	 * @param FormInterface $form
	 * @param UserManager   $userManager
	 *
	 * @return bool
	 */
	private function handleRegistrationForm(FormInterface $form, UserManager $userManager)
	{
		if ($form->isValid()) {
			$data = $form->getData();
			$data['lang'] = $this->language;

			/* @var $user User */
			$user = User::getByEmail($data['email'], ['limit' => 1, 'unpublished' => true]);
			if (null !== $user) {
				$form['email']->addError(new FormError('msg_email_registered')); // this does a double translation (TODO...)
				$this->addErrorMsg($this->translate('msg_form_invalid'), true);

				return false;
			}

			$result = $userManager->createUser($data);

			if ($result) {
				$this->addSuccessMsg(sprintf($this->translate('msg_registration_successfull'), $data['email']));
			}

			return $result;
		} else {
			$this->addErrorMsg($this->translate('msg_form_invalid'));
		}

		return false;
	}

	/**
	 * @param FormInterface $form
	 * @param MailManager   $mailManager
	 *
	 * @return bool
	 */
	private function handlePasswordResetForm(FormInterface $form, MailManager $mailManager)
	{
		if ($form->isValid()) {
			$data = $form->getData();

			/* @var $user User */
			$user = User::getByEmail($data['email'], ['limit' => 1, 'unpublished' => true]);
			if (null === $user) {
				$form['email']->addError(new FormError(sprintf($this->translate('msg_email_not_registered'), $data['email']))); // TODO

				return false;
			}

			$token = strtolower(md5(uniqid()));

			try {
				$user->setPasswordResetToken($token);
				$user->save();
				$mailManager->sendMail('/notifikace/reset-hesla', $this->language, $data['email'], null, [
					'link' => $this->getRequest()->getSchemeAndHttpHost().Utils::url('password-reset', [
						'token' => $token,
						'language' => $this->language,
					]),
					'user' => $user,
				]);
				$this->addSuccessMsg(sprintf($this->translate('msg_password_reset_successfull'), $data['email']));

				return true;
			} catch (\Exception $e) {
				Logger::error('PASSOWORD RESET FORM - '.$e->getMessage()."\n".$e->getTraceAsString());
				$this->addErrorMsg($this->translate('msg_unknown_error'));
			}
		} else {
			$this->addErrorMsg($this->translate('msg_form_invalid'));
		}

		return false;
	}

	/**
	 * @param FormInterface $form
	 *
	 * @return bool
	 */
	private function handlePasswordResetSetForm(FormInterface $form)
	{
		if ($form->isValid()) {
			$data = $form->getData();

			/* @var $user User */
			$user = User::getByPasswordResetToken($data['token'], ['limit' => 1, 'unpublished' => true]);
			if (null === $user) {
				$this->addErrorMsg($this->translate('msg_unknown_error'));

				return false;
			}

			try {
				$user->setPassword($data['password']);
				$user->setPasswordResetToken('');
				$user->save();
				$this->addSuccessMsg(sprintf($this->translate('msg_password_change_successfull')));

				return true;
			} catch (\Exception $e) {
				Logger::error('PASSOWORD RESET CHANGE FORM - '.$e->getMessage()."\n".$e->getTraceAsString());
				$this->addErrorMsg($this->translate('msg_unknown_error'));
			}
		} else {
			$this->addErrorMsg($this->translate('msg_form_invalid'));
		}

		return false;
	}

	/**
	 * @param FormInterface $form
	 *
	 * @return bool
	 */
	private function handlePasswordChangeForm(FormInterface $form)
	{
		if ($form->isValid()) {
			$data = $form->getData();

			$user = $this->getCurrentUser();

			/* @var $passwordField ClassDefinition\Data\Password */
			$passwordField = $user->getClass()->getFieldDefinition('password');
			if (!($passwordField instanceof Password) || false === $passwordField->verifyPassword($data['password_old'], $user, false)) {
				$form['password_old']->addError(new FormError('msg_wrong_old_password')); // this does a double translation (TODO...)
				$this->addErrorMsg($this->translate('msg_form_invalid'));

				return false;
			}

			try {
				$user->setPassword($data['password']);
				$user->save();
				$this->addSuccessMsg($this->translate('msg_password_change_successfull'));

				return true;
			} catch (\Exception $e) {
				Logger::error('PASSOWORD CHANGE FORM - '.$e->getMessage()."\n".$e->getTraceAsString());
				$this->addErrorMsg($this->translate('msg_unknown_error'));
			}
		} else {
			$this->addErrorMsg($this->translate('msg_form_invalid'));
		}

		return false;
	}

	/**
	 * @param FormInterface $form
	 *
	 * @return bool
	 */
	private function handleProfileForm(FormInterface $form)
	{
		if ($form->isValid()) {
			$data = $form->getData();

			$user = $this->getCurrentUser();
			$user->setValues($data);
			try {
				$user->save();
			} catch (\Exception $e) {
				Logger::error('PROFILE FORM - '.$e->getMessage()."\n".$e->getTraceAsString());
				$this->addErrorMsg($this->translate('msg_unknown_error'));
			}

			$this->addSuccessMsg($this->translate('msg_profile_changed'));

			return true;
		} else {
			$this->addErrorMsg($this->translate('msg_form_invalid'));
		}

		return false;
	}
}
