package app.controller;

import app.config.SiteSecDBData;
import app.model.CredentialData;
import app.model.Users;
import app.repository.UsersRepository;
import app.service.UsersEmailsService;

import ca.tecreations.db.mysql.MySQL;
import ca.tecreations.misc.TString;

import jakarta.validation.Valid; // "F:\projects\security1\jars\jakarta.validation-api-3.0.2.jar"
import java.util.List;
import java.util.Optional;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.ui.Model;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.validation.BindingResult; // "F:\projects\security1\jars\spring-context-6.2.1.jar"
import org.springframework.validation.Errors; // "F:\projects\security1\jars\spring-context-6.2.1.jar"
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute; // "F:\projects\security1\jars\spring-web-6.2.1.jar"
import org.springframework.web.bind.annotation.PostMapping; // "F:\projects\security1\jars\spring-web-6.2.1.jar"
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;

@RestController
public class PasswordController {
    public boolean debug = true;
    
    @Autowired
    UsersEmailsService ues;
    
    @Autowired
    public UsersRepository usersRepository;
    
    @Autowired
    DriverManagerDataSource dataSource;
     
    @Autowired
    SiteSecDBData data;
     
    @Autowired
    public PasswordEncoder passwordEncoder;

    @GetMapping("/account/change_pass")
    public ModelAndView changePassLinkGET() {
        CredentialData data = new CredentialData();
        ModelAndView mv = new ModelAndView("account/change_pass");
        mv.addObject("credential", data);
        return mv;
    }
     
    @PostMapping("/account/change_pass")
    public ModelAndView changePassLinkPOST(@Valid @ModelAttribute("credential") CredentialData credentialData, 
            BindingResult result, 
            Model model,
            Errors errors) 
    throws Exception {

        ModelAndView mv = new ModelAndView("account/change_pass");
        mv.addObject("credential", credentialData);
        if (!credentialData.getPassword().equals(credentialData.getConfirmation())) {
            result.rejectValue("confirmation", "mismatch", "Password and confirmation do not match.");
        } else {
            String email = credentialData.getEmail();
            MySQL mysql = new MySQL(dataSource);
            
            String uid = mysql.getValue("SELECT uid FROM users WHERE email='" + email + "' LIMIT 1",false);
            if (uid == null) {
                uid = mysql.getValue("SELECT uid FROM emails WHERE email='" + email + "' LIMIT 1");
            }
            if (uid != null) {
                String sql = "UPDATE users SET password='" + passwordEncoder.encode(credentialData.getPassword()) + "' " +
                             "WHERE uid='" + uid + "'";
                mysql.issue(sql);
                mv.addObject("message", "Password changed.");
            }
        } 
        return mv;
    }
    

    
    
    @GetMapping("/request_reset_pass_link")
    public ModelAndView requestResetPassLinkGET() {
        return new ModelAndView("account/start_pass_reset");
    }
     
    @PostMapping("/request_reset_pass_link")
    public ModelAndView requestResetPassLinkPOST(@RequestParam String email) {
        MySQL mysql = new MySQL(dataSource);
        String uid = mysql.getValue("SELECT uid FROM users WHERE email='" + email + "'");
        Optional<Users> data = usersRepository.findByEmail(email);
        if (data.isPresent()) {
            Users user = data.get();
            TString code = new TString(TString.BIG_ALPHA_NUM,32);
            ues.addResetPassword(user.getUID().toString(),code.toString());
            ues.sendResetPassword(user);
        }
        ModelAndView mv = new ModelAndView("account/start_pass_reset");
        mv.addObject("message", "Password reset link sent.");
        return mv;
    }
    
    
    @GetMapping("/reset_pass")
    public ModelAndView resetPassGET(@RequestParam String code) 
    throws Exception {
        System.out.println("\nResetPassword.getParams\n");
        MySQL mysql = new MySQL(dataSource);
        CredentialData data = new CredentialData();
        String uid = mysql.getValue("SELECT uid FROM account_ops WHERE txt='" + code + "'");
        data.setEmail(mysql.getValue("SELECT email FROM users WHERE uid='" + uid + "'"));
        ModelAndView mv = new ModelAndView("account/pass_reset");
        mv.addObject("reset", data);
        return mv;
    }
    
    @PostMapping("/reset_pass")
    public ModelAndView resetPassPOST(
            @Valid @ModelAttribute("reset") CredentialData reset, 
            BindingResult result, 
            Model model,
            Errors errors) 
    throws Exception {
        String email = reset.getEmail();
        MySQL mysql = new MySQL(dataSource);
        ModelAndView mv = new ModelAndView("account/pass_reset");
        if (!reset.getPassword().equals(reset.getConfirmation())) {
            result.rejectValue("confirmation", "mismatch", "Password and confirmation do not match.");
        } else if (!errors.hasErrors()) {
            String sql = "UPDATE users SET password='" +
                         passwordEncoder.encode(reset.getPassword()) + 
                         "' WHERE email='" + email + "'";
            mysql.issue(sql,data.debug);
            String uid = mysql.getValue("SELECT uid FROM users WHERE email='" + email + "'");
            mysql.issue("DELETE FROM account_ops WHERE uid='" + uid + "' AND op='PASSWORD_RESET'",data.debug);
            // redirectView to /login?pass_reset!
            mv = new ModelAndView("account/login");
            mv.addObject("message","Password Reset Completed.");
            mv.addObject("email",reset.getEmail());
        } else {
            mv.addObject("reset", reset);
             
        }
        return mv;  
    }
}
