<?php

namespace App\Controller;

use App\Entity\PasswordToken;
use App\Form\NewPasswordType;
use App\Form\ResetPasswordType;
use App\Service\PasswordTokenService;
use App\Service\UserService;
use Cake\Chronos\Chronos;
use FOS\RestBundle\Controller\Annotations as Rest;
use FOS\RestBundle\Controller\FOSRestController;
use FOS\RestBundle\View\View;
use Lexik\Bundle\JWTAuthenticationBundle\Services\JWTTokenManagerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;

class ResetPasswordController extends FOSRestController
{
    private $userService;
    /**
     * @var PasswordTokenService
     */
    private $passwordTokenService;
    /**
     * @var UserPasswordEncoderInterface
     */
    private $encoder;
    /**
     * @var JWTTokenManagerInterface
     */
    private $JWTManager;

    public function __construct(UserService $userService, PasswordTokenService $passwordTokenService, UserPasswordEncoderInterface $encoder, JWTTokenManagerInterface $JWTManager)
    {
        $this->userService = $userService;
        $this->passwordTokenService = $passwordTokenService;
        $this->encoder = $encoder;
        $this->JWTManager = $JWTManager;
    }

    /**
     * Request password reset.
     *
     * @Rest\Post("/user/password/reset")
     *
     * @return View
     */
    public function postResetPassword(Request $request): View
    {
        $form = $this->createForm(ResetPasswordType::class);

        $form->submit($request->request->all());

        if ($form->isSubmitted() && $form->isValid()) {
            try {
                $user = $this->userService->getUserByEmail($request->get('email'));
            } catch (\Exception $e) {
                return View::create($form, Response::HTTP_BAD_REQUEST);
            }

            $this->passwordTokenService->deleteByUser($user);

            $passwordToken = (new PasswordToken())
                ->setUser($user)
                ->setExpiresAt(Chronos::create()->addDay(1)->toMutable())
                ->setType('RESET');

            $this->passwordTokenService->save($passwordToken);

            return View::create([], Response::HTTP_OK);
        }

        return View::create($form, Response::HTTP_BAD_REQUEST);
    }

    /**
     * Request new password.
     *
     * @Rest\Post("/user/password/confirm")
     *
     * @return View
     */
    public function postNewPassword(Request $request): View
    {
        $token = $request->get('token');

        try {
            /** @var PasswordToken $passwordToken */
            $passwordToken = $this->passwordTokenService->getByToken($token);
        } catch (\Exception $exception) {
            return View::create(['message' => $exception->getMessage()], Response::HTTP_BAD_REQUEST);
        }

        $form = $this->createForm(NewPasswordType::class);

        $form->submit($request->request->all());

        if ($form->isSubmitted() && $form->isValid()) {
            $user = $passwordToken->getUser();
            $user->setPlainPassword($form->getData()['newPassword']);
            $user->setPassword($this->encoder->encodePassword($user, $form->getData()['newPassword']));
            $this->userService->saveUser($user);

            $this->passwordTokenService->delete($passwordToken);

            $token = $this->JWTManager->create($user);

            return View::create(['token' => $token], Response::HTTP_OK);
        }

        return View::create($form, Response::HTTP_BAD_REQUEST);
    }
}
