package com.rjconsultores.ventaboletos.dao.hibernate;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.hibernate.SQLQuery;
import org.hibernate.SessionFactory;
import org.hibernate.transform.Transformers;
import org.hibernate.type.BigDecimalType;
import org.hibernate.type.BooleanType;
import org.hibernate.type.DateType;
import org.hibernate.type.IntegerType;
import org.hibernate.type.LongType;
import org.hibernate.type.StringType;
import org.hibernate.type.TimestampType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Repository;

import com.rjconsultores.ventaboletos.dao.BusquedaDatosTicketDAO;
import com.rjconsultores.ventaboletos.entidad.Pacote;
import com.rjconsultores.ventaboletos.enums.SituacaoVendaPacote;
import com.rjconsultores.ventaboletos.enums.TipoFormapago;
import com.rjconsultores.ventaboletos.utilerias.OcdUtil;
import com.rjconsultores.ventaboletos.vo.busquedapacotes.ClientePacoteVO;
import com.rjconsultores.ventaboletos.vo.busquedapacotes.DadosBancarioVO;
import com.rjconsultores.ventaboletos.vo.busquedapacotes.EnderecoApanheVO;
import com.rjconsultores.ventaboletos.vo.busquedapacotes.ItemAdicionalVO;
import com.rjconsultores.ventaboletos.vo.busquedapacotes.NotaCreditoVendaPacoteVO;
import com.rjconsultores.ventaboletos.vo.busquedapacotes.OcdPacoteVO;
import com.rjconsultores.ventaboletos.vo.busquedapacotes.PacoteVO;
import com.rjconsultores.ventaboletos.vo.busquedapacotes.PagamentoVO;
import com.rjconsultores.ventaboletos.vo.busquedapacotes.PassageiroVO;
import com.rjconsultores.ventaboletos.vo.busquedapacotes.ServicoVO;
import com.rjconsultores.ventaboletos.vo.busquedapacotes.transformer.DatosClientePacoteResultTransformer;
import com.rjconsultores.ventaboletos.vo.busquedapacotes.transformer.DatosDadosBancarioResultTransformer;
import com.rjconsultores.ventaboletos.vo.busquedapacotes.transformer.DatosEnderecoApanheResultTransformer;
import com.rjconsultores.ventaboletos.vo.busquedapacotes.transformer.DatosItemAdicionalResultTransformer;
import com.rjconsultores.ventaboletos.vo.busquedapacotes.transformer.DatosPassageiroResultTransformer;
import com.rjconsultores.ventaboletos.vo.busquedapacotes.transformer.DatosServicoResultTransformer;
import com.rjconsultores.ventaboletos.vo.busquedapacotes.transformer.DatosTicketResultTransformer;
import com.rjconsultores.ventaboletos.vo.caja.PagamentoCartaoVO;

@Repository("busquedaDatosTicketDAO")
public class BusquedaDatosTicketHibernateDAO extends GenericHibernateDAO<Pacote, Integer> implements BusquedaDatosTicketDAO {

	private static Logger log = LogManager.getLogger(BusquedaDatosTicketHibernateDAO.class);

	@Autowired
	public BusquedaDatosTicketHibernateDAO(@Qualifier("sessionFactory") SessionFactory factory) {
		setSessionFactory(factory);
	}

	@Override
	public List<PacoteVO> buscaDatosTickets(Date fecInicial, Date fecFinal, Date fecVentaInicial, Date fecVentaFinal, Date fecAlteracaoInicial, Date fecAlteracaoFinal) {
		List<PacoteVO> pacotes = new ArrayList<PacoteVO>();

		try {
			pacotes = carregarDadosPacotes(fecInicial, fecFinal, fecVentaInicial, fecVentaFinal, fecAlteracaoInicial, fecAlteracaoFinal);
						
			if (!pacotes.isEmpty()) {
				carregarDadosPagamento(pacotes, fecInicial, fecFinal, fecVentaInicial, fecVentaFinal, fecAlteracaoInicial, fecAlteracaoFinal);
				carregarDadosServico(pacotes, fecInicial, fecFinal, fecVentaInicial, fecVentaFinal, fecAlteracaoInicial, fecAlteracaoFinal);
				carregarDadosPassageiros(pacotes, fecInicial, fecFinal, fecVentaInicial, fecVentaFinal, fecAlteracaoInicial, fecAlteracaoFinal);
				carregarDadosCliente(pacotes, fecInicial, fecFinal, fecVentaInicial, fecVentaFinal, fecAlteracaoInicial, fecAlteracaoFinal);
				carregarDadosEnderecoApanhe(pacotes, fecInicial, fecFinal, fecVentaInicial, fecVentaFinal, fecAlteracaoInicial, fecAlteracaoFinal);
				carregarDadosItemPacotes(pacotes, fecInicial, fecFinal, fecVentaInicial, fecVentaFinal, fecAlteracaoInicial, fecAlteracaoFinal);
			}

		} catch (Exception e) {
			log.error(e.getMessage(), e);
			pacotes.clear();
		}

		return getPacotesFiltradosReserva(pacotes);
	}

