package com.dacrt.SBIABackend.security.controler;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.regex.Pattern;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.servlet.http.HttpServletRequest;
import java.text.Normalizer;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.dacrt.SBIABackend.security.dto.AuditAllDto;
import com.dacrt.SBIABackend.security.dto.AuditAllResponseDto;
import com.dacrt.SBIABackend.security.dto.AuditDtoMod;
import com.dacrt.SBIABackend.security.dto.AuditModResponseDto;
import com.dacrt.SBIABackend.security.dto.AuditRequestDto;
import com.dacrt.SBIABackend.security.dto.EntrypointsDto;
import com.dacrt.SBIABackend.security.dto.MenuResponseDto;
import com.dacrt.SBIABackend.security.dto.RespuestaDto;
import com.dacrt.SBIABackend.security.dto.RespuestaMsgDto;
import com.dacrt.SBIABackend.security.dto.RespuestaValueDto;
import com.dacrt.SBIABackend.security.dto.UsersListDto;
import com.dacrt.SBIABackend.security.dto.PrivilegesDto;
import com.dacrt.SBIABackend.security.dto.ParamsDto;
import com.dacrt.SBIABackend.security.dto.ParamsResponseDto;
import com.dacrt.SBIABackend.security.entity.Audit;
import com.dacrt.SBIABackend.security.entity.Params;
import com.dacrt.SBIABackend.security.entity.Roles;
import com.dacrt.SBIABackend.security.entity.Users;
import com.dacrt.SBIABackend.security.repository.ParamsRepository;
import com.dacrt.SBIABackend.security.repository.UsersRepository;
import com.dacrt.SBIABackend.security.service.UsersService;
import com.dacrt.SBIABackend.security.service.MenuService;
import com.dacrt.SBIABackend.security.service.ParamsService;
import com.dacrt.SBIABackend.security.service.SecurityService;
import com.dacrt.SBIABackend.utils.HttpReqRespUtils;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.dacrt.SBIABackend.security.repository.AuditRepository;
import com.dacrt.SBIABackend.security.service.SecurityService;


@RestController
@RequestMapping("/system")
@CrossOrigin(origins = "*")
//@CrossOrigin(origins = "")
public class SystemController {
	
	@Autowired
	private ParamsRepository paramsRepository;
	
	@Autowired
	private UsersRepository usersRepository;
	
	@Autowired
	private AuditRepository auditRepository;
	
	@Autowired
	UsersService usersService;
	
	@Autowired
	ParamsService paramsService;
	
	@Autowired
	MenuService menuService;
	
	@Autowired
	SecurityService securityService;
	
	@Autowired
	private ObjectMapper objectMapper;
	
	@PersistenceContext
    private EntityManager entityManager;
	
	
	Logger logger = LoggerFactory.getLogger(SystemController.class);
	//@RequestBody final Users email
	
