/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.rjconsultores.ventaboletos.service.impl;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.security.authentication.CredentialsExpiredException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.rjconsultores.ventaboletos.dao.RecuperarSenhaDAO;
import com.rjconsultores.ventaboletos.dao.UsuarioDAO;
import com.rjconsultores.ventaboletos.dao.UsuarioPerfilDAO;
import com.rjconsultores.ventaboletos.entidad.Empleado;
import com.rjconsultores.ventaboletos.entidad.Perfil;
import com.rjconsultores.ventaboletos.entidad.RecuperarSenha;
import com.rjconsultores.ventaboletos.entidad.Usuario;
import com.rjconsultores.ventaboletos.entidad.UsuarioPerfil;
import com.rjconsultores.ventaboletos.exception.BusinessException;
import com.rjconsultores.ventaboletos.service.ConstanteService;
import com.rjconsultores.ventaboletos.service.LogAuditoriaService;
import com.rjconsultores.ventaboletos.service.UsuarioService;
import com.rjconsultores.ventaboletos.utilerias.ApplicationProperties;
import com.rjconsultores.ventaboletos.utilerias.CustomEnum;
import com.rjconsultores.ventaboletos.utilerias.UsuarioLogado;
import com.rjconsultores.ventaboletos.utilerias.seguridad.ContrasenaUtileria;
import com.rjconsultores.ventaboletos.vo.embarcada.UsuarioEmbarcadaVO;
import com.rjconsultores.ventaboletos.web.utilerias.spring.AppContext;

/**
 * 
 * @author Administrador
 */
@Service("usuarioService")
public class UsuarioServiceImpl implements UsuarioService, UserDetailsService {

	@Autowired
	private UsuarioDAO usuarioDAO;
	@Autowired
	private UsuarioPerfilDAO usuarioPerfilDAO;
	@Autowired
	private LogAuditoriaService logAuditoriaService;
	private static final Logger log = LogManager.getLogger(UsuarioServiceImpl.class);
	
	@Autowired
	private RecuperarSenhaDAO recuperarSenhaDAO;

	public List<Usuario> buscarPeloNome(String nome) {
		return usuarioDAO.buscarPeloNome(nome);
	}

	public List<Usuario> obtenerTodos() {
		return usuarioDAO.obtenerTodos();
	}

	public Usuario obtenerID(Integer id) {
		
		Usuario usuario = usuarioDAO.obtenerID(id);
		try {
			usuario.clonar();
		} catch (Exception e) {
			log.error(e.getMessage(), e);
		}
		return usuario;
		
	}
	
	@Override
	public Usuario obtenerCompletoID(Integer id) {
		
		Usuario usuario = usuarioDAO.obtenerID(id);
		try {
			usuario.clonar();
		} catch (Exception e) {
			log.error(e.getMessage(), e);
		}
		return usuario;
		
	}

