package com.eactive.testmaster.login.controller;

import com.eactive.testmaster.common.exception.UserNotFoundException;
import com.eactive.testmaster.login.dto.PasswordResetDTO;
import com.eactive.testmaster.login.entity.Token;
import com.eactive.testmaster.login.service.TokenService;
import com.eactive.testmaster.user.service.UserService;
import java.time.LocalDateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.Validator;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;

/**
 * Created by Sungpil Hyun
 */
@Controller
@ConditionalOnProperty(name = "password.reset.enabled", havingValue = "true")
public class PasswordResetController {

    public static final String RESET_PASSWORD = "page/resetPassword";
    public static final String FORGOT_PASSWORD = "page/forgotPassword";
    @Autowired
    private UserService userService;

    @Autowired
    private TokenService tokenService;

    @Autowired
    private Validator validator;


    @GetMapping(value = "/forgot_password.do")
    public String forgotPasswordView() {
        return FORGOT_PASSWORD;
    }

    /**
     * 비밀번호 초기화 링크를 생성한다.
     *
     * @param email
     * @param model
     * @return
     */
    @PostMapping(value = "/forgot_password.do")
    public String requestPasswordReset(@RequestParam(value = "email", defaultValue = "0") String email,
                                       Model model) {
        try {
            userService.requestPasswordReset(email);
        } catch (UserNotFoundException e) {
            model.addAttribute("error", "존재하지 않는 이메일입니다.");
            return FORGOT_PASSWORD;
        } catch (Exception e) {
            model.addAttribute("error", "비밀번호 초기화 요청에 실패하였습니다.");
            return FORGOT_PASSWORD;
        }

        return "redirect:/forgot_password.do?success";
    }

    @GetMapping("/reset_password.do")
    public String resetPasswordView(@RequestParam(value = "token", defaultValue = "0") String tokenValue,
                                    Model model) {
        Token token = tokenService.findByToken(tokenValue);

        if (token == null || token.getExpiresAt().isBefore(LocalDateTime.now())) {
            return "redirect:/forgot_password.do?expired";
        }

        model.addAttribute("tokenValue", tokenValue);
        model.addAttribute("passwordReset", new PasswordResetDTO());
        return RESET_PASSWORD;
    }

    @PostMapping("/reset_password.do")
    @Transactional
    public String resetPassword(@ModelAttribute("passwordResetRequest") PasswordResetDTO passwordReset,
                                BindingResult bindingResult,
                                Model model) {

        Token token = tokenService.findByToken(passwordReset.getToken());

        if (token == null || token.getExpiresAt().isBefore(LocalDateTime.now())) {
            return "redirect:/forgot_password.do?expired";
        }

        validator.validate(passwordReset, bindingResult);

        if (bindingResult.hasErrors()) {
            model.addAttribute("tokenValue", passwordReset.getToken());
            model.addAttribute("passwordReset", passwordReset);
            return RESET_PASSWORD;
        }

        userService.resetPassword(token.getEmail(), passwordReset.getPassword());

        tokenService.deleteToken(token);

        return "redirect:/login";
    }
}