	//@GetMapping("/menus)
	//public ResponseEntity<MenuResponseDto> menu(@PathVariable final String sessionid) throws ParseException {
	//@PostMapping("/params")
	@PostMapping("/params/{parmid}")
	public ResponseEntity<ParamsResponseDto> paramsUpdate(HttpServletRequest request,@RequestBody ParamsDto tiposfiltros,@PathVariable("parmid") final Integer parmid) throws ParseException {
		
		
		RespuestaValueDto respuestaValueDto;
		RespuestaMsgDto respuesta = new RespuestaMsgDto("");
		HttpStatus estatus = HttpStatus.FORBIDDEN;
		ParamsResponseDto paramsResponseDto = new ParamsResponseDto();
		ParamsDto detalleParams;
		PrivilegesDto detallePrivilege;
	     List<ParamsDto> listasParams = new ArrayList<>();
	     List<PrivilegesDto> listasPrivelege = new ArrayList<>();
		 int idparametro = parmid;
		 int valor = idparametro;
		 String fechaComoCadena;
		 String sessionid = request.getHeader("Authorization");
		  Date fecha = new Date();
		    SimpleDateFormat  formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
	        String dataFormattata = formatter.format(fecha);
	        Date fechaDate = formatter.parse(dataFormattata);
	        AuditRequestDto  auditDto=new AuditRequestDto();
	       	        	     	       	       	  		
		   Date fecha2 = new Date();
		   Calendar calendar = Calendar.getInstance();
       
	
		 
			if (sessionid==null) {
				String var = "";
				boolean bloked = false;
				RespuestaMsgDto respuestaDto = new RespuestaMsgDto(var);
				//respuestaDto.setBlocked(bloked);
				respuestaDto.setMsg("Llamada al servicio malformado");
				//Error 400
				return new ResponseEntity(respuestaDto, HttpStatus.BAD_REQUEST);
			} else   {
				 
				   sessionid = sessionid.substring(7);
				   Optional<Users> encontreSessionUsuario =usersRepository.getBySessionid(sessionid);
				//   String usuarioIN = encontreSessionUsuario.get().getUsr();
				 //  int position = usuarioIN.indexOf('('); 
				   
				   if (encontreSessionUsuario.isPresent()) {
					   Date FechaReg = encontreSessionUsuario.get().getValidthru(); 

					   //fechaComoCadena  = securityService.consultarSessionActiva(FechaReg,fecha2);
					   fechaComoCadena  = securityService.consultarSessionActiva(FechaReg,fecha2,encontreSessionUsuario.get().getId());
					   
					   
					    if (fechaComoCadena=="") {
						   
						   
						   
						   String var = "";
							boolean bloked = false;
							RespuestaMsgDto respuestaDto = new RespuestaMsgDto(var);
							//respuestaDto.setBlocked(bloked);
							respuestaDto.setMsg("Sesión expirada o inválida"); 
							return new ResponseEntity(respuestaDto, HttpStatus.UNAUTHORIZED);
						   
					    }
					   
					   Roles roles = encontreSessionUsuario.get().getRolid();
					   int idrol = roles.getId();
					   int rolisvalid = auditRepository.getCantbyRolAndPrivi(idrol, 611);
					   
					   if (rolisvalid==0) {
						   
						   String var = "";
							boolean bloked = false;
							RespuestaMsgDto respuestaDto = new RespuestaMsgDto(var);
							//respuestaDto.setBlocked(bloked);
							respuestaDto.setMsg("No tiene los Privilegios"); 
							return new ResponseEntity(respuestaDto, HttpStatus.FORBIDDEN);
						   
					   }
					   
					  boolean existeParam =  paramsService.existsById(parmid);
				      
				      if (!existeParam) {
				    	    String var = "";
							boolean bloked = false;
							RespuestaMsgDto respuestaDto = new RespuestaMsgDto(var);
							//respuestaDto.setBlocked(bloked);
							respuestaDto.setMsg("Registro no encontrado"); 
							return new ResponseEntity(respuestaDto, HttpStatus.NOT_FOUND);
				    	  
				      } else
				      {
				    	  
				      
						  
						    //////////////////////////INSERCION BLOQUE DE AUDITORIA///////////////////
						     String module = "Parámetros";
						     Optional<Params> paraactualiza = paramsRepository.findById(parmid);
						     String Descmodule = "Se actualizó el parametro : " + paraactualiza.get().getParamname()  ;
						    
					         auditDto.setIpaddr(HttpReqRespUtils.getClientIpAddressIfServletRequestExist());			        
					         
					         String singo1 = "(";
					         String singo2 = ")";
					         String usryemail = encontreSessionUsuario.get().getUsr().concat(" ").concat(singo1).concat(encontreSessionUsuario.get().getEmail().concat(singo2));
					         auditDto.setUserref(usryemail);
					         auditDto.setModule(module);
					         auditDto.setDesc(Descmodule);
					         auditDto.setCreatedat(fechaDate);
					 		   usersService.registrarAuditSesion(auditDto); 
					 		  //////////////////////////INSERCION BLOQUE DE AUDITORIA///////////////////					   				
				      }
				 } else {
						String var = "";
						boolean bloked = false;
						RespuestaMsgDto respuestaDto = new RespuestaMsgDto(var);
						//respuestaDto.setBlocked(bloked);
						respuestaDto.setMsg("Sesión expirada o inválida");
						//Error 400
						return new ResponseEntity(respuestaDto, HttpStatus.UNAUTHORIZED);
				 }
			}
			
			
		
		try {
			Params tipoParams2;
			
			Params tipoParams = paramsService.getParamsByid(parmid);
			tipoParams.setValue(tiposfiltros.getValue());
			tipoParams.setGroup(tipoParams.getGroup());
			tipoParams.setInfo(tipoParams.getInfo());
		 	tipoParams.setModifiedat(fechaDate);
			tipoParams.setName(tipoParams.getName());
			tipoParams.setParamname(tipoParams.getParamname());
			tipoParams.setType(tipoParams.getType());
			tipoParams2=paramsService.addIdParams(tipoParams);
			
			if (tipoParams2!=null) { //Comprobar si es distinto de null
				
				//String Resp = parmid.toString();
				respuestaValueDto= new RespuestaValueDto(parmid);
				estatus=HttpStatus.OK;
				return new ResponseEntity(respuestaValueDto, estatus);
				
			}else {
				respuesta= new RespuestaMsgDto("Fallo la actualizacion");
				estatus=HttpStatus.BAD_REQUEST;
				return new ResponseEntity(respuesta, estatus);
				
			}
			
						
       
		}catch (Exception e) {
            // Manejo de excepciones
			respuesta= new RespuestaMsgDto("Error interno del servidor");
			estatus=HttpStatus.INTERNAL_SERVER_ERROR;            
        }
		
		return new ResponseEntity(respuesta, estatus);
	
	}
	
