package br.com.citframework.util;

import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;

import br.com.centralit.citcorpore.bean.ControleSlaDTO;
import br.com.centralit.citcorpore.bean.SolicitacaoServicoDTO;
import br.com.centralit.citcorpore.negocio.ControleSlaServiceEjb;
import br.com.centralit.citcorpore.util.CITCorporeUtil;
import br.com.centralit.citcorpore.util.Enumerados.TipoDate;
import br.com.citframework.integracao.TransactionControler;

/**
 * Classe de testes para validacao do comportamento de
 * {@link ControleSlaServiceEjb}
 * 
 * @author gilberto.nery - <a href=
 *         "mailto:gilberto.nery@centrait.com.br">gilberto.nery@centrait.com.br</a>
 * @since 2016-10-06
 */
@RunWith(value = MockitoJUnitRunner.class)
public class ControleSlaServiceEjbTest {

	@Mock
	private TransactionControler tc;
	private ControleSlaServiceEjb controleSla = new ControleSlaServiceEjb();
	private SolicitacaoServicoDTO solicitacao = new SolicitacaoServicoDTO();
	private List<ControleSlaDTO> listaControleSLA;
	
	@Before
	public void setUp() {
		solicitacao = new SolicitacaoServicoDTO();
		listaControleSLA = new ArrayList<>();
	}

	@BeforeClass
	public static void inserirCalendarioEJornadaComIntervalo() {
		CITCorporeUtil.SGBD_PRINCIPAL = SQLConfig.POSTGRESQL;
		Constantes.setClasseTeste();
	}

	private Integer transformaSegundosEmMinutos(Integer segundos){
		return segundos / 60;
	}
	
	private SolicitacaoServicoDTO solicitacaoServicoDTOFactory(Integer idCalendario, Integer prazoHH, Integer prazoMM, Integer tempoAtendimentoHH, Integer tempoAtendimentoMM){
		solicitacao.setIdCalendario(idCalendario);
		solicitacao.setPrazoHH(prazoHH);
		solicitacao.setPrazoMM(prazoMM);
		solicitacao.setTempoAtendimentoHH(tempoAtendimentoHH);
		solicitacao.setTempoAtendimentoMM(tempoAtendimentoMM);
		
		return solicitacao;
	}
	
	private ControleSlaDTO controleSlaDTOFactory(Timestamp dataHoraInicial, Timestamp dataHoraFinal, double tempoTotal){
		return new ControleSlaDTO(0, 0, 0, dataHoraInicial, dataHoraFinal, 0, 0, tempoTotal);
	}
	