	private List<PacoteVO> getPacotesFiltradosReserva(List<PacoteVO> pacotes) {
		List<PacoteVO> retorno = new ArrayList<PacoteVO>();
		for (PacoteVO p : pacotes) {
			if (p.getFormaspagamento() != null && !p.getFormaspagamento().isEmpty()) {
				retorno.add(p);
			}
		}
		return retorno;
	}

	@SuppressWarnings("unchecked")
	private List<PacoteVO> carregarDadosPacotes(Date fecInicial, Date fecFinal, Date fecVentaInicial, Date fecVentaFinal, Date fecAlteracaoInicial, Date fecAlteracaoFinal) {
		StringBuilder sQuery = new StringBuilder();
		sQuery.append("SELECT VP.VENDAPACOTE_ID, VP.DATAPACOTE, VP.DATAVENDA, VP.SUBTOTAL, VP.TOTAL, VP.DESCONTO, VP.NUMOPERACION, P.PACOTE_ID, ")
				.append("P.NOMPACOTE, P.DESCPACOTE, E.NOMBEMPRESA, VP.SITUACAO, PV.NOMBPUNTOVENTA, VP.USUARIO_ID, VP.FECMODIF, VP.DATACANCELAMENTO, ")
				.append("COUNT(TVP.TARIFAVENDAPACOTE_ID) AS QTDEPASSAGEIRO, E.EMPRESA_ID, ")
				.append("SUM(B.PRECIOPAGADO) AS TOTALTARIFA, ")
				.append("SUM(B.IMPORTETAXAEMBARQUE) AS TOTALTAXAEMBARQUE, ")
				.append("SUM(B.IMPORTEPEDAGIO) AS TOTALPEDAGIO, ")
				.append("SUM(B.IMPORTEOUTROS) AS TOTALOUTROS, ")
				.append("SUM(B.IMPORTESEGURO) AS TOTALSEGURO, ")
				.append("VP.INDENCARGOVENTA, ")
				.append("(SELECT COUNT(DISTINCT PFP.PACOTEFORMAPAGO_ID) FROM PACOTE_FORMAPAGO PFP WHERE PFP.VENDAPACOTE_ID = VP.VENDAPACOTE_ID) AS QTDEPACOTEFORMAPAGO ")
				.append("FROM VENDA_PACOTE VP ")
				.append("JOIN PACOTE P ON P.PACOTE_ID = VP.PACOTE_ID ")
				.append("JOIN EMPRESA E ON E.EMPRESA_ID = P.EMPRESA_ID ")
				.append("LEFT JOIN PUNTO_VENTA PV ON PV.PUNTOVENTA_ID = VP.PUNTOVENTA_ID ")
				.append("LEFT JOIN TARIFA_VENDA_PACOTE TVP ON TVP.VENDAPACOTE_ID = VP.VENDAPACOTE_ID ")
				.append("LEFT JOIN BOLETO B ON B.BOLETO_ID = TVP.BOLETO_ID ")
				.append("WHERE (B.BOLETO_ID IS NULL OR B.INDSTATUSBOLETO = 'V') ");

		adicionarFiltros(sQuery, fecInicial, fecFinal, fecVentaInicial, fecVentaFinal, fecAlteracaoInicial, fecAlteracaoFinal);

		sQuery.append("GROUP BY VP.VENDAPACOTE_ID, VP.DATAPACOTE, VP.DATAVENDA, VP.SUBTOTAL, VP.TOTAL, ")
				.append("VP.DESCONTO, VP.NUMOPERACION, P.PACOTE_ID, P.NOMPACOTE, P.DESCPACOTE, E.NOMBEMPRESA, ")
				.append("VP.SITUACAO, PV.NOMBPUNTOVENTA, VP.USUARIO_ID, VP.FECMODIF, VP.DATACANCELAMENTO, E.EMPRESA_ID, VP.INDENCARGOVENTA ");

		SQLQuery query = getSession().createSQLQuery(sQuery.toString())
				.addScalar("VENDAPACOTE_ID", LongType.INSTANCE)
				.addScalar("DATAPACOTE", DateType.INSTANCE)
				.addScalar("DATAVENDA", TimestampType.INSTANCE)
				.addScalar("SUBTOTAL", BigDecimalType.INSTANCE)
				.addScalar("TOTAL", BigDecimalType.INSTANCE)
				.addScalar("DESCONTO", BigDecimalType.INSTANCE)
				.addScalar("NUMOPERACION", StringType.INSTANCE)
				.addScalar("PACOTE_ID", LongType.INSTANCE)
				.addScalar("NOMPACOTE", StringType.INSTANCE)
				.addScalar("DESCPACOTE", StringType.INSTANCE)
				.addScalar("NOMBEMPRESA", StringType.INSTANCE)
				.addScalar("SITUACAO", IntegerType.INSTANCE)
				.addScalar("NOMBPUNTOVENTA", StringType.INSTANCE)
				.addScalar("USUARIO_ID", IntegerType.INSTANCE)
				.addScalar("QTDEPASSAGEIRO", IntegerType.INSTANCE)
				.addScalar("TOTALTARIFA", BigDecimalType.INSTANCE)
				.addScalar("TOTALTAXAEMBARQUE", BigDecimalType.INSTANCE)
				.addScalar("TOTALPEDAGIO", BigDecimalType.INSTANCE)
				.addScalar("TOTALOUTROS", BigDecimalType.INSTANCE)
				.addScalar("TOTALSEGURO", BigDecimalType.INSTANCE)
				.addScalar("QTDEPACOTEFORMAPAGO", IntegerType.INSTANCE)
				.addScalar("FECMODIF", TimestampType.INSTANCE)
				.addScalar("DATACANCELAMENTO", TimestampType.INSTANCE)
				.addScalar("EMPRESA_ID", IntegerType.INSTANCE)
				.addScalar("INDENCARGOVENTA", BooleanType.INSTANCE);

		query.setResultTransformer(new DatosTicketResultTransformer());
		adicionarFiltros(query, fecInicial, fecFinal, fecVentaInicial, fecVentaFinal, fecAlteracaoInicial, fecAlteracaoFinal);

		return query.list();
	}