	@Transactional(rollbackFor = BusinessException.class)
	@Override
	public Usuario suscribirActualizar(Usuario entidad, String senha, Perfil perfil) throws BusinessException {
		
		try{
			
			Usuario originalClone = entidad.getCloneObject();
	
			// validaciOn duplicado
			List<Usuario> lsUsuario = this.buscarPelaCveUsuario(entidad.getClaveUsuario());
			boolean podeSalvar = false;
			if (lsUsuario.isEmpty()) {
				podeSalvar = true;
			} else {
				if (entidad.getUsuarioId() != null) {
					for (Usuario u : lsUsuario) {
						if (u.getUsuarioId().equals(entidad.getUsuarioId())) {
							podeSalvar = true;
						}
					}
				}
			}
	
			if (!podeSalvar) {
				throw new BusinessException("MSG.Registro.Existe");
			}
			if (senha != null) {
				// validaciOn complejidad contrasena
				if (ApplicationProperties.getInstance().isCustomHabilitado(CustomEnum.CONTRASENA_VALIDA_COMPLEJIDAD.getDescricao())) {
					
					ConstanteService constanteService = (ConstanteService) AppContext.getApplicationContext().getBean("constanteService");
					boolean CONSTANTE_CANT_MIN_CARACTER_OITO = constanteService.buscarPorNomeConstante("CONSTANTE_CANT_MIN_CARACTER_OITO").getValorconstante() != null ? Boolean.parseBoolean(constanteService.buscarPorNomeConstante("CONSTANTE_CANT_MIN_CARACTER_OITO").getValorconstante()) : false;
					
					if(CONSTANTE_CANT_MIN_CARACTER_OITO) {
						ContrasenaUtileria  contrasenaUtileria = new ContrasenaUtileria(8);
						contrasenaUtileria.validarContrasenaCompleja(senha);
					} else {
						ContrasenaUtileria  contrasenaUtileria = new ContrasenaUtileria();
						contrasenaUtileria.validarContrasenaCompleja(senha);
					}
				}
	
				// encriptacion contrasena
				entidad.setSenha(ContrasenaUtileria.encriptarContrasena(senha));
			}
	
			// Perfil
			UsuarioPerfil up = new UsuarioPerfil();
			up.setUsuario(entidad);
			up.setPerfil(perfil);
			up.setActivo(Boolean.TRUE);
			up.setFecmodif(Calendar.getInstance().getTime());
			up.setUsuariomodifId(UsuarioLogado.getUsuarioLogado().getUsuarioId());
	
			if (entidad.getUsuarioId() != null) {
				List<UsuarioPerfil> lsUsuarioPerfil = usuarioPerfilDAO.obtenerPorUsuario(entidad);
				for (UsuarioPerfil up2 : lsUsuarioPerfil) {
					usuarioPerfilDAO.borrar(up2);
				}
			}
			List<UsuarioPerfil> lsUp = new ArrayList<UsuarioPerfil>();
			lsUp.add(up);
			entidad.setUsuarioPerfilList(lsUp);
	
			entidad.setUsuariomodifId(UsuarioLogado.getUsuarioLogado().getUsuarioId());
			entidad.setFecmodif(Calendar.getInstance().getTime());
			entidad.setActivo(Boolean.TRUE);
	
			if (entidad.getUsuarioId() == null) {	
				 usuarioDAO.suscribir(entidad);
				 logAuditoriaService.auditar(null, entidad, entidad.getEmpresa() != null && !entidad.getEmpresa().isEmpty()? entidad.getEmpresa().get(0).getEmpresaId(): null);
				return entidad;

			} else {
				entidad = usuarioDAO.actualizacion(entidad);
				logAuditoriaService.auditar(originalClone, entidad, entidad.getEmpresa() != null && !entidad.getEmpresa().isEmpty()? entidad.getEmpresa().get(0).getEmpresaId(): null);
				return entidad;
			}
		}catch (Exception e) {
			log.error(e.getMessage(), e);
			throw new RuntimeException(e.getMessage(), e);
		}
	}

	@Transactional(rollbackFor = BusinessException.class)
	@Override
	public Usuario cambiarContrasena(Usuario entidad, String senha) throws BusinessException {
		
		// validaciOn duplicado
		List<Usuario> lsUsuario = this.buscarPelaCveUsuario(entidad.getClaveUsuario());
		boolean podeSalvar = false;
		if (lsUsuario.isEmpty()) {
			podeSalvar = true;
		} else {
			if (entidad.getUsuarioId() != null) {
				for (Usuario u : lsUsuario) {
					if (u.getUsuarioId().equals(entidad.getUsuarioId())) {
						podeSalvar = true;
					}
				}
			}
		}

		if (!podeSalvar) {
			throw new BusinessException("MSG.Registro.Existe");
		}
		if (senha != null) {
			// validaciOn complejidad contrasena
			if (ApplicationProperties.getInstance().isCustomHabilitado(CustomEnum.CONTRASENA_VALIDA_COMPLEJIDAD.getDescricao())) {
				
				ConstanteService constanteService = (ConstanteService) AppContext.getApplicationContext().getBean("constanteService");
				boolean CONSTANTE_CANT_MIN_CARACTER_OITO = constanteService.buscarPorNomeConstante("CONSTANTE_CANT_MIN_CARACTER_OITO").getValorconstante() != null ? Boolean.parseBoolean(constanteService.buscarPorNomeConstante("CONSTANTE_CANT_MIN_CARACTER_OITO").getValorconstante()) : false;
				
				if(CONSTANTE_CANT_MIN_CARACTER_OITO) {
					ContrasenaUtileria  contrasenaUtileria = new ContrasenaUtileria(8);
					contrasenaUtileria.validarContrasenaCompleja(senha);
				} else {
					ContrasenaUtileria  contrasenaUtileria = new ContrasenaUtileria();
					contrasenaUtileria.validarContrasenaCompleja(senha);
				}	
			}

			// encriptacion contrasena
			entidad.setSenha(ContrasenaUtileria.encriptarContrasena(senha));
		}

		entidad.setFecContrasena(Calendar.getInstance().getTime());
		entidad.setUsuariomodifId(entidad.getUsuarioId());
		entidad.setFecmodif(Calendar.getInstance().getTime());
		entidad.setIndTrocaSenha(Boolean.FALSE);
		entidad.setActivo(Boolean.TRUE);

		if (entidad.getUsuarioId() != null) {
			return usuarioDAO.actualizacion(entidad);
		} else {
			throw new BusinessException("MSG.Registro.Existe");
		}
	}