	//@GetMapping("/menus)
	//public ResponseEntity<MenuResponseDto> menu(@PathVariable final String sessionid) throws ParseException {
	@PostMapping("/params")
	public ResponseEntity<ParamsResponseDto> params(HttpServletRequest request,@RequestBody UsersListDto tiposfiltros) throws ParseException {
		RespuestaDto respuesta = new RespuestaDto("", false);
		HttpStatus estatus = HttpStatus.FORBIDDEN;
		ParamsResponseDto paramsResponseDto = new ParamsResponseDto();
		ParamsDto detalleParams;
		PrivilegesDto detallePrivilege;
		String fechaComoCadena;
		Long cuantosregistro = (long) 0;
	     List<ParamsDto> listasParams = new ArrayList<>();
	     List<PrivilegesDto> listasPrivelege = new ArrayList <>();
		 
		 String sessionid = request.getHeader("Authorization");
		  Date fecha = new Date();
		    SimpleDateFormat  formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
	        String dataFormattata = formatter.format(fecha);
	        Date fechaDate = formatter.parse(dataFormattata);
	        AuditRequestDto  auditDto=new AuditRequestDto();	       	        	     	      
	        
	   	  String searchIn = "";
	      String searchModule = "";
		  String searchUsr = "";
		  String contentIn = "";
		 
		  
		 int orderIn = 0;
		 int offsetIn = 0;
		 int numofrecordsIn = 0;
	
		 Date fecha2 = new Date();		
		 
			if (sessionid==null) {
				String var = "";
				boolean bloked = false;
				RespuestaDto respuestaDto = new RespuestaDto(var, bloked);
				respuestaDto.setBlocked(bloked);
				respuestaDto.setMsg("Sesión expirada o inválida");
				//Error 400
				return new ResponseEntity(respuestaDto, HttpStatus.BAD_REQUEST);
			} else   {
				 
				   sessionid = sessionid.substring(7);
				   Optional<Users> encontreSessionUsuario =usersRepository.getBySessionid(sessionid);
				   
				   if (encontreSessionUsuario.isPresent()) {
					   
					   Date FechaReg = encontreSessionUsuario.get().getValidthru(); 
					   //Llamada a la funcion que validad el tiempo de Session, retorna la fecha sumandole el tiempo de session activa, y vacio si no esta activa
					   

					    fechaComoCadena  = securityService.consultarSessionActiva(FechaReg,fecha2,encontreSessionUsuario.get().getId());

					   
					    if (fechaComoCadena=="") {
						   
						   
						   
						   String var = "";
							boolean bloked = false;
							RespuestaMsgDto respuestaDto = new RespuestaMsgDto(var);
							//respuestaDto.setBlocked(bloked);
							respuestaDto.setMsg("Sesión expirada o inválida"); 
							return new ResponseEntity(respuestaDto, HttpStatus.UNAUTHORIZED);
						   
					    }
					   //Este proceso permite obtener un listado de los parámetros (tabla "params") (Priv 610)
					   Roles roles = encontreSessionUsuario.get().getRolid();
					   int idrol = roles.getId();
					   int rolisvalid = auditRepository.getCantbyRolAndPrivi(idrol, 610);
					   
					   if (rolisvalid==0) {
						   
						   String var = "";
							boolean bloked = false;
							RespuestaMsgDto respuestaDto = new RespuestaMsgDto(var);
							//respuestaDto.setBlocked(bloked);
							respuestaDto.setMsg("No tiene los Privilegios"); 
							return new ResponseEntity(respuestaDto, HttpStatus.FORBIDDEN);
							
					   }
						  searchIn = tiposfiltros.getFilters().getSearch();
						  
						    String Salida = usersService.verificarCaracteresValidosConRegex(searchIn);
							  
							  if (Salida=="NOOK") {
								  String var = "";
									boolean bloked = false;
									RespuestaMsgDto respuestaDto = new RespuestaMsgDto(var);
									//respuestaDto.setBlocked(bloked);
									respuestaDto.setMsg("Caracteres no permitidos en la busqueda"); 
									return new ResponseEntity(respuestaDto, HttpStatus.BAD_REQUEST);
							  }
							  
						  searchIn = eliminarAcentos(tiposfiltros.getFilters().getSearch()); 
						  
						   //searchIn = eliminarAcentos(searchIn);
						  searchModule = tiposfiltros.getFilters().getModule();
						  searchUsr = tiposfiltros.getFilters().getUser();
						  
					
						  orderIn = tiposfiltros.getOrder();
						  offsetIn = tiposfiltros.getOffset();
						  numofrecordsIn = tiposfiltros.getNumofrecords();
						  contentIn = tiposfiltros.getContent();
						 // menuService.iscontentdiffnull(contentIn, encontreSessionUsuario.get().getId());
						  if (contentIn !=null) {
							  menuService.iscontentdiffnull(contentIn, encontreSessionUsuario.get().getId());
						  }
			
					
					
				 } else {
						String var = "";
						boolean bloked = false;
						RespuestaDto respuestaDto = new RespuestaDto(var, bloked);
						respuestaDto.setBlocked(bloked);
						respuestaDto.setMsg("Sesión expirada o inválida");
						//Error 400
						return new ResponseEntity(respuestaDto, HttpStatus.UNAUTHORIZED);
				 }
			}
			
			
		
		try {
			
			//int id = 3;
			//Se setean algunas palabras claves del Manejador de BD
			/*comienzo del comentario*/  
			
			String SentenciaBase = "SELECT new com.dacrt.SBIABackend.security.dto.ParamsDto (u.id, u.paramname,u.group,u.name,u.type,u.value,u.info,u.modifiedat) FROM Params u";									
			String QueryTotal = "";
			String name = "u.name";
			String group = "u.group";
			String lowerparam = "main.sinacentos(LOWER(u.paramname))";
			String lowername = "main.sinacentos(LOWER(u.name))";
			String lowergroup = "main.sinacentos(LOWER(u.group))";
			String LowerSearch = searchIn.toLowerCase();
		
			 switch (searchIn) { 
			    case "":  // viene sin busqueda por el like
			    	//QueryTotal = SentenciaBase;
			    	QueryTotal = SentenciaBase +  " WHERE " + "TRUE = TRUE";
			     break;
			  
			    default:	// viene con el parametro para buscar por el like		   			    				    	
			    	QueryTotal = SentenciaBase + " WHERE " + lowerparam + " LIKE  " + "'%" + LowerSearch + "%'"  + " OR " +  lowername + " LIKE " + "'%" + LowerSearch + "%'" +
			    	" OR " + lowergroup + " LIKE " + "'%" + LowerSearch + "%'";
			    	
	         }
			 
			 TypedQuery<ParamsDto> paramsCount= entityManager.createQuery(QueryTotal, ParamsDto.class);
			 cuantosregistro = (long) paramsCount.getResultList().size();
			 String ordena="";
			 if (orderIn == 1 || orderIn == 2 || orderIn == 3) {
				  ordena = " ASC";
			 }  else if (orderIn == -1 || orderIn == -2 || orderIn == -3) {
				  ordena = " DESC";
			 } else {
				 	String var2 = "";
					boolean bloked = false;
					RespuestaMsgDto respuestaDto = new RespuestaMsgDto(var2);
					respuestaDto= new RespuestaMsgDto("Error interno del servidor");
					estatus=HttpStatus.INTERNAL_SERVER_ERROR;   
					return new ResponseEntity(respuestaDto, estatus);
			 }
		
			 int absolutoOrden = Math.abs(orderIn);
			 switch (absolutoOrden) { 
			    case 1:  //ordena por group y name ascendente
			    	
			    	QueryTotal = QueryTotal + " ORDER BY " + group + ordena + "," + name + ordena;
			     break;
			    case 2://ordena por group ascendente
			    	
			    	QueryTotal = QueryTotal + " ORDER BY " + group + ordena;
			     break;
			   
			    case 3: //ordena por name ascendente
			    	
			    	QueryTotal = QueryTotal + " ORDER BY " + name + ordena;
			    	break;			
			   }
			 
			 //Se mapea la entidad se le pasa el query y lo bota como un tipo de objeto ParamDto-Buscar en los DTO 
			     TypedQuery<ParamsDto> params= entityManager.createQuery(QueryTotal, ParamsDto.class);
			      params.setFirstResult(offsetIn);
			      params.setMaxResults(numofrecordsIn);
			      List<ParamsDto> listacompleta = params.getResultList();
			
			      
		    	  	detallePrivilege = new PrivilegesDto();
		    	  	detallePrivilege.setUpdate(true);
		    	  	detallePrivilege.setView(true);
		    	
		    	  	//Se le pasa el listado al DTO RESPONSE que contiene la estructura de Salida solicitada
			      paramsResponseDto.setNumofrecords(cuantosregistro);
		           //paramsResponseDto.setValidthru(ValidThrufechaSalida);
		           paramsResponseDto.setValidthru(fechaComoCadena);		           
		           paramsResponseDto.setRecords(listacompleta);
		           paramsResponseDto.setPrivileges(detallePrivilege);		      		   			
		  						           
                return ResponseEntity.ok(paramsResponseDto);
		     																
						
       
		} catch (Exception e) {
            // Manejo de excepciones
			respuesta= new RespuestaDto("Error interno del servidor", false);
			estatus=HttpStatus.INTERNAL_SERVER_ERROR;            
        }finally {
	        if (entityManager != null && entityManager.isOpen()) {
	            entityManager.close();
	        }
        }
		
		return new ResponseEntity(respuesta, estatus);
	
	}

	
	public String arrayAParentesis(List<Integer> lista) {
		
	    if (lista == null || lista.isEmpty()) {
	        return "()";
	    }
	    StringBuilder sb = new StringBuilder("(");
	    for (int i = 0; i < lista.size(); i++) {
	        sb.append(lista.get(i));
	        if (i < lista.size() - 1) {
	            sb.append(", ");
	        }
	    }
	    sb.append(")");
	    return sb.toString();
	}
	
	
	
	  public String eliminarAcentos(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}]");
	        return pattern.matcher(normalized).replaceAll("");
	    }

	
}