	@SuppressWarnings("unchecked")
	private void carregarDadosPagamento(List<PacoteVO> pacotes, Date fecInicial, Date fecFinal, Date fecVentaInicial, Date fecVentaFinal, Date fecAlteracaoInicial, Date fecAlteracaoFinal) {
		StringBuilder sQuery = new StringBuilder();
		sQuery.append("SELECT ");
		sQuery.append("PFP.PACOTEFORMAPAGO_ID,");
		sQuery.append("PFP.VALOR,");
		sQuery.append("PFP.VENDAPACOTE_ID,");
		sQuery.append("FP.FORMAPAGO_ID,");
		sQuery.append("FP.DESCPAGO,");
		sQuery.append("NC.NOTACREDITOVENDAPACOTE_ID,");
		sQuery.append("VPC.NUMOPERACION AS NUMOPERACAOPACOTECANCELAMENTO,");
		sQuery.append("FP.TIPO_PAGO,");
		sQuery.append("OCD.OCD_ID,");
		sQuery.append("OCD.NUMOPERACION AS NUMOPERACION_OCD,");
		sQuery.append("CD.CAJADIVERSOS_ID ");

		sQuery.append("FROM PACOTE_FORMAPAGO PFP ");
		sQuery.append("JOIN FORMA_PAGO FP ON FP.FORMAPAGO_ID = PFP.FORMAPAGO_ID ");
		sQuery.append("LEFT JOIN VENDA_PACOTE VP ON VP.VENDAPACOTE_ID = PFP.VENDAPACOTE_ID ");
		sQuery.append("LEFT JOIN NOTA_CREDITO_VENDA_PACOTE NC ON NC.NOTACREDITOVENDAPACOTE_ID = PFP.NOTACREDITOVENDAPACOTE_ID ");
		sQuery.append("LEFT JOIN VENDA_PACOTE VPC ON NC.VENDAPACOTECANCELAMENTO_ID = VPC.VENDAPACOTE_ID ");
		sQuery.append("LEFT JOIN OCD OCD ON OCD.OCD_ID = PFP.OCD_ID ");
		sQuery.append("INNER JOIN CAJA_DIVERSOS CD ON CD.VENDAPACOTE_ID = PFP.VENDAPACOTE_ID ");
	  
		sQuery.append("WHERE 1=1 AND CD.PRECIO >= 0 AND (FP.CVESISTEMA <> 'FORMA_PAGO_RESERVA' OR FP.CVESISTEMA IS NULL) ");

		adicionarFiltros(sQuery, fecInicial, fecFinal, fecVentaInicial, fecVentaFinal, fecAlteracaoInicial, fecAlteracaoFinal);

		sQuery.append("ORDER BY VP.VENDAPACOTE_ID, PFP.PACOTEFORMAPAGO_ID");

		SQLQuery query = getSession().createSQLQuery(sQuery.toString())
				.addScalar("VALOR", BigDecimalType.INSTANCE)
				.addScalar("VENDAPACOTE_ID", LongType.INSTANCE)
				.addScalar("FORMAPAGO_ID", IntegerType.INSTANCE)
				.addScalar("DESCPAGO", StringType.INSTANCE)
				.addScalar("NOTACREDITOVENDAPACOTE_ID", LongType.INSTANCE)
				.addScalar("NUMOPERACAOPACOTECANCELAMENTO", StringType.INSTANCE)
				.addScalar("TIPO_PAGO", IntegerType.INSTANCE)
				.addScalar("OCD_ID", LongType.INSTANCE)
				.addScalar("NUMOPERACION_OCD", StringType.INSTANCE)
				.addScalar("CAJADIVERSOS_ID", LongType.INSTANCE);

		query.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
		adicionarFiltros(query, fecInicial, fecFinal, fecVentaInicial, fecVentaFinal, fecAlteracaoInicial, fecAlteracaoFinal);

		HashMap<Long, List<HashMap<String, Object>>> resultGroupedByCajaDiversos = new HashMap<Long, List<HashMap<String, Object>>>();

		for (HashMap<String, Object> h : (List<HashMap<String, Object>>) query.list()) {
			Long cajaDiversosId = (Long) h.get("CAJADIVERSOS_ID");
			if (!resultGroupedByCajaDiversos.containsKey(cajaDiversosId)) {
				List<HashMap<String, Object>> list = new ArrayList<HashMap<String, Object>>();
				list.add(h);
				resultGroupedByCajaDiversos.put(cajaDiversosId, list);
			} else {
				resultGroupedByCajaDiversos.get(cajaDiversosId).add(h);
			}
		}

		List<PagamentoVO> pagamentos = getResult(resultGroupedByCajaDiversos);

		for (PacoteVO pacote : pacotes) {
			int flag = -1;
			for (PagamentoVO pagamento : pagamentos) {
				if (pagamento.getVendapacoteId().equals(pacote.getVendapacoteId())) {

					flag = 0;
					if (pacote.getFormaspagamento() == null) {
						pacote.setFormaspagamento(new ArrayList<PagamentoVO>());
					}

					if (isPacoteReserva(pacote) && isPagamentoPacoteReserva(pagamento) ||
							(isPagamentoPacoteReserva(pagamento) && pacote.getQtdePacoteFormaspago() == 1) ||
							(!isPacoteReserva(pacote) && !isPagamentoPacoteReserva(pagamento))) {
						pacote.getFormaspagamento().add(pagamento);
					}

					if (isPagamentoDeposito(pagamento)) {
						carregarDadosDeposito(pacote, pagamento);
					}
				} else if (flag == 0) {
					break;
				}

			}
		}
	}

