package br.mp.mprj.portal.portlet.gestaomensagens.service.service.impl;

import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import javax.mail.internet.AddressException;

import br.mp.mprj.portal.portlet.gestaomensagens.email.EnvioEmailAgendado;
import br.mp.mprj.portal.portlet.gestaomensagens.email.EnvioEmailMensagem;
import br.mp.mprj.portal.portlet.gestaomensagens.enums.SituacaoEnvioEnum;
import br.mp.mprj.portal.portlet.gestaomensagens.enums.TipoAgendamentoEnum;
import br.mp.mprj.portal.portlet.gestaomensagens.service.model.Agendamento;
import br.mp.mprj.portal.portlet.gestaomensagens.service.model.Mensagem;
import br.mp.mprj.portal.portlet.gestaomensagens.service.model.impl.AgendamentoModelImpl;
import br.mp.mprj.portal.portlet.gestaomensagens.service.service.base.AgendamentoLocalServiceBaseImpl;
import br.mp.mprj.portal.portlet.gestaomensagens.service.service.persistence.AgendamentoFinderUtil;
import br.mp.mprj.portal.portlet.gestaomensagens.workflow.StatusWorkflowEnum;

import com.liferay.portal.kernel.dao.orm.QueryUtil;
import com.liferay.portal.kernel.exception.PortalException;
import com.liferay.portal.kernel.exception.SystemException;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.util.OrderByComparator;
import com.liferay.portal.kernel.util.OrderByComparatorFactoryUtil;

/**
 * The implementation of the agendamento local service.
 *
 * <p>
 * All custom service methods should be put in this class. Whenever methods are added, rerun ServiceBuilder to copy their definitions into the {@link br.mp.mprj.portal.portlet.gestaomensagens.service.service.AgendamentoLocalService} interface.
 *
 * <p>
 * This is a local service. Methods of this service will not have security checks based on the propagated JAAS credentials because this service can only be accessed from within the same VM.
 * </p>
 *
 * @author Henrique Simoes
 * @see br.mp.mprj.portal.portlet.gestaomensagens.service.service.base.AgendamentoLocalServiceBaseImpl
 * @see br.mp.mprj.portal.portlet.gestaomensagens.service.service.AgendamentoLocalServiceUtil
 */
public class AgendamentoLocalServiceImpl extends AgendamentoLocalServiceBaseImpl {
	
	
	private static final Log _log = LogFactoryUtil.getLog(AgendamentoLocalServiceImpl.class);
	private SimpleDateFormat sdfHorario = new SimpleDateFormat("HH:mm");
	
	/**
	 * Retorna os agendamentos de determinada mensagem, de acordo com os tipos definidos em {@link TipoAgendamentoEnum} (posi&ccedil;&atilde;o do enum, ou seja, ordinal).
	 * @param mensagemId
	 * @param tiposAgendamento
	 * @return
	 * @throws PortalException
	 * @throws SystemException
	 */
	public List<Agendamento> findByMensagemTipoAgendamentoMultiplos(long mensagemId, int[] tiposAgendamento)
			throws PortalException, SystemException {
		return agendamentoPersistence.findByMensagemTipoMultipo(mensagemId, tiposAgendamento);
	}
	