	@Transactional
	public void borrar(Usuario entidad) {

		entidad = obtenerID(entidad.getUsuarioId());

		for (UsuarioPerfil up : entidad.getUsuarioPerfilList()) {
			up.setUsuariomodifId(UsuarioLogado.getUsuarioLogado().getUsuarioId());
			up.setFecmodif(Calendar.getInstance().getTime());
			up.setActivo(Boolean.FALSE);
		}

		entidad.setUsuariomodifId(UsuarioLogado.getUsuarioLogado().getUsuarioId());
		entidad.setFecmodif(Calendar.getInstance().getTime());
		entidad.setActivo(Boolean.FALSE);

		usuarioDAO.actualizacion(entidad);
		logAuditoriaService.auditarExclusao(entidad, entidad.getEmpresa() != null && !entidad.getEmpresa().isEmpty()? entidad.getEmpresa().get(0).getEmpresaId(): null);
	}

	public Usuario buscarPeloNomeSenha(String stUsuario, String senha) {
		senha = ContrasenaUtileria.encriptarContrasena(senha);
		return usuarioDAO.buscarPeloNomeSenha(stUsuario, senha);
	}

	@Override
	public UserDetails loadUserByUsername(String login) throws UsernameNotFoundException, DataAccessException, CredentialsExpiredException {
		if (login == null) {
			throw new UsernameNotFoundException("Usuario não encontrado");
		}
		List<Usuario> list = usuarioDAO.buscarPelaCveUsuario(login.toUpperCase());

		if (list.isEmpty()) {
			throw new UsernameNotFoundException("Usuario não encontrado");
		}

		Usuario user = list.get(0);

		if (ApplicationProperties.getInstance().isCustomHabilitado(CustomEnum.CONTRASENA_VALIDA_COMPLEJIDAD.getDescricao())) {
			if (!user.isCredentialsNonExpired()) {
				throw new CredentialsExpiredException("Senha Expirada");
			}
		}
		
		if (user.getIndTrocaSenha() != null) {
			if (user.getIndTrocaSenha()) { 
				throw new CredentialsExpiredException("Senha Expirada");
			}	
		}

		return user;
	}

	public List<Usuario> buscarPorEmpleado(Empleado empleado) {
		return usuarioDAO.buscarPorEmpleado(empleado);
	}

	public List<Usuario> buscarPelaCveUsuario(String cveUsuario) {
		return usuarioDAO.buscarPelaCveUsuario(cveUsuario);
	}

	@Override
	public List<Usuario> buscarPeloNomeLike(String nome) {
		return usuarioDAO.buscarPeloNomeLike(nome);
	}

	@Override
	public List<UsuarioEmbarcadaVO> buscarUsuariosEmbarcadaPorPontoVenda(Long puntoVentaId) {
		return usuarioDAO.buscarUsuarioPorPontoVenda(puntoVentaId);
	}
	
	@Override
	public List<UsuarioEmbarcadaVO>  buscarUsuariosEmbarcadaPorDispositivo(Long dispositivoEmbarcadaId){
		return usuarioDAO.buscarUsuarioPorDispositivo(dispositivoEmbarcadaId);
	}
	
	@Override
	public List<UsuarioEmbarcadaVO> buscarUsuarioEmbarcadaPorUsuariosIds(List<Long> usuariosIdList) {
		return usuarioDAO.buscarUsuarioEmbarcadaPorUsuariosIds(usuariosIdList);
	}

	@Override
	public List<UsuarioEmbarcadaVO> buscaUsuariosDoPuntoVenta(Long puntoVentaId) {
		return usuarioDAO.buscaUsuariosDoPuntoVenta(puntoVentaId);
	}
	
	@Override
	public RecuperarSenha buscarLinkRecuperacaoSenhaPeloParam(String param) {
		return recuperarSenhaDAO.buscarPeloParam(param);
	}

	@Override
	@Transactional
	public void desativarLinkRecuperacaoSenha(RecuperarSenha entidad) {
		entidad.setActivo(Boolean.FALSE);
		
		recuperarSenhaDAO.actualizacion(entidad);
	}
	
	@Override
	@Transactional
	public void salvarLinkRecuperacaoSenha(RecuperarSenha entidad) {
		recuperarSenhaDAO.suscribir(entidad);
	}
}