	@SuppressWarnings("unchecked")
	private List<PagamentoVO> getResult(HashMap<Long, List<HashMap<String, Object>>> firstResult) {

		StringBuilder sQuery = new StringBuilder();

		sQuery.append("SELECT CDP.CAJADIVERSOSPAGO_ID, ");
		sQuery.append("CT.TIPOTARJETA, ");
		sQuery.append("CT.NUMAUTORIZACION, ");
		sQuery.append("CT.CANTPARCELAS, ");
		sQuery.append("CT.NOMBTITULAR, ");
		sQuery.append("CT.FECOPERACION, ");
		sQuery.append("CT.NUMTARJETA, ");
		sQuery.append("CT.DESCOPERADORACARTAO, ");
		sQuery.append("CDP.CAJADIVERSOS_ID ");
		sQuery.append("FROM CAJA_DIVERSOS_PAGO CDP ");
		sQuery.append("LEFT JOIN CAJA_TARJETA CT ON CT.CAJATARJETA_ID = CDP.CAJATARJETA_ID ");
		sQuery.append("WHERE CDP.CAJADIVERSOS_ID IN (:cajaDiversosId) ");
		sQuery.append("ORDER BY CDP.CAJADIVERSOS_ID, CDP.CAJADIVERSOSPAGO_ID ");

		SQLQuery query = getSession().createSQLQuery(sQuery.toString())
				.addScalar("CAJADIVERSOSPAGO_ID", LongType.INSTANCE)
				.addScalar("TIPOTARJETA", StringType.INSTANCE)
				.addScalar("NUMAUTORIZACION", StringType.INSTANCE)
				.addScalar("CANTPARCELAS", IntegerType.INSTANCE)
				.addScalar("NOMBTITULAR", StringType.INSTANCE)
				.addScalar("FECOPERACION", DateType.INSTANCE)
				.addScalar("NUMTARJETA", StringType.INSTANCE)
				.addScalar("DESCOPERADORACARTAO", StringType.INSTANCE)
				.addScalar("CAJADIVERSOS_ID", LongType.INSTANCE);

		query.setParameterList("cajaDiversosId", firstResult.keySet());

		query.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);

		List<HashMap<String, Object>> secondResult = query.list();
		int count = 0;

		for (Long cajaDiversosId : firstResult.keySet()) {
			count = 0;
			for (HashMap<String, Object> s : secondResult) {
				if (cajaDiversosId.equals(s.get("CAJADIVERSOS_ID"))) {
					try{
						firstResult.get(cajaDiversosId).get(count).putAll(s);
					}catch(Exception ex){
						log.info("***info> cajaDiversosId: " + cajaDiversosId + ", verificar reserva");
					}
					count++;
				}
			}
		}

		List<PagamentoVO> pagamentos = new ArrayList<PagamentoVO>();
		List<HashMap<String, Object>> dadosExtraidos = new ArrayList<HashMap<String, Object>>();

		for (Long cajaDiversosId : firstResult.keySet()) {
			dadosExtraidos.addAll(firstResult.get(cajaDiversosId));
		}

		for (HashMap<String, Object> m : dadosExtraidos) {
			PagamentoVO pagamento = new PagamentoVO();
			setDatosPacote(pagamento, m);
			pagamentos.add(pagamento);
		}