	/**
	 * Define as informa&ccedil;&otilde;es de agendamento nos atributos da mensagem.
	 * @param mensagem - inst&acirc;ncia de {@link Mensagem} devidamente inicializada.
	 * @param carregarCalendario - definir se deve ou n&atilde;o carregar os Map's auxiliares para a montagem do calend&aacute;rio na p&aacute;gina.
	 */
	public void carregarAgendamento(Mensagem mensagem, boolean carregarCalendario)
			throws PortalException, SystemException {
		List<Agendamento> listAg = new ArrayList<Agendamento>();
		mensagem.setAgendamentos(listAg);
		
		OrderByComparator orderBy = OrderByComparatorFactoryUtil.create(AgendamentoModelImpl.TABLE_NAME, "dataInicio", true);
		
		for(TipoAgendamentoEnum tipoAg : TipoAgendamentoEnum.values()) {
			List<Agendamento> listTemp = agendamentoPersistence
											.findByMensagemTipo(
													mensagem.getMensagemId(), 
													tipoAg.ordinal(),
													QueryUtil.ALL_POS,
													QueryUtil.ALL_POS,
													orderBy);
			
			//adiciona os agendamentos no objeto Mensagem
			listAg.addAll(listTemp);
			
			//processa os agendamentos do calendario, para montar os Maps auxiliares da montagem da pagina
			if (carregarCalendario 
					&& tipoAg.ordinal() == TipoAgendamentoEnum.CALENDARIO.ordinal()) {
				//montar as datas e horarios do calendario
				Map<Long, Map<String, Agendamento>> calendario = new TreeMap<>();
				mensagem.setDatasCalendario(calendario);
				
				//processar todos os agendamentos do tipo calendario
				for (Agendamento ag : listTemp) {
					long unixDate = ag.getDataCalendario().getTime();
					if (ag.getSituacaoEnvio() == 0){
						
						Map<String, Agendamento> horarios = calendario.get(unixDate);
						
						if (horarios == null) {
							horarios = new TreeMap<>();
							calendario.put(unixDate, horarios);
						}

						//verifica se o horario ja foi mapeado para a data
						String hora = sdfHorario.format(ag.getDataInicio());
						if (!horarios.containsKey(hora)) {
							horarios.put(hora, ag);
						}
					}
				}
			}
		}
	}	
	/**
	 * Localiza todos os Agendamentos que ainda estao
	 * pendentes de envio e que possuem a data e hora anterior ao
	 * momento atual.
	 */
	public List<Agendamento> findByMensagensPendetesDeEnvio() {
		return AgendamentoFinderUtil.findByMensagensPendetesDeEnvio();
	}
	/**
	 * Recupera o total de agendamentos por mensagem e situacao de envio.
	 */
	public int recuperaTotalAgendamentosPorSituacao(long mensagemId, int situacaoEnvio) throws SystemException{
		return agendamentoPersistence.countByMensagemIdSituacaoEnvio(mensagemId, situacaoEnvio);
	}
	
	/**
	 * Recupera uma lista de agendamentos por mensagem e situacao de envio.
	 */
	public List<Agendamento> recuperaAgendamentosPorSituacao(long mensagemId, int situacaoEnvio) throws SystemException{
		return agendamentoPersistence.findByMensagemIdSituacaoEnvio(mensagemId, situacaoEnvio);
	}
	/**
	 * Recupera uma lista de agendamentos por mensagem.
	 */
	public List<Agendamento> recuperaAgendamentos(long  mensagemId) throws SystemException{
		return agendamentoPersistence.findByMensagemId(mensagemId);
	}
	
	public void gerenciaAgendamentos(final Mensagem mensagem , final Agendamento agendamento) throws SystemException{
		
		final Date dataEnvio = new Date();
		
		if (recuperaAgendamentosPorSituacao(mensagem.getMensagemId(), SituacaoEnvioEnum.PENDENTE.ordinal()).size() == 1){
			mensagem.setSituacaoEnvio(SituacaoEnvioEnum.ENVIADO.ordinal());
		}
		
		//Atualiza a mensagem configurando seu status como enviado
		mensagem.setDataUltimoEnvio(dataEnvio);
		mensagemLocalService.updateMensagem(mensagem);
		
		agendamento.setDataEnvio(dataEnvio);
		agendamento.setSituacaoEnvio(SituacaoEnvioEnum.ENVIADO.ordinal());
		updateAgendamento(agendamento);
		
	}
	
	public void enviaMensagem(Mensagem mensagem, Agendamento agendamento) throws PortalException, SystemException, AddressException, UnsupportedEncodingException {
		
	//	mensagem.setSituacaoEnvio(SituacaoEnvioEnum.PROCESSANDO.ordinal());
	//	mensagemLocalService.updateMensagem(mensagem);
    	
		gerenciaAgendamentos(mensagem , agendamento);
		
		EnvioEmailMensagem envio = new EnvioEmailAgendado(mensagem);
		envio.enviarEmail(2);
	}
	
	public void enviaMensagem(final List<Agendamento> listaAgendamento) 
			throws PortalException {
		if (listaAgendamento != null) {
			for (Agendamento agendamento : listaAgendamento){
				try {
					final Mensagem mensagem = mensagemLocalService.getMensagem(agendamento.getMensagemId());
					
					if (mensagem.getStatusWorkflow() == StatusWorkflowEnum.APROVADO.getStatus()) {	
						
						enviaMensagem(mensagem, agendamento);
					}
				} catch (Exception e) {
					_log.error("Ocorreu uma falha durante o envio da mensagem de identificador: [ " + agendamento.getMensagemId() 
					+ " ]." , e);
				} 
			}		
		}
	}
}
