package com.dacrt.SBIABackend.security.service;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;

import java.util.Set;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
import java.util.Optional;
import java.util.Properties;

import javax.mail.Message;
import javax.mail.Message.RecipientType;
import javax.mail.MessagingException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.net.ssl.TrustManager;
import javax.persistence.Column;
import javax.transaction.Transactional;
import javax.validation.constraints.NotNull;
import javax.net.ssl.*;
import java.security.cert.X509Certificate;
import java.text.Normalizer;
import java.security.NoSuchAlgorithmException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.KeyManagementException;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.dao.DataAccessException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.lang.NonNull;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;

import com.dacrt.SBIABackend.dto.Mensaje;
import com.dacrt.SBIABackend.security.dto.AuditRequestDto;
import com.dacrt.SBIABackend.security.dto.RespuestaMsgDto;
import com.dacrt.SBIABackend.security.entity.Users;
import com.dacrt.SBIABackend.security.entity.Audit;
import com.dacrt.SBIABackend.security.entity.Params;
import com.dacrt.SBIABackend.security.repository.UsersRepository;
import com.dacrt.SBIABackend.security.repository.AuditRepository;
import com.dacrt.SBIABackend.security.repository.ParamsRepository;
import com.dacrt.SBIABackend.security.repository.RolesRepository;

@Service
@Transactional
public class UsersService {
	Logger logger = LoggerFactory.getLogger(UsersService.class);

	@Autowired
	UsersRepository usersRepository;
	
	@Autowired
	AuditRepository auditRepository;
	
	@Autowired
	RolesRepository rolesRepository;
	
	@Autowired
	ParamsRepository paramsRepository;
	
	/*@Autowired
	private UsuarioSesionRepository usuarioSesionRepository;*/
	
	@Autowired
	PasswordEncoder passworEncoder;
	
	//@Autowired
 	//private JavaMailSender javaMailSender;
	
	@Autowired 
	private JavaMailSender mailSender;
	
	@Value("$(spring.mail.username)")
	private String fromEmailId;
	
	@Value("${spring.mail.port}")
	private String puerto;
	
	@Value("${spring.mail.host}")
	private String hostemail;
		
	@Value("${spring.mail.username}")
	private String usersemail;
	
	@Value("${spring.mail.password}")
	private String pwdemail;
	
	@Value("${spring.mail.protocol}")
	private String protocolo;
	
	@Value("${spring.mail.properties.mail.smtp.auth}")
	private String auth;
	
	@Value("${spring.mail.properties.mail.smtp.starttls.enabled}")
	private String starttls;
	
	
	
	
	
	
	java.util.Date fechaActual = new java.util.Date();
	
