package com.rjconsultores.ventaboletos.service.impl;

import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map.Entry;

import javax.mail.AuthenticationFailedException;
import javax.mail.SendFailedException;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.rjconsultores.ventaboletos.constantes.Constantes;
import com.rjconsultores.ventaboletos.dao.LogHistoricoContingenciaDAO;
import com.rjconsultores.ventaboletos.entidad.Constante;
import com.rjconsultores.ventaboletos.entidad.EmpresaEmail;
import com.rjconsultores.ventaboletos.entidad.EmpresaEmailConfig;
import com.rjconsultores.ventaboletos.entidad.LogHistoricoContingencia;
import com.rjconsultores.ventaboletos.enums.EAmbienteContingencia;
import com.rjconsultores.ventaboletos.enums.EStatusContingencia;
import com.rjconsultores.ventaboletos.exception.BusinessException;
import com.rjconsultores.ventaboletos.rest.ContingenciaClienteRest;
import com.rjconsultores.ventaboletos.service.ConstanteService;
import com.rjconsultores.ventaboletos.service.ContingenciaService;
import com.rjconsultores.ventaboletos.service.EmpresaEmailConfigService;
import com.rjconsultores.ventaboletos.service.EmpresaEmailService;
import com.rjconsultores.ventaboletos.utilerias.SendMail;
import com.rjconsultores.ventaboletos.utilerias.SendMail.AuthType;
import com.rjconsultores.ventaboletos.utilerias.StringHelper;
import com.rjconsultores.ventaboletos.utilerias.UsuarioLogado;

/**
 * @author vjcor
 *
 */
@Service("contingenciaService")
public class ContingenciaServiceImpl implements ContingenciaService {
	
	private static final String EMAIL_SUPORTE_SCO_RJCONSULTORES = "EMAIL_SUPORTE_RJCONSULTORES";
	
	private static final Logger log = LogManager.getLogger(ContingenciaServiceImpl.class);
	
	@Autowired
	private LogHistoricoContingenciaDAO histContingenciaDAO;
	
	@Autowired
	private EmpresaEmailService empresaEmailService;
	
	@Autowired
	private EmpresaEmailConfigService empresaEmailConfigService;
	
	@Autowired
	private ConstanteService constanteService;
	
	public List<LogHistoricoContingencia> buscarHistorico(Integer empresaID, Integer estadoID) {		
		return histContingenciaDAO.buscarHistorico(empresaID, estadoID);
	}
	
	@Transactional
	public LogHistoricoContingencia salvarHistoricoContingencia(LogHistoricoContingencia historicoCont) throws BusinessException, SendFailedException, AuthenticationFailedException{
		historicoCont.setUsuario(UsuarioLogado.getUsuarioLogado());		
		historicoCont.setDataHora(Calendar.getInstance().getTime());
		
		if (historicoCont.getEmpresa() == null) {
			throw new BusinessException("NÃO é possível salvar sem a empresa");
		} 
		
		if (historicoCont.getEstado() == null) {
			throw new BusinessException("NÃO é possível salvar sem o estado referente");
		}
		
		if (historicoCont.getMotivo() == null) {
			throw new BusinessException("NÃO é possível salvar sem o motivo referente");
		}			
		
		try {
			Integer retorno = definirStatusContingencia(historicoCont);

			if (retorno == null) {
				throw new BusinessException(" entre em contato com o administrador do sistema.");
			}

			if (EStatusContingencia.CONTINGENCIA.equals(getStatusContingencia(historicoCont))) {
				enviaEmail(historicoCont);
			}
		} catch (SendFailedException e2 ) {
			setMotivoNaoTrocaStatus(historicoCont, e2);
			histContingenciaDAO.suscribir(historicoCont);
			throw e2;
		}catch (AuthenticationFailedException e2) {
			setMotivoNaoTrocaStatus(historicoCont, e2);
			histContingenciaDAO.suscribir(historicoCont);
			throw e2;
		}
		
		return histContingenciaDAO.suscribir(historicoCont);
	}

	private void setMotivoNaoTrocaStatus(LogHistoricoContingencia historicoCont, Exception e) {
		log.error(String.format("Erro no envio de e-mail de contingência da empresa %s para o estado %s.", historicoCont.getEmpresa().getEmpresaId(),historicoCont.getEstado()), e);

		String motivo = historicoCont.getMotivo();
		motivo = motivo.concat("**Problema no envio de E-mail de notificação. Favor checar.");
		
		historicoCont.setMotivo(motivo);
	}

