package br.mp.mprj.portal.portlet.gestaomensagens.action;

import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Map;
import java.util.TreeMap;

import javax.mail.internet.AddressException;
import javax.portlet.PortletException;
import javax.portlet.PortletRequest;
import javax.portlet.PortletResponse;

import com.liferay.counter.service.CounterLocalServiceUtil;
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.servlet.SessionErrors;
import com.liferay.portal.kernel.servlet.SessionMessages;
import com.liferay.portal.kernel.util.GetterUtil;
import com.liferay.portal.kernel.util.ParamUtil;
import com.liferay.portal.kernel.util.Validator;
import com.liferay.portal.kernel.workflow.WorkflowConstants;
import com.liferay.portal.service.ServiceContext;
import com.liferay.portal.service.ServiceContextFactory;
import com.liferay.util.portlet.PortletProps;

import br.mp.mprj.portal.portlet.gestaomensagens.email.EnvioEmailMensagem;
import br.mp.mprj.portal.portlet.gestaomensagens.email.EnvioEmailWorkflow;
import br.mp.mprj.portal.portlet.gestaomensagens.enums.TipoAgendamentoEnum;
import br.mp.mprj.portal.portlet.gestaomensagens.enums.TipoEnvioEnum;
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.service.AgendamentoLocalServiceUtil;
import br.mp.mprj.portal.portlet.gestaomensagens.service.service.MensagemLocalServiceUtil;
import br.mp.mprj.portal.portlet.gestaomensagens.util.GestaoMensagensUtil;
import br.mp.mprj.portal.portlet.gestaomensagens.workflow.AcaoWorkflowEnum;
import br.mp.mprj.portal.portlet.gestaomensagens.workflow.StatusWorkflowEnum;
import br.mp.mprj.portal.portlet.gestaomensagens.workflow.WorkflowUtil;

/**
 * Action específica para tratar o agendamento da mensagem.
 * @author Henrique
 *
 */
