package fr.eni.enchere.controllers;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.i18n.phonenumbers.NumberParseException;
import com.google.i18n.phonenumbers.PhoneNumberUtil;
import com.google.i18n.phonenumbers.Phonenumber;
import fr.eni.enchere.security.LoginService;
import org.springframework.beans.factory.annotation.Autowired;
import org.apache.commons.validator.routines.EmailValidator;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.validation.BindingResult;
import fr.eni.enchere.bll.UserService;
import fr.eni.enchere.bo.UserProfil;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.servlet.view.RedirectView;
import org.springframework.web.util.UriComponentsBuilder;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;

@Controller
@RequestMapping("/inscription")
public class InscriptionController {

    private final String API_URL = "https://apicarto.ign.fr/api/codes-postaux/communes/";

    @Autowired
    private final UserService userService;
    private LoginService loginService;
    private PasswordEncoder passwordEncoder;
    private EmailValidator emailValidator;
    private PhoneNumberUtil phoneValidator;

    public InscriptionController(UserService userService, PasswordEncoder passwordEncoder, EmailValidator emailValidator, PhoneNumberUtil phoneValidator, LoginService loginService) {
        this.userService = userService;
        this.passwordEncoder = passwordEncoder;
        this.emailValidator = emailValidator;
        this.phoneValidator = phoneValidator;
        this.loginService = loginService;
    }

    @GetMapping
    public String viewInscription(Model model) {
        // Vérifier si l'utilisateur est déjà authentifié
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (!authentication.getName().equals("anonymousUser")){
            return "redirect:/enchere";
        }
        model.addAttribute("userProfile", new UserProfil());
        return "inscription";
    }

    @PostMapping("/newUser")
    public String setUser(@ModelAttribute("userProfile") UserProfil userProfile, @RequestParam("confirmPassword") String confirmPassword, BindingResult result) {
        // Vérifier si le pseudo existe déjà
        List<String> allUsernames = userService.listPseudo();
        if (allUsernames.contains(userProfile.getPseudo())) {
            result.rejectValue("pseudo", "error.userProfile", "Ce pseudo est déjà utilisé.");
        }
        if (userProfile.getPseudo().isEmpty()){
            result.rejectValue("pseudo", "error.userProfile", "Entrer un pseudo.");
        }
        // Vérifier si l'e-mail existe déjà
        List<String> allEmails = userService.listEmail();
        if (allEmails.contains(userProfile.getEmail())) {
            result.rejectValue("email", "error.userProfile", "Cet e-mail est déjà utilisé.");
        }
        // vérifier si l'e-mail est valide
        if (!emailValidator.isValid(userProfile.getEmail())) {
            result.rejectValue("email", "error.userProfile", "L'adresse e-mail n'est pas valide.");
        }
        // vérifier si le numéro de téléphone est valide
        PhoneNumberUtil phoneNumberUtil = PhoneNumberUtil.getInstance();
        try {
            Phonenumber.PhoneNumber number = phoneNumberUtil.parse(userProfile.getTelephone(), "FR"); // Indiquez le code pays, ici FR pour la France
            phoneNumberUtil.isValidNumber(number);
        } catch (NumberParseException e) {
            result.rejectValue("telephone", "error.userProfile", "Le numéro de téléphone n'est pas valide.");
        }
        // vérification retrait
        //Vérification rue
        if (!Pattern.matches("^[a-zA-Z0-9 ]+$", userProfile.getRue())){
            result.rejectValue("rue", "error.userProfile", "Le rue n'est pas valide.");
        }
        if (userProfile.getRue().isEmpty()){
            result.rejectValue("rue", "error.userProfile", "Entrer une rue.");
        }
        //Vérifier code postal et ville
        if(Pattern.matches("^\\d{5}$", userProfile.getCode_postal())){
            //Récupérer les villes en fonction du code postal
            RestTemplate restTemplate = new RestTemplate();
            List<String> villeCodePostal = new ArrayList<>(); // Initialisez la liste pour éviter les NullPointerException
            String apiUrl = API_URL + userProfile.getCode_postal();
            ResponseEntity<JsonNode> response = restTemplate.getForEntity(apiUrl, JsonNode.class); // Désérialiser en JsonNode
            if (response.getStatusCode().is2xxSuccessful()) {
                JsonNode responseBody = response.getBody();
                if (responseBody.isArray()) { // Vérifiez si le corps de la réponse est un tableau JSON
                    for (JsonNode node : responseBody) {
                        String cityName = node.get("nomCommune").asText();
                        villeCodePostal.add(cityName);
                    }
                } else {
                    result.rejectValue("ville", "error.userProfile", "Une erreur est survenue !");
                }
                if (!villeCodePostal.contains(userProfile.getVille())) {
                    String showCity = String.join(", ", villeCodePostal);
                    result.rejectValue("ville", "error.userProfile", "Essayer : " + showCity);
                }
            } else {
                result.rejectValue("ville", "error.userProfile", "La ville n'est pas valide.");
            }
        } else {
            result.rejectValue("code_postal", "error.userProfile", "Le code postal n'est pas valide.");
        }
        // vérifier si les mot de passes sont identique
        if (!confirmPassword.equals(userProfile.getPassword())) {
            result.rejectValue("password", "error.userProfile", "Les mots de passe ne correspond pas.");
        }
        // Vérifier si le mot de passe est sécurisé
        String passwordRegex = "^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@?*#$%^&+=_!\\-])(?=\\S+$).{8,}$";
        Pattern pattern = Pattern.compile(passwordRegex);
        // Vérifier si le mot de passe correspond à l'expression régulière
        if (!pattern.matcher(userProfile.getPassword()).matches()){
            result.rejectValue("password", "error.userProfile", "Le mot de passe ne correspond pas aux critères de sécurité.");
        }
        // Si des erreurs de validation sont détectées, retourner à la page de création de compte
        if (result.hasErrors()) {
            return "inscription";
        }
        // Sinon, enregistrer l'utilisateur et rediriger vers la page de connexion
        userService.setUtilisateur(userProfile);
        return "redirect:/enchere";
    }
}