	private List<ControleSlaDTO> listaDeControleDeSlaFactory(){

		listaControleSLA = new ArrayList<>();
		Timestamp dataHoraInicial;
		Timestamp dataHoraFinal;
		
		try{
			dataHoraInicial = UtilDatas.convertStringToTimestamp(TipoDate.TIMESTAMP_WITH_SECONDS, "10/10/2016 14:50:00","PT");
			dataHoraFinal = UtilDatas.convertStringToTimestamp(TipoDate.TIMESTAMP_WITH_SECONDS, "10/10/2016 14:57:00","PT");
			listaControleSLA.add(controleSlaDTOFactory(dataHoraInicial, dataHoraFinal, 420));
			
			dataHoraInicial = UtilDatas.convertStringToTimestamp(TipoDate.TIMESTAMP_WITH_SECONDS, "10/10/2016 15:00:00","PT");
			dataHoraFinal = UtilDatas.convertStringToTimestamp(TipoDate.TIMESTAMP_WITH_SECONDS, "10/10/2016 15:05:00","PT");
			listaControleSLA.add(controleSlaDTOFactory(dataHoraInicial, dataHoraFinal,  300));
			
			dataHoraInicial = UtilDatas.convertStringToTimestamp(TipoDate.TIMESTAMP_WITH_SECONDS, "10/10/2016 15:10:00","PT");
			dataHoraFinal = UtilDatas.convertStringToTimestamp(TipoDate.TIMESTAMP_WITH_SECONDS, "10/10/2016 15:19:00","PT");
			listaControleSLA.add(controleSlaDTOFactory(dataHoraInicial, dataHoraFinal,  540));
			
			dataHoraInicial = UtilDatas.convertStringToTimestamp(TipoDate.TIMESTAMP_WITH_SECONDS, "10/10/2016 16:00:00","PT");
			dataHoraFinal = UtilDatas.convertStringToTimestamp(TipoDate.TIMESTAMP_WITH_SECONDS, "10/10/2016 16:01:00","PT");
			listaControleSLA.add(controleSlaDTOFactory(dataHoraInicial, dataHoraFinal,  60));
			
			dataHoraInicial = UtilDatas.convertStringToTimestamp(TipoDate.TIMESTAMP_WITH_SECONDS, "10/10/2016 16:33:00","PT");
			dataHoraFinal = UtilDatas.convertStringToTimestamp(TipoDate.TIMESTAMP_WITH_SECONDS, "10/10/2016 16:33:00","PT");
			listaControleSLA.add(controleSlaDTOFactory(dataHoraInicial, dataHoraFinal,  0));
			
			dataHoraInicial = UtilDatas.convertStringToTimestamp(TipoDate.TIMESTAMP_WITH_SECONDS, "10/10/2016 17:49:00","PT");
			dataHoraFinal = UtilDatas.convertStringToTimestamp(TipoDate.TIMESTAMP_WITH_SECONDS, "10/10/2016 18:49:00","PT");
			listaControleSLA.add(controleSlaDTOFactory(dataHoraInicial, dataHoraFinal,  3600));
			
			//Levando em consideracao uma jornada de trabalho das 08:00 as 20:00, o termino dessa atividade seria no proximo dia util
			dataHoraInicial = UtilDatas.convertStringToTimestamp(TipoDate.TIMESTAMP_WITH_SECONDS, "10/10/2016 18:50:00","PT");
			dataHoraFinal = UtilDatas.convertStringToTimestamp(TipoDate.TIMESTAMP_WITH_SECONDS, "11/10/2016 08:50:00","PT");
			listaControleSLA.add(controleSlaDTOFactory(dataHoraInicial, dataHoraFinal,  7200));
			
			dataHoraInicial = UtilDatas.convertStringToTimestamp(TipoDate.TIMESTAMP_WITH_SECONDS, "11/10/2016 09:48:00","PT");
			dataHoraFinal = UtilDatas.convertStringToTimestamp(TipoDate.TIMESTAMP_WITH_SECONDS, "11/10/2016 09:51:00","PT");
			listaControleSLA.add(controleSlaDTOFactory(dataHoraInicial, dataHoraFinal,  180));
			
			//Total TA (Tempo de atendimento) = 420 + 300 + 540 + 60 + 0 + 3600 + 7200 + 180 = 12300 = 3,41 HH:MM = 3:25 
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		return listaControleSLA;
	}
	
	@Test
	public void testCalculoTempoAtraso() {
		//SLA Menor que o tempo de atendimento
		solicitacao.setPrazoHH(4);
		solicitacao.setPrazoMM(30);
		solicitacao.setTempoAtendimentoHH(3);
		solicitacao.setTempoAtendimentoMM(59);
		
		Integer tempoAtraso = controleSla.calcularTempoAtraso(solicitacao);
		Assert.assertTrue(transformaSegundosEmMinutos(tempoAtraso).equals(0));
		
		//SlA igual ao tempo de atendimento
		solicitacao = solicitacaoServicoDTOFactory(1, 4, 30, 4, 30);
		tempoAtraso = controleSla.calcularTempoAtraso(solicitacao);
		Assert.assertTrue(transformaSegundosEmMinutos(tempoAtraso).equals(0));
		
		//SLA menor que o tempo de atendimento
		solicitacao.setPrazoHH(5);
		solicitacao.setPrazoMM(20);
		solicitacao.setTempoAtendimentoHH(6);
		solicitacao.setTempoAtendimentoMM(2);
		tempoAtraso = controleSla.calcularTempoAtraso(solicitacao);
		Assert.assertTrue(transformaSegundosEmMinutos(tempoAtraso).equals(42));
		
	}
	
	@Test
	public void testIsSolicitacaoEstaAtrasada() {
		
		solicitacao = solicitacaoServicoDTOFactory(1, 4, 30, 3, 59);
		Assert.assertFalse(controleSla.isSolicitacaoEmAtendimentoAtrasado(solicitacao));
		
		solicitacao = solicitacaoServicoDTOFactory(1, 4, 30, 4, 30);		
		Assert.assertFalse(controleSla.isSolicitacaoEmAtendimentoAtrasado(solicitacao));
		
		solicitacao = solicitacaoServicoDTOFactory(1, 5, 20, 6, 2);
		Assert.assertTrue(controleSla.isSolicitacaoEmAtendimentoAtrasado(solicitacao));

		solicitacao = solicitacaoServicoDTOFactory(1, 500, 0, 0, 0);
		Assert.assertFalse(controleSla.isSolicitacaoEmAtendimentoAtrasado(solicitacao));

		solicitacao = solicitacaoServicoDTOFactory(1, 0, 1, 0, 2);
		Assert.assertTrue(controleSla.isSolicitacaoEmAtendimentoAtrasado(solicitacao));
	}
	
	@Ignore
	public void testRecuperaDataInicioAtrasado() {
		try {
			
			Timestamp dataHoraParametro = UtilDatas.convertStringToTimestamp(TipoDate.TIMESTAMP_WITH_SECONDS, "10/10/2016 14:52:00","PT");
			Timestamp dataHoraInicioDoAtrasoCalculado;
			//SLA = 0:2 / TA = 0:4 / Atraso: 0:2
			solicitacao = solicitacaoServicoDTOFactory(1, 0, 2, 0, 4);
			dataHoraInicioDoAtrasoCalculado = controleSla.recuperarDataHoraLimiteSla(listaDeControleDeSlaFactory(), solicitacao);
			Assert.assertTrue(dataHoraParametro.equals(dataHoraInicioDoAtrasoCalculado));
			
			
			//Solicitacao nao esta atrasada
			dataHoraParametro = UtilDatas.convertStringToTimestamp(TipoDate.TIMESTAMP_WITH_SECONDS, "10/10/2016 15:18:00","PT");
			dataHoraInicioDoAtrasoCalculado = null;
			//SLA = 0:20 / Tempo de atendimento: 0:18
			solicitacao = solicitacaoServicoDTOFactory(1, 0, 20, 0, 18);
			dataHoraInicioDoAtrasoCalculado = controleSla.recuperarDataHoraLimiteSla(listaDeControleDeSlaFactory(), solicitacao);
			Assert.assertTrue(dataHoraParametro.equals(dataHoraInicioDoAtrasoCalculado));
			
			
			//Atrasado
			dataHoraParametro = UtilDatas.convertStringToTimestamp(TipoDate.TIMESTAMP_WITH_SECONDS, "10/10/2016 18:47:00","PT");
			dataHoraInicioDoAtrasoCalculado = null;
			//SLA = 1:20 > TA = 2:4
			solicitacao = solicitacaoServicoDTOFactory(1, 1, 20, 2, 4);
			dataHoraInicioDoAtrasoCalculado = controleSla.recuperarDataHoraLimiteSla(listaDeControleDeSlaFactory(), solicitacao);
			Assert.assertTrue(dataHoraParametro.equals(dataHoraInicioDoAtrasoCalculado));
			
			
			//Atrasado
			dataHoraParametro = UtilDatas.convertStringToTimestamp(TipoDate.TIMESTAMP_WITH_SECONDS, "10/10/2016 18:29:00","PT");
			dataHoraInicioDoAtrasoCalculado = null;
			//SLA = 1:02 > TA = 2:4
			solicitacao = solicitacaoServicoDTOFactory(1, 1, 2, 2, 4);
			dataHoraInicioDoAtrasoCalculado = controleSla.recuperarDataHoraLimiteSla(listaDeControleDeSlaFactory(), solicitacao);
			Assert.assertTrue(dataHoraParametro.equals(dataHoraInicioDoAtrasoCalculado));
			
			
			//SLA muito maior
			dataHoraParametro = UtilDatas.convertStringToTimestamp(TipoDate.TIMESTAMP_WITH_SECONDS, "12/10/2016 10:26:00","PT");
			dataHoraInicioDoAtrasoCalculado = null;
			//SLA = 16:00 > TA = 0:15
			solicitacao = solicitacaoServicoDTOFactory(1, 16, 0, 0, 5);
			dataHoraInicioDoAtrasoCalculado = controleSla.recuperarDataHoraLimiteSla(listaDeControleDeSlaFactory(), solicitacao);
			Assert.assertTrue(dataHoraParametro.equals(dataHoraInicioDoAtrasoCalculado));
			
			
			//Atrasado + 1 dia
			dataHoraParametro = UtilDatas.convertStringToTimestamp(TipoDate.TIMESTAMP_WITH_SECONDS, "11/10/2016 08:03:00","PT");
			dataHoraInicioDoAtrasoCalculado = null;
			//SLA = 2:35 > TA = 2:40
			solicitacao = solicitacaoServicoDTOFactory(1, 2, 35, 2, 40);
			dataHoraInicioDoAtrasoCalculado = controleSla.recuperarDataHoraLimiteSla(listaDeControleDeSlaFactory(), solicitacao);
			Assert.assertTrue(dataHoraParametro.equals(dataHoraInicioDoAtrasoCalculado));
		} catch (Exception e) {
			e.printStackTrace();
			Assert.assertTrue(false);
		}
	}
	
	@After
	public void tearDown(){
		
	}
	
	@AfterClass
	public static void encerrarTeste(){
		
	}
}