public class WizardMensagemAgendamentoActionCommand extends
		WizardBaseActionCommand {
	
	private Log _log = LogFactoryUtil.getLog(WizardMensagemAgendamentoActionCommand.class);
	private final String HTML_LITERAL_AGENDAMENTO_IMEDIATO = "<strong>A mensagem foi configurada para ser enviada imediatamente.</strong>";
	private final String HTML_LITERAL_AGENDAMENTO_AGENDADO = "<strong>A mensagem foi configurada para ser enviada nas seguintes datas e horários:</strong><br/>";
	
	@Override
	public boolean processCommand(PortletRequest req, PortletResponse res)
			throws PortletException {
		super.processCommand(req, res);
		
		try {
			Mensagem mensagem = getMensagem(req);
			
			preencherDadosFormulario(req, mensagem);
			
			processarAgendamento(req, mensagem);

			mensagem.setGravarAgendamento(true);
			
			gravarMensagem(req, mensagem);
			
			//Se a mensagem estiver configurada como pre-aprovada
			if (mensagem.getStatusWorkflow() == StatusWorkflowEnum.APROVADO.getStatus()){
				
				
				mensagem.setRascunho(false);
				mensagem.setGravarAgendamento(false);
				MensagemLocalServiceUtil.updateMensagem(mensagem);
				
				if (mensagem.getClonagemPai() > 0){
					MensagemLocalServiceUtil.cancelarMensagem(mensagem.getClonagemPai());
				}
				
				removerMensagemSession(req);
				SessionMessages.add(req, "mensagem-gravada-aprovada-workflow");	
				
				return true;
				
				
			} else if (ParamUtil.getBoolean(req, "gravarWorkflow") && !ParamUtil.getBoolean(req, "edicao")) {
				
				ServiceContext serviceContext = ServiceContextFactory.getInstance(Mensagem.class.getName(), req);
				
				if (mensagem.getStatusWorkflow() == StatusWorkflowEnum.PENDENTE_REVISAO.getStatus()){
					
					WorkflowUtil.atualizarStatusWorkflow(mensagem, AcaoWorkflowEnum.REVISAR, 
							GetterUtil.getString(PortletProps.get("workflow.texto-padrao.revisao")), serviceContext.getUserId(), 
							serviceContext);
					
				} else {
					WorkflowUtil.inicializarWorkflowMensagem(mensagem, serviceContext);
				}
				
				mensagem.setRascunho(false);
				mensagem.setGravarAgendamento(false);
				mensagem.setStatusWorkflow(WorkflowConstants.STATUS_DRAFT);
				
				if (mensagem.getClonagemPai() > 0){
					MensagemLocalServiceUtil.cancelarMensagem(mensagem.getClonagemPai());
				}
				
				MensagemLocalServiceUtil.updateMensagem(mensagem);
				
				EnvioEmailMensagem envioEmail = new EnvioEmailWorkflow(mensagem);
				envioEmail.enviarEmail(0);
				
				removerMensagemSession(req);
			} else if (ParamUtil.getBoolean(req, "edicao")){
				
				mensagem.setRascunho(false);
				MensagemLocalServiceUtil.updateMensagem(mensagem);
				removerMensagemSession(req);
				
			}
			
			SessionMessages.add(req, "mensagem-gravada-aguardar-workflow");
		}
		catch (PortalException|SystemException|AddressException|UnsupportedEncodingException ex) {
			_log.error("Problemas ao processar agendamento:", ex);
			SessionErrors.add(req, "erro-wizard-agendamento-mensagem");
			GestaoMensagensUtil.descartarRascunhos(req);
			return false;
		}
		
		return true;
	}
	
	private void preencherDadosFormulario(PortletRequest req, Mensagem mensagem) {
		mensagem.setTipoEnvio(ParamUtil.getInteger(req, "tipoEnvio"));
	}
	
	private void processarAgendamento(PortletRequest req, Mensagem mensagem)
			throws PortalException, SystemException {
		
		if (mensagem.getTipoEnvio() == TipoEnvioEnum.IMEDIATO.ordinal()){
			mensagem.setLiteralAgendamento(HTML_LITERAL_AGENDAMENTO_IMEDIATO);
			return;
		}
		
		String literalAgendamento = "";
		
		//transforma a string das datas selecionadas concatenada1s por virgula em array, 
		//para agilizar o processamento posterior
		long[] datasSel = GetterUtil.getLongValues(ParamUtil.getString(req, "datasCalendario").split(","));
		
		Date dataAtualizacao = new Date();
		
		Map<Long, Map<String, Agendamento>> datasHorarios = mensagem.getDatasCalendario();
		
		for (long unixDate : datasSel) {
			//verifica se o objeto ja possui horarios para a data selecionada.
			Map<String, Agendamento> horarios = datasHorarios.get(unixDate);
			
			//inicializar caso necessário
			if (horarios == null) {
				horarios = new TreeMap<>();
				datasHorarios.put(unixDate, horarios);
			}
			
			//preencher o Map com os horarios definidos para cada data na pagina
			String[] horariosParam = ParamUtil.getParameterValues(req, "horario_" + unixDate);
			for (String hora : horariosParam) {
				if (Validator.isNull(hora)) {
					continue;
				}
				
				//verificar se já existe o horário no Map da data
				Agendamento agendamento = horarios.get(hora);
				
				//criar, caso necessario
				if (agendamento == null) {
					agendamento = criarAgendamento(mensagem, TipoAgendamentoEnum.CALENDARIO);
					mensagem.getAgendamentos().add(agendamento);
					horarios.put(hora, agendamento);
				}
				
				//definir valores
				String[] partesHora = hora.split(":");
				Date date = new Date(unixDate);
				//prepara um calendar com a data e horario
				Calendar cal = GregorianCalendar.getInstance();
				cal.setTimeInMillis(date.getTime());
				cal.set(Calendar.HOUR_OF_DAY, Integer.parseInt(partesHora[0]));
				cal.set(Calendar.MINUTE, Integer.parseInt(partesHora[1]));
				
				agendamento.setDataCalendario(date);
				agendamento.setDataInicio(cal.getTime());
				
				literalAgendamento += new SimpleDateFormat("dd/MM/yyyy").format(date) + " - " + 
									  new SimpleDateFormat("HH:mm:ss").format(cal.getTime()) + "<br/>";
				
				
				agendamento.setDataAtualizacao(dataAtualizacao);
				
				agendamento.setNaoExcluir(true);
			}
		}
		mensagem.setLiteralAgendamento(HTML_LITERAL_AGENDAMENTO_AGENDADO + literalAgendamento);
	}
	
	/**
	 * Inicializa uma instancia de {@link Agendamento}.
	 * @param mensagem
	 * @return
	 * @throws PortalException
	 * @throws SystemException
	 */
	private Agendamento criarAgendamento(Mensagem mensagem, TipoAgendamentoEnum tipo)
			throws PortalException, SystemException {
		Agendamento agendamento = AgendamentoLocalServiceUtil.createAgendamento(CounterLocalServiceUtil.increment());
		agendamento.setCompanyId(mensagem.getCompanyId());
		agendamento.setGroupId(mensagem.getGroupId());
		agendamento.setMensagemId(mensagem.getMensagemId());
		agendamento.setTipoAgendamento(tipo.ordinal());
		return agendamento;
	}
	
}