		return pagamentos;
	}

	private void setDatosPacote(PagamentoVO pagamento, Map<String, Object> tupleMap) {
		pagamento.setMoeda("R$");
		pagamento.setVendapacoteId((Long) tupleMap.get("VENDAPACOTE_ID"));
		pagamento.setFormapagoId((Integer) tupleMap.get("FORMAPAGO_ID"));
		pagamento.setFormapagamento((String) tupleMap.get("DESCPAGO"));
		pagamento.setValor((BigDecimal) tupleMap.get("VALOR"));

		Integer tipoPago = (Integer) tupleMap.get("TIPO_PAGO");
		pagamento.setTipoFormapago(TipoFormapago.getTipoFormapagoByValor(tipoPago));

		if (isVentaCartaoCredito(pagamento.getTipoFormapago()) || isVentaCartaoDebito(pagamento.getTipoFormapago())) {
			PagamentoCartaoVO cartao = new PagamentoCartaoVO();
			cartao.setBandeira((String) tupleMap.get("TIPOTARJETA"));
			cartao.setNumautorizacao((String) tupleMap.get("NUMAUTORIZACION"));
			cartao.setParcelas((Integer) tupleMap.get("CANTPARCELAS"));
			cartao.setTitular((String) tupleMap.get("NOMBTITULAR"));
			cartao.setDatapagamento((Date) tupleMap.get("FECOPERACION"));
			cartao.setNumcartao((String) tupleMap.get("NUMTARJETA"));
			cartao.setNumcartao((String) tupleMap.get("NUMTARJETA"));
			cartao.setOperadoracartao((String) tupleMap.get("DESCOPERADORACARTAO"));

			pagamento.setCartao(cartao);
		}

		if (isVentaNotaCredito(pagamento.getTipoFormapago())) {
			if (tupleMap.get("NOTACREDITOVENDAPACOTE_ID") != null) {
				NotaCreditoVendaPacoteVO notacredito = new NotaCreditoVendaPacoteVO();
				notacredito.setVouchernotacredito(((Long) tupleMap.get("NOTACREDITOVENDAPACOTE_ID")).toString());
				notacredito.setNumoperacaopacotecancelamento((String) tupleMap.get("NUMOPERACAOPACOTECANCELAMENTO"));
				pagamento.setNotacredito(notacredito);
			}

			if (tupleMap.get("OCD_ID") != null) {
				String voucherocd = OcdUtil.generaLocalizadorOCD((String) tupleMap.get("NUMOPERACION_OCD"), (Long) tupleMap.get("OCD_ID"));
				OcdPacoteVO ocdPacote = new OcdPacoteVO();
				ocdPacote.setVoucherocd(voucherocd);
				pagamento.setOcd(ocdPacote);
			}
		}

	}

	private boolean isVentaCartaoCredito(TipoFormapago tipoFormapago) {
		return TipoFormapago.CREDITO.equals(tipoFormapago);
	}

	private boolean isVentaCartaoDebito(TipoFormapago tipoFormapago) {
		return TipoFormapago.DEBITO.equals(tipoFormapago);
	}

	private boolean isVentaNotaCredito(TipoFormapago tipoFormapago) {
		return TipoFormapago.NOTA_CREDITO.equals(tipoFormapago);
	}

	/**
	 * Adiciona os filtros na query
	 * 
	 * @param query
	 * @param fecInicial
	 * @param fecFinal
	 * @param fecVentaInicial
	 * @param fecVentaFinal
	 * @param fecAlteracaoInicial
	 * @param fecAlteracaoFinal
	 */
	private void adicionarFiltros(SQLQuery query, Date fecInicial, Date fecFinal, Date fecVentaInicial, Date fecVentaFinal, Date fecAlteracaoInicial, Date fecAlteracaoFinal) {
		query.setParameter("situacaoPacote", SituacaoVendaPacote.RESERVA.getShortValue());

		if (fecInicial != null) {
			query.setParameter("fecInicial", fecInicial, DateType.INSTANCE);
		}
		if (fecFinal != null) {
			query.setParameter("fecFinal", fecFinal, DateType.INSTANCE);
		}

		if (fecVentaInicial != null) {
			query.setParameter("fecVentaInicial", fecVentaInicial, TimestampType.INSTANCE);
		}
		if (fecVentaFinal != null) {
			query.setParameter("fecVentaFinal", fecVentaFinal, TimestampType.INSTANCE);
		}

		if (fecAlteracaoInicial != null) {
			query.setParameter("fecAlteracaoInicial", fecAlteracaoInicial, TimestampType.INSTANCE);
		}
		if (fecAlteracaoFinal != null) {
			query.setParameter("fecAlteracaoFinal", fecAlteracaoFinal, TimestampType.INSTANCE);
		}
	}

	private void adicionarFiltros(StringBuilder sQuery, Date fecInicial, Date fecFinal, Date fecVentaInicial, Date fecVentaFinal, Date fecAlteracaoInicial, Date fecAlteracaoFinal) {

		sQuery.append("AND VP.SITUACAO != :situacaoPacote ");

		if (fecInicial != null) {
			sQuery.append("AND VP.DATAPACOTE >= :fecInicial ");
		}
		if (fecFinal != null) {
			sQuery.append("AND VP.DATAPACOTE <= :fecFinal ");
		}

		if (fecVentaInicial != null) {
			sQuery.append("AND VP.DATAVENDA >= :fecVentaInicial ");
		}
		if (fecVentaFinal != null) {
			sQuery.append("AND VP.DATAVENDA <= :fecVentaFinal ");
		}

		if (fecAlteracaoInicial != null) {
			sQuery.append("AND VP.FECMODIF >= :fecAlteracaoInicial ");
		}
		if (fecAlteracaoFinal != null) {
			sQuery.append("AND VP.FECMODIF <= :fecAlteracaoFinal ");
		}

	}

	private boolean isPagamentoDeposito(PagamentoVO pagamento) {
		return TipoFormapago.DEPOSITO.equals(pagamento.getTipoFormapago());
	}

	private boolean isPacoteReserva(PacoteVO pacote) {
		return SituacaoVendaPacote.RESERVA.toString().equals(pacote.getStatus());
	}

	private boolean isPagamentoPacoteReserva(PagamentoVO pagamento) {
		return TipoFormapago.RESERVA.equals(pagamento.getTipoFormapago());
	}

	@SuppressWarnings("unchecked")
	private void carregarDadosServico(List<PacoteVO> pacotes, Date fecInicial, Date fecFinal, Date fecVentaInicial, Date fecVentaFinal, Date fecAlteracaoInicial, Date fecAlteracaoFinal) {
		StringBuilder sQuery = new StringBuilder();
		sQuery.append("SELECT DISTINCT VP.VENDAPACOTE_ID, B.FECHORVIAJE, B.ORIGEN_ID, CONCAT(CONCAT(ORI.CVEPARADA,' - '),ORI.DESCPARADA) AS ORIGEM, CONCAT(CONCAT(DES.CVEPARADA,' - '),DES.DESCPARADA) AS DESTINO ")
				.append("FROM VENDA_PACOTE VP ")
				.append("JOIN PACOTE P ON P.PACOTE_ID = VP.PACOTE_ID ")
				.append("JOIN TARIFA_VENDA_PACOTE TVP ON TVP.VENDAPACOTE_ID = VP.VENDAPACOTE_ID ")
				.append("JOIN BOLETO B ON B.BOLETO_ID = TVP.BOLETO_ID ")
				.append("JOIN PARADA ORI ON ORI.PARADA_ID = B.ORIGEN_ID ")
				.append("JOIN PARADA DES ON DES.PARADA_ID = B.DESTINO_ID ")
				.append("WHERE 1=1 ");

		adicionarFiltros(sQuery, fecInicial, fecFinal, fecVentaInicial, fecVentaFinal, fecAlteracaoInicial, fecAlteracaoFinal);

		SQLQuery query = getSession().createSQLQuery(sQuery.toString())
				.addScalar("VENDAPACOTE_ID", LongType.INSTANCE)
				.addScalar("FECHORVIAJE", TimestampType.INSTANCE)
				.addScalar("ORIGEN_ID", IntegerType.INSTANCE)
				.addScalar("ORIGEM", StringType.INSTANCE)
				.addScalar("DESTINO", StringType.INSTANCE);

		query.setResultTransformer(new DatosServicoResultTransformer());
		adicionarFiltros(query, fecInicial, fecFinal, fecVentaInicial, fecVentaFinal, fecAlteracaoInicial, fecAlteracaoFinal);

		List<ServicoVO> servicos = query.list();
		for (PacoteVO pacote : pacotes) {
			for (ServicoVO servico : servicos) {
				if (servico.getVendapacoteId().equals(pacote.getVendapacoteId())) {
					pacote.setServico(servico);
					break;
				}
			}
		}
	}

	@SuppressWarnings("unchecked")
	private void carregarDadosCliente(List<PacoteVO> pacotes, Date fecInicial, Date fecFinal, Date fecVentaInicial, Date fecVentaFinal, Date fecAlteracaoInicial, Date fecAlteracaoFinal) {
		StringBuilder sQuery = new StringBuilder();
		sQuery.append("SELECT VP.VENDAPACOTE_ID, C.NOMBCLIENTE, C.APELLIDOPATERNO, C.APELLIDOMATERNO, C.NUMTELEFONO, C.DESCCORREO, C.NUMIDENTIFICAUNO, ")
				.append("CD.DESCCALLE, CD.DESCCALLECOMP, CD.DESCCOLONIA, CD.DESCIUDAD, CD.NUMINTERIOR, CD.CODPOSTAL, CD.DESESTADO ")
				.append("FROM CLIENTE C ")
				.append("JOIN VENDA_PACOTE VP ON VP.CLIENTE_ID = C.CLIENTE_ID ")
				.append("LEFT JOIN CLIENTE_DIRECCION CD ON CD.CLIENTE_ID = C.CLIENTE_ID ")
				.append("WHERE 1=1 ");

		adicionarFiltros(sQuery, fecInicial, fecFinal, fecVentaInicial, fecVentaFinal, fecAlteracaoInicial, fecAlteracaoFinal);

		SQLQuery query = getSession().createSQLQuery(sQuery.toString())
				.addScalar("VENDAPACOTE_ID", LongType.INSTANCE)
				.addScalar("NOMBCLIENTE", StringType.INSTANCE)
				.addScalar("APELLIDOPATERNO", StringType.INSTANCE)
				.addScalar("APELLIDOMATERNO", StringType.INSTANCE)
				.addScalar("NUMIDENTIFICAUNO", StringType.INSTANCE)
				.addScalar("DESCCORREO", StringType.INSTANCE)
				.addScalar("NUMTELEFONO", StringType.INSTANCE)
				.addScalar("CODPOSTAL", StringType.INSTANCE)
				.addScalar("DESCCALLE", StringType.INSTANCE)
				.addScalar("NUMINTERIOR", StringType.INSTANCE)
				.addScalar("DESCCALLECOMP", StringType.INSTANCE)
				.addScalar("DESESTADO", StringType.INSTANCE)
				.addScalar("DESCIUDAD", StringType.INSTANCE)
				.addScalar("DESCCOLONIA", StringType.INSTANCE);

		query.setResultTransformer(new DatosClientePacoteResultTransformer());
		adicionarFiltros(query, fecInicial, fecFinal, fecVentaInicial, fecVentaFinal, fecAlteracaoInicial, fecAlteracaoFinal);

		List<ClientePacoteVO> clientesPacotes = query.list();
		for (PacoteVO pacote : pacotes) {
			for (ClientePacoteVO clientePacote : clientesPacotes) {
				if (clientePacote.getVendapacoteId().equals(pacote.getVendapacoteId())) {
					pacote.setClientePacote(clientePacote);
				}
			}
		}
	}

	@SuppressWarnings("unchecked")
	private void carregarDadosPassageiros(List<PacoteVO> pacotes, Date fecInicial, Date fecFinal, Date fecVentaInicial, Date fecVentaFinal, Date fecAlteracaoInicial, Date fecAlteracaoFinal) {
		StringBuilder sQuery = new StringBuilder();
		sQuery.append("SELECT DISTINCT VP.VENDAPACOTE_ID, TVP.TARIFAVENDAPACOTE_ID, TVP.NOMEPASSAGEIRO, CONCAT(CONCAT(TVP.TIPODOC,' - '), TVP.DOCUMENTO) AS DOCUMENTO, B.NUMASIENTO, C.CATEGORIA_ID, C.DESCCATEGORIA, B.BOLETO_ID,C.CVECATEGORIA ")
				.append("FROM VENDA_PACOTE VP ")
				.append("JOIN TARIFA_VENDA_PACOTE TVP ON TVP.VENDAPACOTE_ID = VP.VENDAPACOTE_ID ")
				.append("LEFT JOIN BOLETO B ON B.BOLETO_ID = TVP.BOLETO_ID ")
				.append("LEFT JOIN CATEGORIA C ON C.CATEGORIA_ID = B.CATEGORIA_ID ")
				.append("WHERE 1=1 ");

		adicionarFiltros(sQuery, fecInicial, fecFinal, fecVentaInicial, fecVentaFinal, fecAlteracaoInicial, fecAlteracaoFinal);

		SQLQuery query = getSession().createSQLQuery(sQuery.toString())
				.addScalar("VENDAPACOTE_ID", LongType.INSTANCE)
				.addScalar("BOLETO_ID", LongType.INSTANCE)
				.addScalar("TARIFAVENDAPACOTE_ID", LongType.INSTANCE)
				.addScalar("NOMEPASSAGEIRO", StringType.INSTANCE)
				.addScalar("DOCUMENTO", StringType.INSTANCE)
				.addScalar("NUMASIENTO", StringType.INSTANCE)
				.addScalar("CATEGORIA_ID", IntegerType.INSTANCE)
				.addScalar("CVECATEGORIA", StringType.INSTANCE)
				.addScalar("DESCCATEGORIA", StringType.INSTANCE);

		query.setResultTransformer(new DatosPassageiroResultTransformer());
		adicionarFiltros(query, fecInicial, fecFinal, fecVentaInicial, fecVentaFinal, fecAlteracaoInicial, fecAlteracaoFinal);

		List<PassageiroVO> passageiros = query.list();
		for (PacoteVO pacote : pacotes) {
			for (PassageiroVO passageiro : passageiros) {
				if (passageiro.getVendapacoteId().equals(pacote.getVendapacoteId())) {
					if (pacote.getPax() == null) {
						pacote.setPax(new ArrayList<PassageiroVO>());
					}
					pacote.getPax().add(passageiro);
				}
			}
		}
	}

	@SuppressWarnings("unchecked")
	private void carregarDadosEnderecoApanhe(List<PacoteVO> pacotes, Date fecInicial, Date fecFinal, Date fecVentaInicial, Date fecVentaFinal, Date fecAlteracaoInicial, Date fecAlteracaoFinal) {
		StringBuilder sQuery = new StringBuilder();
		sQuery.append("SELECT DISTINCT VP.VENDAPACOTE_ID, EA.LOCAL, EA.DESCHOTEL, EA.CEP, EA.ENDERECO, EA.NUMERO, EA.COMPLEMENTO, EA.CIDADE, EA.BAIRRO, EA.REFERENCIA ")
				.append("FROM ENDERECO_APANHE EA ")
				.append("JOIN VENDA_PACOTE VP ON EA.VENDAPACOTE_ID = VP.VENDAPACOTE_ID ")
				.append("WHERE EA.ACTIVO = 1 ");

		adicionarFiltros(sQuery, fecInicial, fecFinal, fecVentaInicial, fecVentaFinal, fecAlteracaoInicial, fecAlteracaoFinal);

		SQLQuery query = getSession().createSQLQuery(sQuery.toString())
				.addScalar("VENDAPACOTE_ID", LongType.INSTANCE)
				.addScalar("LOCAL", IntegerType.INSTANCE)
				.addScalar("CEP", StringType.INSTANCE)
				.addScalar("ENDERECO", StringType.INSTANCE)
				.addScalar("NUMERO", StringType.INSTANCE)
				.addScalar("COMPLEMENTO", StringType.INSTANCE)
				.addScalar("CIDADE", StringType.INSTANCE)
				.addScalar("BAIRRO", StringType.INSTANCE)
				.addScalar("REFERENCIA", StringType.INSTANCE)
				.addScalar("DESCHOTEL", StringType.INSTANCE);

		query.setResultTransformer(new DatosEnderecoApanheResultTransformer());
		adicionarFiltros(query, fecInicial, fecFinal, fecVentaInicial, fecVentaFinal, fecAlteracaoInicial, fecAlteracaoFinal);

		List<EnderecoApanheVO> enderecosApanhe = query.list();
		for (PacoteVO pacote : pacotes) {
			for (EnderecoApanheVO enderecoApanhe : enderecosApanhe) {
				if (enderecoApanhe.getVendapacoteId().equals(pacote.getVendapacoteId())) {
					pacote.setEnderecoApanhe(enderecoApanhe);
				}
			}
		}
	}

	@SuppressWarnings("unchecked")
	private void carregarDadosItemPacotes(List<PacoteVO> pacotes, Date fecInicial, Date fecFinal, Date fecVentaInicial, Date fecVentaFinal, Date fecAlteracaoInicial, Date fecAlteracaoFinal) {
		StringBuilder sQuery = new StringBuilder();
		sQuery.append("SELECT DISTINCT IA.DESCITEMADICIONAL, VP.VENDAPACOTE_ID, PI.ITEMADICIONAL_ID ")
				.append("FROM ITEM_ADICIONAL IA ")
				.append("JOIN PACOTE_ITEM PI ON IA.ITEMADICIONAL_ID = PI.ITEMADICIONAL_ID ")
				.append("JOIN PACOTE P ON P.PACOTE_ID = PI.PACOTE_ID ")
				.append("JOIN VENDA_PACOTE VP ON VP.PACOTE_ID = P.PACOTE_ID ")
				.append("WHERE IA.ACTIVO = 1 ");

		adicionarFiltros(sQuery, fecInicial, fecFinal, fecVentaInicial, fecVentaFinal, fecAlteracaoInicial, fecAlteracaoFinal);

		SQLQuery query = getSession().createSQLQuery(sQuery.toString())
				.addScalar("DESCITEMADICIONAL", StringType.INSTANCE)
				.addScalar("VENDAPACOTE_ID", LongType.INSTANCE)
				.addScalar("ITEMADICIONAL_ID", LongType.INSTANCE);

		query.setResultTransformer(new DatosItemAdicionalResultTransformer());
		adicionarFiltros(query, fecInicial, fecFinal, fecVentaInicial, fecVentaFinal, fecAlteracaoInicial, fecAlteracaoFinal);

		List<ItemAdicionalVO> itens = query.list();
		for (PacoteVO pacote : pacotes) {
			for (ItemAdicionalVO itemAdicional : itens) {
				if (itemAdicional.getVendapacoteId().equals(pacote.getVendapacoteId())) {
					if (pacote.getItens() == null) {
						pacote.setItens(new ArrayList<ItemAdicionalVO>());
					}
					pacote.getItens().add(itemAdicional);
				}
			}
		}
	}

	@SuppressWarnings("unchecked")
	private void carregarDadosDeposito(PacoteVO pacote, PagamentoVO pagamento) {
		StringBuilder sQuery = new StringBuilder();
		sQuery.append("SELECT CDDP.IDENTIFICACAO_DEPOSITO, CDDP.IMPORTE, CDDP.FECDEPOSITO ")
				.append("FROM CAJA_DET_DEPOSITO_PAGO CDDP ")
				.append("JOIN CAJA_DIVERSOS_PAGO CDP ON CDP.CAJADIVERSOSPAGO_ID = CDDP.CAJADIVERSOSPAGO_ID ")
				.append("JOIN CAJA_DIVERSOS CD ON CD.CAJADIVERSOS_ID = CDP.CAJADIVERSOS_ID ")
				.append("WHERE CDDP.ACTIVO = 1 ")
				.append("AND CD.VENDAPACOTE_ID = :vendapacoteId ")
				.append("AND CDP.FORMAPAGO_ID = :formapagoId ");

		SQLQuery query = getSession().createSQLQuery(sQuery.toString())
				.addScalar("IDENTIFICACAO_DEPOSITO", StringType.INSTANCE)
				.addScalar("IMPORTE", BigDecimalType.INSTANCE)
				.addScalar("FECDEPOSITO", DateType.INSTANCE);

		query.setResultTransformer(new DatosDadosBancarioResultTransformer());
		query.setParameter("vendapacoteId", pacote.getVendapacoteId());
		query.setParameter("formapagoId", pagamento.getFormapagoId());

		List<DadosBancarioVO> dadosBancarios = query.list();
		if (dadosBancarios != null && !dadosBancarios.isEmpty()) {
			pagamento.setDadosBancarios(dadosBancarios);
		}
	}

}