	private Integer definirStatusContingencia(LogHistoricoContingencia historicoCont) {
		
		Integer statusEnviado = Integer.valueOf(historicoCont.getStatus());

		List<Constante> constantesContig = constanteService.buscarPorNomeConstanteLike(Constantes.BPE_URL_CONTIG);
		if (CollectionUtils.isEmpty(constantesContig)) {
			Constante constanteBPeURL = constanteService.buscarPorNomeConstante(Constantes.BPE_URL);
			constantesContig.add(constanteBPeURL);
		}

		HashMap<Constante, Integer> retornos = new HashMap<Constante, Integer>();

		for (Constante constante : constantesContig) {

			try {
				String url = constante.getValorconstante();
				Integer retorno = ContingenciaClienteRest.getInstance().consultar(url, historicoCont.getEstado().getCveestado(), historicoCont.getAmbiente().toString(), StringHelper.retornaSomenteNumeros(historicoCont.getEmpresa().getCnpj()));
				retornos.put(constante, retorno);
			} catch (Exception e) {
				log.error("", e);
			}
		}

		for (Entry<Constante, Integer> entry : retornos.entrySet()) {
			if (entry.getValue() == null || (entry.getValue() != null && entry.getValue().equals(statusEnviado))) {
				log.info("O Servidor:" + entry.getKey().getValorconstante() + "enviou: " + statusEnviado + " recebeu " + entry.getValue());
				return null;
			}
		}

		for (Constante constante : constantesContig) {

			try {
				String bpeURL = constante.getValorconstante();

				Integer retorno = ContingenciaClienteRest.getInstance().definir(bpeURL, historicoCont.getEstado().getCveestado(),
						historicoCont.getAmbiente().toString(), StringHelper.retornaSomenteNumeros(historicoCont.getEmpresa().getCnpj()),
						Integer.valueOf(historicoCont.getStatus()));

				log.info("Servidor:" + bpeURL + " status:" + retorno);

			} catch (Exception e) {
				log.error("", e);
			}
		}
		
		return statusEnviado;

	}

	private EStatusContingencia getStatusContingencia(LogHistoricoContingencia historicoCont) {
		return EStatusContingencia.getStatusContingencia(Integer.valueOf(historicoCont.getStatus()));
	}

	private void enviaEmail(LogHistoricoContingencia historicoCont) throws SendFailedException, AuthenticationFailedException {

		EmpresaEmail empresaEmail = empresaEmailService.buscarPorEmpresa(historicoCont.getEmpresa());
		EmpresaEmailConfig empresaEmailConfig = empresaEmailConfigService.buscarPorEmpresa(historicoCont.getEmpresa());
		Constante emailSuporRJConstante = constanteService.buscarPorNomeConstante(EMAIL_SUPORTE_SCO_RJCONSULTORES);
		String emailSuporRJ = emailSuporRJConstante !=null ?  emailSuporRJConstante.getValorconstante() : null;
		if (empresaEmail != null && empresaEmailConfig != null &&
				empresaEmailConfig.getIndAutenticacao() != null && empresaEmail.getEmailDe() != null &&
				empresaEmailConfig.getTipoAutorizacao() != null && empresaEmailConfig.getSmtp() != null &&
				empresaEmailConfig.getSenha() != null && empresaEmailConfig.getSmtpPorta() != null &&
				empresaEmailConfig.getSmtpEmail() != null && empresaEmail.getDestinatario() != null) {

			SendMail mail = new SendMail();
			mail.setAuth(empresaEmailConfig.getIndAutenticacao());
			if (StringUtils.isNotEmpty(empresaEmailConfig.getTipoAutorizacao())) {
				mail.setAuthType(AuthType.valueOf(empresaEmailConfig.getTipoAutorizacao()));
			}
			mail.setEmailFrom(empresaEmail.getEmailDe());
			mail.setSmtpHost(empresaEmailConfig.getSmtp());
			mail.setSmtpPassword(empresaEmailConfig.getSenha());
			mail.setSmtpPort(empresaEmailConfig.getSmtpPorta());
			mail.setSmtpUser(empresaEmailConfig.getSmtpEmail());
			mail.setSubject("Contingência Off-line BP-e");
			mail.setText(getMensagem(historicoCont));
			mail.setEmailTo(empresaEmail.getDestinatario());
			if(StringUtils.isNotBlank(emailSuporRJ)) {
				mail.setEmailToCO(emailSuporRJ);				
			}
			mail.send();
		}
	}

	private String getMensagem(LogHistoricoContingencia historicoContingencia) {
		StringBuilder mensagem = new StringBuilder();
		mensagem.append(String.format("A empresa %s está com a emissão do BP-e em contingência off-line para a UF %s no ambiente de %s. ", 
				historicoContingencia.getEmpresa().getNombempresa(), historicoContingencia.getEstado().getCveestado(), 
				EAmbienteContingencia.getAmbienteContingencia(historicoContingencia.getAmbiente()).getDescricao()));
		mensagem.append("A emissão em contingência deve ser tratada como exceção, sendo que a regra deve ser a emissão com autorização em tempo real.");
		mensagem.append("O Fisco poderá solicitar esclarecimentos, e até mesmo restringir ao contribuinte a utilização da modalidade de contingência off-line, caso seja identificado que o emissor do BP-e utiliza a contingência em demasia e sem justificativa aceitável, quando comparado a outros contribuintes em situação similar."); 
		mensagem.append("Na utilização de contingência off-line, o contribuinte assume o risco de perda da informação dos "); 
		mensagem.append("BP-e emitidos em contingência, até que os mesmos constem da base de dados do Fisco.");
		return mensagem.toString();
	}

}