	/*public void sendEmail(String recipient,String body,String subject) throws NoSuchAlgorithmException, KeyManagementException {
		
		//fromEmailId = "ggcncodetest@gmail.com";
		
		
		JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
		try {
		mailSender.setHost(hostemail);
		//puerto = (int) puerto;
		//int puertoint = Integer.parseInt(puerto);
		mailSender.setPort(587);
		mailSender.setUsername(usersemail);
		mailSender.setPassword(pwdemail);
		
		MimeMessage message = mailSender.createMimeMessage();
		message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(recipient));
		message.setContent(body, "text/html; charset=utf-8");
		
		
		Properties props = mailSender.getJavaMailProperties();
		props.put("mail.transport.protocol",protocolo);
		props.put("mail.smtp.auth", auth);
		props.put("mail.smtp.starttls.enabled", starttls); // Habilita STARTTLS
		props.put("mail.smtp.starttls.required", starttls);
		props.put("mail.debug", starttls);
		props.put("mail.smtp.ssl.trust", hostemail); //add this line
		//spring.mail.properties.mail.smtp.starttls.required=true
		
		
		TrustManager[] trustAllCerts = new TrustManager[] {
                new X509TrustManager() {
                    public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                        return null;
                    }
                    public void checkClientTrusted(X509Certificate[] certs, String authType) {
                    }
                    public void checkServerTrusted(X509Certificate[] certs, String authType) {
                    }
                }
        };
		
		    SSLContext sslContext = SSLContext.getInstance("TLS");
	        sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
	        SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
	        mailSender.send(message);
	//	props.put(&quot;mail.debug&quot;, &quot;true&quot;); // Para depuración

		 } 
		 catch (MessagingException e) {
	            // Manejar excepciones
	            e.printStackTrace();
	        }
		
	}*/
	

public void sendEmail(String recipient,String body,String subject)  {
		
		
		SimpleMailMessage simpleMailMessage= new SimpleMailMessage();
		 //JavaMailSender mailSender;
		 try {
		MimeMessage message = mailSender.createMimeMessage();
		message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(recipient));
		message.setContent(body, "text/html; charset=utf-8");
		message.setSubject(subject);
		message.setFrom(new InternetAddress(usersemail));
	        
		mailSender.send(message);
		 } 
		 catch (MessagingException e) {
	            // Manejar excepciones
	            e.printStackTrace();
	        }
		
	}

	public Optional<Users> getByUsr(String usr){
		return usersRepository.findByUsr(usr);
	}
	
	public Optional<Users> getByEmail(String email){
		return usersRepository.findByEmail(email);
	}
	
	public boolean existsByUsr(String usr) {
		return usersRepository.existsByUsr(usr);
	}
	
	public boolean existsByEmail(String email) {
		return usersRepository.existsByEmail(email);
	}
	
	public Users getUsersByid(Integer id) {
		Users tipoUsers = usersRepository.findById(id).orElseThrow(() ->
          		new IllegalArgumentException("No se encontro el parametro con id: " + id));
 		 return tipoUsers;
 	}
 	
	
	public boolean existsById(Integer id) {
		return usersRepository.existsById(id);
	}
	
	public void save(Users usr) {
		usersRepository.save(usr);
	}
	

	
	public Users getUsr(Integer id) {
		Users usr = usersRepository.findById(id).orElseThrow(() ->
        new IllegalArgumentException(
                "Usuario con id: " + id + " no puede ser encontrado"));
		return usr;
	}
	
	
	
	public String ArmarBodySendMailUser(String ruta,String usuario,String saludo,String url,String accion,String minlong,String cantMay,String cantMin,String cantSimbo,String simPermi) {
		
		String contenido = "";
		
	    contenido = String.format(""+
                 "<html> "+
	        		
                 "<body> "+  
	  	            "<div id='1' style='background-color: #F8F8F8;width: 875px;height: 550px;background-position-x: 320px; background-position-y: 240px;' > "+
                                   "<div style='margin:0 auto;text-align:center;background-color: #354856;width: 377px;height: 170px;background-position-x: 320px; background-position-y: 241px;'> "+ 
                                        "<img style='margin-top: 40px;width: 200px;height: 87px;' src='%s' alt='logo'> "+
                                   "</div> "+
                                   "<div style='border:1px solid #FFF;margin:0 auto;background-color: #FFFFFF;width: 377px;height: 377px;background-position-x: 596px; background-position-y: 404px;'> "+
                                         "<div id='2' > "+
                                            "<div style='font-weight:bold;margin:15px auto 5px auto; text-align:center;font-weight:bold;color: #152228;font-family: Arial, Helvetica, sans-serif;font-size: 18px;line-height: 22px;width: 266px;'> "+
                                               "Hola, <b>%s</b> "+
                                             "</div> "+
                                            "<div style='font-weight:bold;margin:12px auto 20px auto;width:380px;color: #4c4c4d;font-family: Roboto;font-size: 15px;letter-spacing: 0.22px;line-height: 16px;width: 266px;text-align:center;'> "+
                                               " %s" +
                                            "</div> "+
                                          "</div> "+                                          
                                          "<div style='text-align:center;padding: 10px;'> "+
                                           "<a style='background-color: #EA8B1D;border-radius: 9px;text-align:center;padding: 9px 86px;font-family: Arial, Helvetica, sans-serif;text-transform: uppercase;color:#fff;' href='%s'><b> %s </b></a> "+
                                          "</div> "+
	   	                            "<div style='background-color: #f5f3f3;border-radius: 6px;width: 266px;height: 170px;background-position-x: 625px; background-position-y: 585px;margin:10px auto 0 auto;'> "+
                                  "<div id='2' style='padding:10px;color: #828386;font-family: Roboto;font-size: 14px;line-height: 15px;  width: 244px;text-align: left;'> "+
                                  "<div style='font-weight:bold;margin-bottom:7px;color: #828386;font-family: Roboto;font-size: 12px;line-height: 14px;width: 244px;text-align: left;'>Le recordamos que la contraseña debe cumplir con los siguientes requerimientos:</div> "+
                                  "<div style='font-weight:bold;color: #828386;font-family: Roboto;font-size: 12px;line-height: 15px;width: 244px;text-align: left;padding:3px 0;'> &#10004; Longitud Mínima: %s </div> "+
                                  "<div style='font-weight:bold;color: #828386;font-family: Roboto;font-size: 12px;line-height: 15px;width: 244px;text-align: left;padding:3px 0;'> &#10004; Cantidad de Mayúsculas: %s </div> "+
                                  "<div style='font-weight:bold;color: #828386;font-family: Roboto;font-size: 12px;line-height: 15px;width: 244px;text-align: left;padding:3px 0;'> &#10004; Cantidad de Mínúsculas: %s </div> "+
                                  "<div style='font-weight:bold;color: #828386;font-family: Roboto;font-size: 12px;line-height: 15px;width: 244px;text-align: left;padding:3px 0;'> &#10004; Cantidad de Símbolos: %s </div> "+
                                  "<div style='font-weight:bold;color: #828386;font-family: Roboto;font-size: 12px;line-height: 15px;width: 244px;text-align: left;padding:3px 0;'> &#10004; Símbolos Permitidos: %s </div> "+
                                "</div> "+
                           "</div> "+
                       "</div> "+
                     "</div> "+
                  "</body> "+
             "</html>", ruta,usuario,saludo,url,accion,minlong,cantMay,cantMin,cantSimbo,simPermi);
	
		
	    return contenido;
		
	}
	
	public String eliminarAcentosService(String texto) {
	    // 1. Normalizar la cadena para separar los caracteres base de sus diacríticos
	    String normalized = Normalizer.normalize(texto, Normalizer.Form.NFD);

	    // 2. Usar una expresión regular para eliminar cualquier carácter que no sea una letra base ASCII
	   // Pattern pattern = Pattern.compile("[^\\p{ASCII}]");
	    Pattern pattern = Pattern.compile("\\p{InCombiningDiacriticalMarks}+");
	    return pattern.matcher(normalized).replaceAll("");
	}

	
	public String verificarCaracteresValidos(String texto) throws UnsupportedEncodingException {
	  
		 Optional<Params> deCarateresPerTextbox=paramsRepository.findByParamname("TEXTBOX_ALLOWED");
	     String caracterespermi=deCarateresPerTextbox.get().getValue();
	   String encoding2 = StandardCharsets.UTF_8.toString();
		String caracteresCodificados2 = URLEncoder.encode(caracterespermi, encoding2);
     String salida = "OK";
		 for (int i = 0; i < texto.length(); i++) {
			   
			   char currentChar = texto.charAt(i);
			  // String var = currentChar;
			   String var = String.valueOf(currentChar);
			   String VcurrentChar= URLEncoder.encode(var, encoding2);
	            // Verificar si el carácter no está en el conjunto de permitidos
			  // if (caracterespermi.indexOf(currentChar) == -1) {
				   if (caracterespermi.indexOf(var) == -1) {	   	             
	                salida = "NOOK";
					
	            }
	        }
		  return salida;     
	}
	
	
	public String verificarCaracteresValidosConRegex(String texto) {
	    // 1. Obtener la cadena de caracteres permitidos desde el repositorio.
	    // Manejo seguro del Optional. Se asume que el valor existe y no es nulo.
	    // Si no existe, lanza una excepción (dependiendo de la lógica de negocio, podrías usar un valor por defecto).
	    Optional<Params> deCarateresPerTextbox = paramsRepository.findByParamname("TEXTBOX_ALLOWED");
	    if (!deCarateresPerTextbox.isPresent()) {
	        // Manejo de error si la configuración no se encuentra
	        return "ERROR_CONFIGURACION_NO_ENCONTRADA"; 
	    }
	    
	    String caracterespermi = deCarateresPerTextbox.get().getValue();
	    
	    // 2. Escapar y construir el patrón de la expresión regular.
	    // a. Pattern.quote() escapa cualquier carácter especial de regex dentro de caracterespermi.
	    // b. Se encierra en corchetes negados: [^...] 
	    //    Esto significa: "coincide con CUALQUIER carácter que NO esté en esta lista".
	    String regex = "[^" + Pattern.quote(caracterespermi) + "]";
	    
	    // 3. Crear el objeto Pattern para optimizar la coincidencia.
	    Pattern patronNoPermitido = Pattern.compile(regex);
	    

	    // 4. Usar el Matcher para buscar la coincidencia.
	    // El método .find() devuelve true si encuentra AL MENOS UN carácter no permitido.
	    if (patronNoPermitido.matcher(texto).find()) {
	        return "NOOK"; // Se encontró un carácter no permitido.
	    } else {
	        return "OK";   // Todos los caracteres están permitidos.
	    }
	}
	public boolean consultarSesionEstatus(Integer id) {
		 boolean resp=false;
		 int resp1 = usersRepository.consultarSesionEstatus(id);
		// Optional<UsuarioSesion>  usuarioTo = usuarioSesionRepository.consultarSesionActiva(idUsuario);
		 //if(!usuarioTo.isEmpty())resp=true;
		// if(usuarioTo!=null)resp=true;
		// if(usuarioTo.size()>0)resp=true;
		 if(resp1==1) { 
			 resp=true;
		 } else {
			 resp=false;
		 }
	    return resp;
		
	}
	
	public Audit registrarAuditSesion(AuditRequestDto auditDto) {
		Audit auditTo =new Audit();
		auditTo.setIpaddr(auditDto.getIpaddr());;
		auditTo.setCreatedat(auditDto.getCreatedat());;
		auditTo.setModule(auditDto.getModule());;
		auditTo.setDsc(auditDto.getDesc());;
		auditTo.setUserref(auditDto.getUserref());;
		//auditTo.setFecha(AuditRequstDto.getFecha());
		//auditTo.setHoraI(AuditRequestDto.getHoraI());
		//logger.info("****registrarAuditoriaSesion 2 ****");
	    return auditRepository.save(auditTo);
		
	}
	
	public void asociarSessionidUsers(Integer id,String jwt,Date fechaDate,int fail,int idestatus) {
	    usersRepository.asociarSessionidydatos(id,jwt,fechaDate,fail,idestatus);
		
	}
	
	public void asociarSessionidUsersValid(Integer id,String jwt,Date fechaDate,int fail,int idestatus,Date validthru) {
	    usersRepository.asociarSessionidydatosvalid(id,jwt,fechaDate,fail,idestatus,validthru);
		
	}
	
	public Users addIdUsers(Users tipoUsers) {
		return usersRepository.save(tipoUsers);
		
	}
	
	/*public int registrarCerrarSesion(Integer idUsuario,Date fecha,Date horaF) {
	    return usuarioSesionRepository.registrarCerrarSesion(idUsuario,fecha,horaF);
		
	}*/
	
	
	/*public void borrarUnidades(Integer idUsuario) {
	     usersRepository.borraRelacionUnidadUsuario(idUsuario);
	}
	
	public void borrarRoles(Integer idUsuario) {
	     usersRepository.borraRelacionUsuarioRol(idUsuario);
	}*/

}
