package com.rjconsultores.ventaboletos.service.impl;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

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.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.zkoss.util.resource.Labels;

import com.rjconsultores.ventaboletos.constantes.Constantes;
import com.rjconsultores.ventaboletos.dao.ConferenciaComissaoDAO;
import com.rjconsultores.ventaboletos.dao.EmpresaDAO;
import com.rjconsultores.ventaboletos.dao.PuntoVentaDAO;
import com.rjconsultores.ventaboletos.entidad.ComEmpConferencia;
import com.rjconsultores.ventaboletos.entidad.Conferencia;
import com.rjconsultores.ventaboletos.entidad.Empresa;
import com.rjconsultores.ventaboletos.entidad.LogConferencia;
import com.rjconsultores.ventaboletos.entidad.PuntoVenta;
import com.rjconsultores.ventaboletos.entidad.PuntoVentaVO;
import com.rjconsultores.ventaboletos.enums.IndStatusBoleto;
import com.rjconsultores.ventaboletos.enums.comissao.BoletoStatusComissao;
import com.rjconsultores.ventaboletos.exception.BusinessException;
import com.rjconsultores.ventaboletos.service.ConferenciaComissaoService;
import com.rjconsultores.ventaboletos.service.ConstanteService;
import com.rjconsultores.ventaboletos.service.EmpresaService;
import com.rjconsultores.ventaboletos.service.PuntoVentaService;
import com.rjconsultores.ventaboletos.utilerias.DateUtil;
import com.rjconsultores.ventaboletos.utilerias.LocaleUtil;
import com.rjconsultores.ventaboletos.utilerias.MoneyHelper;
import com.rjconsultores.ventaboletos.utilerias.SendMail;
import com.rjconsultores.ventaboletos.utilerias.UsuarioLogado;
import com.rjconsultores.ventaboletos.vo.comissao.BoletoComissao;
import com.rjconsultores.ventaboletos.vo.comissao.ConferenciaComissaoVO;
import com.rjconsultores.ventaboletos.vo.comissao.DiaConferenciaComissaoVO;
import com.rjconsultores.ventaboletos.vo.comissao.EtiquetaMalote;
import com.rjconsultores.ventaboletos.vo.comissao.EventosFinanceirosVO;
import com.rjconsultores.ventaboletos.vo.comissao.FormaPagoEventosFinanceirosVO;
import com.rjconsultores.ventaboletos.vo.comissao.FormapagoVO;
import com.rjconsultores.ventaboletos.vo.comissao.LogConferenciaVO;
import com.rjconsultores.ventaboletos.vo.comissao.OcdVO;
import com.rjconsultores.ventaboletos.vo.comissao.ResumoComissao;

@Service("conferenciaComissaoService")
public class ConferenciaComissaoServiceImpl implements ConferenciaComissaoService {

	private static final String SMTP_HOST = "SMTP_HOST";
	private static final String SMTP_USER = "SMTP_USER";
	private static final String SMTP_EMAIL = "SMTP_EMAIL";
	private static final String SMTP_PORT = "SMTP_PORT";
	private static final String SMTP_PASS = "SMTP_PASS";

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

	@Autowired
	private ConferenciaComissaoDAO conferenciaComissaoDAO;

	@Autowired
	private EmpresaDAO empresaDAO;

	@Autowired
	private PuntoVentaDAO puntoVentaDAO;

	@Autowired
	ConstanteService constanteService;
	@Autowired
	private EmpresaService empresaService;
	@Autowired
	private PuntoVentaService puntoVentaService;

	@Override
	public List<Conferencia> obtenerTodos() {
		return conferenciaComissaoDAO.obtenerTodos();
	}

	@Override
	public Conferencia obtenerID(Long id) {
		return conferenciaComissaoDAO.obtenerID(id);
	}

	@Override
	public Conferencia suscribir(Conferencia entidad) {
		entidad.setUsuarioId(UsuarioLogado.getUsuarioLogado().getUsuarioId());
		entidad.setFecmodif(Calendar.getInstance().getTime());
		entidad.setActivo(Boolean.TRUE);
		return conferenciaComissaoDAO.suscribir(entidad);
	}

	@Override
	public Conferencia actualizacion(Conferencia entidad) {
		return conferenciaComissaoDAO.actualizacion(entidad);
	}

	@Override
	public void borrar(Conferencia entidad) {
		entidad.setUsuarioId(UsuarioLogado.getUsuarioLogado().getUsuarioId());
		entidad.setFecmodif(Calendar.getInstance().getTime());
		entidad.setActivo(Boolean.FALSE);
		conferenciaComissaoDAO.borrar(entidad);
	}

	@Override
	public List<ConferenciaComissaoVO> carregarConferenciaComissao(String competencia, Empresa empresa, PuntoVenta puntoVenta, Date dataMovimento, boolean isDesconsideraPtVendaFechados) throws BusinessException {
		return conferenciaComissaoDAO.carregarConferenciaComissao(competencia, empresa, puntoVenta, dataMovimento,  isDesconsideraPtVendaFechados);
	}

	@Override
	public List<ConferenciaComissaoVO> carregarConferenciaComissao(Date dataInicial, Date dataFinal, Empresa empresa, PuntoVenta puntoVenta, Date dataMovimento, boolean isDesconsideraPtVendaFechados) throws BusinessException {
		return conferenciaComissaoDAO.carregarConferenciaComissao(dataInicial, dataFinal, empresa, puntoVenta, dataMovimento, isDesconsideraPtVendaFechados);
	}

	@Override
	public Conferencia confirmarChegadaMalote(Conferencia conferencia) throws BusinessException {
		conferencia.setDatamalote(new Date());
		if (conferencia.getUsuarioId() == null || conferencia.getUsuarioId() < 1) {
			conferencia.setUsuarioMaloteId(UsuarioLogado.getUsuarioLogado().getUsuarioId());
		}
		return conferenciaComissaoDAO.confirmarChegadaMalote(conferencia);
	}

	@Override
	public Conferencia suscribirOrActualizacion(Conferencia entidad) {
		entidad.setUsuarioId(UsuarioLogado.getUsuarioLogado().getUsuarioId());
		entidad.setFecmodif(Calendar.getInstance().getTime());
		entidad.setActivo(Boolean.TRUE);
		return conferenciaComissaoDAO.suscribirOrActualizacion(entidad);
	}

	@Override
	public Conferencia encerrarMovimentoDiario(Conferencia conferencia) throws BusinessException {
		if (conferencia.getUsuarioId() == null || conferencia.getUsuarioId() < 1) {
			conferencia.setUsuarioId(UsuarioLogado.getUsuarioLogado().getUsuarioId());
		}
		conferencia.setFecmodif(Calendar.getInstance().getTime());
		return conferenciaComissaoDAO.encerrarMovimentoDiario(conferencia);
	}

	@Override
	public List<EventosFinanceirosVO> carregarEventosFinanceiros(Conferencia conferencia) throws BusinessException {
		return conferenciaComissaoDAO.carregarEventosFinanceiros(conferencia);
	}

	@Override
	public List<LogConferenciaVO> carregarLogConferencia(Conferencia conferencia) throws BusinessException {
		return conferenciaComissaoDAO.carregarLogConferencia(conferencia);
	}

	@Override
	public LogConferencia suscribirLogConferencia(LogConferencia logConferencia) throws BusinessException {
		return conferenciaComissaoDAO.suscribirLogConferencia(logConferencia);
	}

	@Override
	public void borrarLogConferencia(LogConferencia logConferencia) throws BusinessException {
		conferenciaComissaoDAO.borrarLogConferencia(logConferencia);
	}

	@Override
	public LogConferencia obtenerLogConferenciaID(Long logconferenciaId) {
		return conferenciaComissaoDAO.obtenerLogConferenciaID(logconferenciaId);
	}

	@Override
	public List<BoletoComissao> carregarBilhetesComissao(List<BoletoComissao> boletoComissaos, List<Conferencia> conferencias, BoletoStatusComissao boletoStatusComissao, boolean carregarDadosFaltantes) throws BusinessException {

		List<BoletoComissao> retorno = new ArrayList<BoletoComissao>();
		Boolean retornar = false;

		for (Conferencia c : conferencias) {

			if (retornar) {
				return retorno;
			}

			if (boletoComissaos == null || boletoComissaos.isEmpty()) {
				boletoComissaos = conferenciaComissaoDAO.carregarBilhetesComissao(c, false, false);
			}

			if (boletoStatusComissao == null) {
				retorno.addAll(boletoComissaos);
				boletoComissaos = null;
				continue;
			}

			Empresa empresa = empresaDAO.obtenerID(c.getEmpresa().getEmpresaId());
			ComEmpConferencia comEmpConferencia = null;
			if (empresa.getComEmpConferencias() != null && !empresa.getComEmpConferencias().isEmpty()) {
				comEmpConferencia = empresa.getComEmpConferencias().iterator().next();
			}
			retornar = true;
			switch (boletoStatusComissao) {
			case BOLETOS_VENDIDOS:
				retorno.addAll(carregarBilhetesVendidos(boletoComissaos, comEmpConferencia, carregarDadosFaltantes));
				break;
			case BOLETO_MANUAL:
				retorno.addAll(carregarBilhetesManuais(boletoComissaos, comEmpConferencia));
				break;
			case BOLETO_CANCELADO:
				retorno.addAll(carregarBilhetesCancelados(boletoComissaos, comEmpConferencia, carregarDadosFaltantes));
				break;
			case BOLETO_DEVOLVIDO:
				retorno.addAll(carregarBilhetesDevolvidos(boletoComissaos, StringUtils.isNotBlank(c.getNumfoliosistema()), comEmpConferencia, carregarDadosFaltantes));
				break;
			case GAP_VENDIDOS:
				retorno.addAll(carregarBilhetesGapsVendidos(boletoComissaos, comEmpConferencia));
				break;
			case GAP_CANCELADO:
				retorno.addAll(carregarBilhetesGapCancelados(boletoComissaos, comEmpConferencia));
				break;
			case GAP_DEVOLVIDO:
				retorno.addAll(carregarBilhetesGapDevolvidos(boletoComissaos, comEmpConferencia));
				break;
			default:
				break;
			}
			return retorno;
		}

		return retorno;
	}

	@Override
	public List<BoletoComissao> carregarBilhetesComissao(List<BoletoComissao> boletoComissaos, Conferencia conferencia, BoletoStatusComissao boletoStatusComissao, boolean carregarDadosFaltantes) throws BusinessException {
		if (boletoComissaos == null) {
			boletoComissaos = conferenciaComissaoDAO.carregarBilhetesComissao(conferencia, false, false);
		}

		if (boletoStatusComissao == null) {
			return boletoComissaos;
		}

		Empresa empresa = empresaDAO.obtenerID(conferencia.getEmpresa().getEmpresaId());
		ComEmpConferencia comEmpConferencia = null;
		if (empresa.getComEmpConferencias() != null && !empresa.getComEmpConferencias().isEmpty()) {
			comEmpConferencia = empresa.getComEmpConferencias().iterator().next();
		}

		List<BoletoComissao> retorno = new ArrayList<BoletoComissao>();
		switch (boletoStatusComissao) {
		case BOLETOS_VENDIDOS:
			retorno.addAll(carregarBilhetesVendidos(boletoComissaos, comEmpConferencia, carregarDadosFaltantes));
			break;
		case BOLETO_MANUAL:
			retorno.addAll(carregarBilhetesManuais(boletoComissaos, comEmpConferencia));
			break;
		case BOLETO_CANCELADO:
			retorno.addAll(carregarBilhetesCancelados(boletoComissaos, comEmpConferencia, carregarDadosFaltantes));
			break;
		case BOLETO_DEVOLVIDO:
			retorno.addAll(carregarBilhetesDevolvidos(boletoComissaos, StringUtils.isNotBlank(conferencia.getNumfoliosistema()), comEmpConferencia, carregarDadosFaltantes));
			break;
		case GAP_VENDIDOS:
			retorno.addAll(carregarBilhetesGapsVendidos(boletoComissaos, comEmpConferencia));
			break;
		case GAP_CANCELADO:
			retorno.addAll(carregarBilhetesGapCancelados(boletoComissaos, comEmpConferencia));
			break;
		case GAP_DEVOLVIDO:
			retorno.addAll(carregarBilhetesGapDevolvidos(boletoComissaos, comEmpConferencia));
			break;
		default:
			break;
		}
		return retorno;
	}

	private Set<BoletoComissao> carregarBilhetesManuais(List<BoletoComissao> boletoComissaos, ComEmpConferencia comEmpConferencia) {
		Set<BoletoComissao> boletos = new HashSet<BoletoComissao>();
		for (BoletoComissao boletoComissao : boletoComissaos) {
			if (boletoComissao.isAbaBilheteManual()) {

				if (comEmpConferencia != null) {
					boletoComissao.setExigeConferenciaAba(comEmpConferencia.getIndbilhetemanual());
				}

				boletos.add(boletoComissao);
			}
		}
		return boletos;
	}

	private Set<BoletoComissao> carregarBilhetesVendidos(List<BoletoComissao> boletoComissaos, ComEmpConferencia comEmpConferencia, boolean carregarDadosFaltantes) {
		Set<BoletoComissao> boletos = new HashSet<BoletoComissao>();
		for (BoletoComissao boletoComissao : boletoComissaos) {
			if (boletoComissao.isAbaBilheteVendido() || carregarDadosFaltantes) {

				if (comEmpConferencia != null) {
					boletoComissao.setExigeConferenciaAba(comEmpConferencia.getIndbilhetevendido());
				}
				if (boletoComissao.isQuitacaoOCD()) {
					continue;
				}
				boletos.add(boletoComissao);

			}
		}
		return boletos;
	}

	private Set<BoletoComissao> carregarBilhetesCancelados(List<BoletoComissao> boletoComissaos, ComEmpConferencia comEmpConferencia, boolean carregarDadosFaltantes) {
		Set<BoletoComissao> boletos = new HashSet<BoletoComissao>();
		for (BoletoComissao boletoComissao : boletoComissaos) {
			if (boletoComissao.isAbaBilheteCancelado() || carregarDadosFaltantes) {

				if (comEmpConferencia != null) {
					boletoComissao.setExigeConferenciaAba(comEmpConferencia.getIndbilhetecancelado());
				}

				boletos.add(boletoComissao);

			}
		}
		return boletos;
	}

	private Set<BoletoComissao> carregarBilhetesDevolvidos(List<BoletoComissao> boletoComissaos, boolean pesquisa, ComEmpConferencia comEmpConferencia, boolean carregarDadosFaltantes) {
		Set<BoletoComissao> boletos = new HashSet<BoletoComissao>();
		for (BoletoComissao boletoComissao : boletoComissaos) {
			if (boletoComissao.isAbaBilheteDevolvido() || carregarDadosFaltantes) {

				boletoComissao.setExigeConferenciaDevolvido(boletoComissao.getIndcarboletosdevolvidosconf() != null && !boletoComissao.getIndcarboletosdevolvidosconf());

				if (comEmpConferencia != null) {
					boletoComissao.setExigeConferenciaAba(comEmpConferencia.getIndbilhetedevolvido());
				}

				if (pesquisa ||
						((boletoComissao.getIndcarboletosdevolvidosconf() != null && boletoComissao.getIndcarboletosdevolvidosconf()) || boletoComissao.getLogconferenciaId() != null)) {
					boletos.add(boletoComissao);
				}

			}
		}
		return boletos;
	}

	private Set<BoletoComissao> carregarBilhetesGapsVendidos(List<BoletoComissao> boletoComissaos, ComEmpConferencia comEmpConferencia) {
		Set<BoletoComissao> boletos = new HashSet<BoletoComissao>();
		for (BoletoComissao boletoComissao : boletoComissaos) {
			if (boletoComissao.isAbaGapVendido()) {

				if (comEmpConferencia != null) {
					boletoComissao.setExigeConferenciaAba(comEmpConferencia.getIndgapvendido());
				}

				boletos.add(boletoComissao);

			}
		}
		return boletos;
	}

	private Set<BoletoComissao> carregarBilhetesGapCancelados(List<BoletoComissao> boletoComissaos, ComEmpConferencia comEmpConferencia) {
		Set<BoletoComissao> boletos = new HashSet<BoletoComissao>();
		for (BoletoComissao boletoComissao : boletoComissaos) {
			if (boletoComissao.isAbaGapCancelado()) {

				if (comEmpConferencia != null) {
					boletoComissao.setExigeConferenciaAba(comEmpConferencia.getIndgapcancelado());
				}

				boletos.add(boletoComissao);
			}
		}
		return boletos;
	}

	private Set<BoletoComissao> carregarBilhetesGapDevolvidos(List<BoletoComissao> boletoComissaos, ComEmpConferencia comEmpConferencia) {
		Set<BoletoComissao> boletos = new HashSet<BoletoComissao>();
		for (BoletoComissao boletoComissao : boletoComissaos) {
			if (boletoComissao.isAbaGapDevolvido()) {

				if (comEmpConferencia != null) {
					boletoComissao.setExigeConferenciaAba(comEmpConferencia.getIndgapdevolvido());
				}

				boletos.add(boletoComissao);

			}
		}
		return boletos;
	}

	@Override
	public List<OcdVO> carregarOcds(Conferencia conferencia) throws BusinessException {
		return conferenciaComissaoDAO.carregarOcds(conferencia);
	}

	@Override
	public Conferencia reabrirMovimentoDiario(Conferencia conferencia) throws BusinessException {
		conferencia.setUsuarioId(UsuarioLogado.getUsuarioLogado().getUsuarioId());
		conferencia.setFecmodif(Calendar.getInstance().getTime());
		return conferenciaComissaoDAO.reabrirMovimentoDiario(conferencia);
	}

	@Override
	public Conferencia obtenerConferenciaDataMovimento(Date datamovimento, Integer puntoventaId, Integer empresaId) throws BusinessException {
		return conferenciaComissaoDAO.obtenerConferenciaDataMovimento(datamovimento, puntoventaId, empresaId);
	}

	@Override
	public boolean isBilhetesSemConferencia(List<BoletoComissao> lsBoletoComissao) throws BusinessException {
		for (BoletoComissao boletoComissao : lsBoletoComissao) {
			if ((boletoComissao.isExigeConferencia() || boletoComissao.isExigeConferenciaAba() || boletoComissao.isExigeConferenciaBoletoDevolvido()) &&
					(!boletoComissao.isConferido() && boletoComissao.getLogconferenciaId() == null)) {
				return true;
			}
		}
		return false;
	}

	@Override
	public boolean isEventosFinanceirosSemConferencia(List<EventosFinanceirosVO> lsEventosFinanceiros) throws BusinessException {
		for (EventosFinanceirosVO eventosFinanceiros : lsEventosFinanceiros) {
			if ((eventosFinanceiros.isExigeConferencia() || eventosFinanceiros.getExigeConferenciaAba()) &&
					(!eventosFinanceiros.isConferido() && (eventosFinanceiros.getLogconferenciaId() == null  || eventosFinanceiros.getLogconferenciaId() == 0))) {
				return true;
			}
		}
		return false;
	}

	@Override
	public BigDecimal totalizarBoletoComissao(List<BoletoComissao> lsBoletoComissao, IndStatusBoleto... statusBilhete) throws BusinessException {
		List<IndStatusBoleto> lStatusBilhete = null;
		if (statusBilhete != null && statusBilhete.length > 0) {
			lStatusBilhete = Arrays.asList(statusBilhete);
		}

		BigDecimal total = BigDecimal.ZERO;
		if (lsBoletoComissao != null) {
			for (BoletoComissao boletoComissao : lsBoletoComissao) {
				if (boletoComissao.isNotSomarBilhete()) {
					continue;
				}

				if ((lStatusBilhete == null || lStatusBilhete.contains(boletoComissao.getIndstatusboletoEnum())) &&
						!boletoComissao.isVendaBilheteConfirmaAberto(boletoComissao.getTipoVenta())) {
					// log.info(boletoComissao.toString());
					total = total.add(boletoComissao.getTotal());
				}
			}
		}
		return total;
	}

	@Override
	public Map<BoletoStatusComissao, BigDecimal> totalizarBoletoComissaoDevolvidosTrocaOcd(List<BoletoComissao> lsBoletoComissao) throws BusinessException {
		BigDecimal totalDevolvidos = BigDecimal.ZERO;
		BigDecimal totalTroca = BigDecimal.ZERO;
		BigDecimal totalOcd = BigDecimal.ZERO;
		if (lsBoletoComissao != null) {
			for (BoletoComissao boletoComissao : lsBoletoComissao) {
				if (boletoComissao.isNotSomarBilhete()) {
					continue;
				}
				if (boletoComissao.isOcd()) {
					totalOcd = totalOcd.add(boletoComissao.getTotal());
				} else if (boletoComissao.isMotivocancelacionDevolvido()) {
					totalDevolvidos = totalDevolvidos.add(boletoComissao.getTotal());
				} else if (boletoComissao.isMotivocancelacionTrocado()) {
					totalTroca = totalTroca.add(boletoComissao.getTotal());
				}
			}
		}
		Map<BoletoStatusComissao, BigDecimal> maps = new HashMap<BoletoStatusComissao, BigDecimal>();
		maps.put(BoletoStatusComissao.BOLETO_DEVOLVIDO, totalDevolvidos);
		maps.put(BoletoStatusComissao.BOLETO_DEVOLVIDO_OCD, totalOcd);
		maps.put(BoletoStatusComissao.BOLETO_DEVOLVIDO_TROCADO, totalTroca);
		return maps;
	}

	@Override
	public BigDecimal totalizarEventosFinanceiros(List<EventosFinanceirosVO> lsEventosFinanceiros) throws BusinessException {
		BigDecimal total = BigDecimal.ZERO;
		if (lsEventosFinanceiros != null) {
			for (EventosFinanceirosVO eventosFinanceiros : lsEventosFinanceiros) {
				/* total = total.add(eventosFinanceiros.getImpingreso()); */
				if (eventosFinanceiros.isCredito()) {
					total = MoneyHelper.somar(total, eventosFinanceiros.getImpingreso());
				} else if (eventosFinanceiros.isDebito()) {
					total = MoneyHelper.subtrair(total, eventosFinanceiros.getImpingreso().abs());
				}
			}
		}
		return total;
	}

	@Override
	public OcdVO totalizarOcd(List<OcdVO> lsOcd) throws BusinessException {
		OcdVO total = new OcdVO();
		total.setValorPagar(BigDecimal.ZERO);
		total.setPenalizacion(BigDecimal.ZERO);

		if (lsOcd != null) {
			for (OcdVO ocd : lsOcd) {
				total.setValorPagar(total.getValorPagar().add(ocd.getValorPagar()));
			}
		}
		return total;
	}

	@Override
	public ResumoComissao gerarResumo(Conferencia conferencia, List<BoletoComissao> boletoComissaos, List<EventosFinanceirosVO> lsEventosFinanceiros, BigDecimal totalBilhetesManual, BigDecimal totalBilhetesVendidos,
			BigDecimal totalBilhetesCancelados, BigDecimal totalBilhetesDevolvidos, BigDecimal totalBilhetesGap, BigDecimal totalBilhetesGapCancelados,
			BigDecimal totalBilhetesGapDevolvidos, BigDecimal totalCreditosEventoFinanceiros, BigDecimal totalDebitosEventoFinanceiros, OcdVO totalOcd,
			BigDecimal totalBilhetesTrocados, BigDecimal totalBilhetesGapTrocados) throws BusinessException {
		ResumoComissao resumoComissao = new ResumoComissao();
		resumoComissao.setTotalDevolvidos(totalBilhetesDevolvidos.add(totalBilhetesGapDevolvidos));
		resumoComissao.setTotalCancelados(totalBilhetesCancelados.add(totalBilhetesGapCancelados));
		resumoComissao.setTotalVendas(totalBilhetesVendidos.add(totalBilhetesManual).add(totalBilhetesGap));
		resumoComissao.setTotalReceitas(totalCreditosEventoFinanceiros);
		resumoComissao.setTotalDespesas(totalDebitosEventoFinanceiros);
		resumoComissao.setTotalTroca(totalBilhetesTrocados.add(totalBilhetesGapTrocados));
		resumoComissao.setTotalOcd(totalOcd);

		carregarTotalFormapago(resumoComissao, boletoComissaos, lsEventosFinanceiros);
		carregarTotalDeposito(conferencia, resumoComissao, boletoComissaos, lsEventosFinanceiros);

		resumoComissao.setListNumSerieECF(puntoVentaDAO.quantidadeECFPorPuntoVenta(conferencia));

		return resumoComissao;
	}

	/**
	 * Calcula o total de deposito
	 * @param conferencia 
	 * @param resumoComissao
	 * @param boletoComissaos
	 * @param lsEventosFinanceiros
	 * @return
	 */
	private void carregarTotalDeposito(Conferencia conferencia, ResumoComissao resumoComissao, List<BoletoComissao> boletoComissaos, List<EventosFinanceirosVO> lsEventosFinanceiros) {
		List<Integer> formaspagosDeposito = new ArrayList<Integer>(Arrays.asList(Constantes.FORMA_PAGO_DINHEIRO.intValue()));
		if(conferencia != null && conferenciaComissaoDAO.isConfMovFPTrocaVlrDeposito(conferencia.getEmpresa())) {
			formaspagosDeposito.add(Constantes.FORMA_PAGO_TROCA_PASSAGEM.intValue());
		}

		BigDecimal totalDeposito = BigDecimal.ZERO;

		for (BoletoComissao boletoComissao : boletoComissaos) {
			if (!boletoComissao.isNotSomarBilhete()) {
				for (FormapagoVO formapago : boletoComissao.getFormapagos()) {
					if (formaspagosDeposito.contains(formapago.getFormapagoId())) {
						// subtraindo as quitacoes de ocd
						if (boletoComissao.isMotivocancelacionQuitacaoOcd()) {
							totalDeposito = MoneyHelper.subtrair(totalDeposito, formapago.getImporte());
							// somando as vendas
						} else if (boletoComissao.isAbaBilheteVendido() || boletoComissao.isAbaGapVendido() || boletoComissao.isAbaBilheteManual()) {
							totalDeposito = MoneyHelper.somar(totalDeposito, formapago.getImporte());
							// subtraindo os cancelamentos
						} else if (boletoComissao.isAbaBilheteCancelado() || boletoComissao.isAbaGapCancelado()) {
							totalDeposito = MoneyHelper.subtrair(totalDeposito, formapago.getImporte());
							// subtraindo as trocas e devolucoes
						} else if (boletoComissao.isAbaBilheteDevolvido() || boletoComissao.isAbaGapDevolvido()) {
							if (boletoComissao.isMotivocancelacionTrocado() || boletoComissao.isMotivocancelacionDevolvido()) {
								totalDeposito = MoneyHelper.subtrair(totalDeposito, formapago.getImporte());
							}
						}
					}
				}
			}
		}

		// calculando os movimentos financeiros
		for (EventosFinanceirosVO eventosFinanceiros : lsEventosFinanceiros) {
			for (FormaPagoEventosFinanceirosVO formaPagamento : eventosFinanceiros.getFormapagos()) {
				if (formaspagosDeposito.contains(formaPagamento.getFormapagoId())) {
					if (eventosFinanceiros.isCredito()) {
						totalDeposito = MoneyHelper.somar(totalDeposito, formaPagamento.getImporte());
					} else if (eventosFinanceiros.isDebito()) {
						totalDeposito = MoneyHelper.subtrair(totalDeposito, formaPagamento.getImporte().abs());
					}
				}
			}
		}

		resumoComissao.setValorDeposito(totalDeposito);

	}

	/**
	 * Totaliza os valores conforme o forma pago, apenas do bilhetes que geraram registros em caixa<br>
	 * (+) Abas: Bilhetes Manual, Bilhetes, Gap Venda<br>
	 * (-) Abas: Bilhetes Cancelados, Bilhetes Devolvidos, Gap Cancelados, Gap Devolvidos<br>
	 * 
	 * @param resumoComissao
	 * @param boletoComissaos
	 * @param lsEventosFinanceiros
	 */
	private void carregarTotalFormapago(ResumoComissao resumoComissao, List<BoletoComissao> boletoComissaos, List<EventosFinanceirosVO> lsEventosFinanceiros) {
		List<FormapagoVO> totalFormapagos = new ArrayList<FormapagoVO>();
		for (BoletoComissao boletoComissao : boletoComissaos) {
			if (!boletoComissao.isNotSomarBilhete()) {
				for (FormapagoVO formapagoBoleto : boletoComissao.getFormapagos()) {
					FormapagoVO formapago;
					if (totalFormapagos.contains(formapagoBoleto)) {
						formapago = totalFormapagos.get(totalFormapagos.indexOf(formapagoBoleto));
					} else {
						formapago = new FormapagoVO(formapagoBoleto.getFormapagoId(), formapagoBoleto.getDescpago(), null, BigDecimal.ZERO);
						totalFormapagos.add(formapago);
					}

					// subtraindo as quitacoes de ocd
					if (boletoComissao.isMotivocancelacionQuitacaoOcd()) {
						formapago.subtract(formapagoBoleto.getImporte());
						// somando as vendas
					} else if (boletoComissao.isAbaBilheteVendido() || boletoComissao.isAbaGapVendido() || boletoComissao.isAbaBilheteManual() || (boletoComissao.isVendaBilheteTransferencia(boletoComissao.getTipoVenta()) &&  formapago.getFormapagoId() == 1)) {
						formapago.add(formapagoBoleto.getImporte());
						// subtraindo os cancelamentos
					} else if (boletoComissao.isAbaBilheteCancelado() || boletoComissao.isAbaGapCancelado()) {
						formapago.subtract(formapagoBoleto.getImporte());
						// subtraindo as trocas e devolucoes
					} else if (boletoComissao.isAbaBilheteDevolvido() || boletoComissao.isAbaGapDevolvido() || boletoComissao.isMotivocancelacionTransferido()) {
						if (boletoComissao.isMotivocancelacionTrocado() || boletoComissao.isMotivocancelacionDevolvido() || boletoComissao.isMotivocancelacionQuitacaoOcd() || (boletoComissao.isVendaBilheteTransferencia(boletoComissao.getTipoVenta()) &&  formapago.getFormapagoId() == 1)) {
							formapago.subtract(formapagoBoleto.getImporte());
						}
					}
				}
			}
		}

		for (EventosFinanceirosVO eventosFinanceiros : lsEventosFinanceiros) {
			for(FormaPagoEventosFinanceirosVO formaPagoEventosFinanceirosVO: eventosFinanceiros.getFormapagos()) {
			FormapagoVO formapagoEventoFinanceiro = new FormapagoVO(formaPagoEventosFinanceirosVO.getFormapagoId(), formaPagoEventosFinanceirosVO.getDescpago(), null, BigDecimal.ZERO);
			if (totalFormapagos.contains(formapagoEventoFinanceiro)) {
				formapagoEventoFinanceiro = totalFormapagos.get(totalFormapagos.indexOf(formapagoEventoFinanceiro));
			} else {
				totalFormapagos.add(formapagoEventoFinanceiro);
			}

			if (eventosFinanceiros.isCredito()) {
				formapagoEventoFinanceiro.add(formaPagoEventosFinanceirosVO.getImporte());
			} else if (eventosFinanceiros.isDebito()) {
				formapagoEventoFinanceiro.subtract(formaPagoEventosFinanceirosVO.getImporte().abs());
			}
			}
		}

		resumoComissao.setTotalFormapago(totalFormapagos);
	}

	@Override
	public EtiquetaMalote decodificarEtiquetaMalote(String codigoBarras) throws BusinessException {
		try {
			EtiquetaMalote etiquetaMalote = new EtiquetaMalote();
			log.debug("Empresa: " + codigoBarras.substring(0, 4));
			etiquetaMalote.setEmpresaId(Integer.valueOf(codigoBarras.substring(0, 4)));
			log.debug("Punto Venta: " + codigoBarras.substring(4, 9));
			etiquetaMalote.setPuntoventaId(Integer.valueOf(codigoBarras.substring(4, 9)));
			log.debug("Numero Malote: " + codigoBarras.substring(9, 19));
			etiquetaMalote.setNumeroMalote(codigoBarras.substring(9, 19));
			log.debug("Data inicial: " + codigoBarras.substring(19, 27));
			etiquetaMalote.setDataInicial(DateUtil.getDateFromString(codigoBarras.substring(19, 27), "ddMMyyyy"));
			log.debug("Data final: " + codigoBarras.substring(27, 35));
			etiquetaMalote.setDataFinal(DateUtil.getDateFromString(codigoBarras.substring(27, 35), "ddMMyyyy"));

			Empresa empresa = empresaDAO.obtenerID(etiquetaMalote.getEmpresaId());
			if (empresa == null) {
				throw new BusinessException("recebimentoMaloteController.msg.erro.empresaNaoLocalizada");
			}
			etiquetaMalote.setNombempresa(empresa.getNombempresa());
			PuntoVenta puntoVenta = puntoVentaDAO.obtenerID(etiquetaMalote.getPuntoventaId());
			if (puntoVenta == null) {
				throw new BusinessException("recebimentoMaloteController.msg.erro.puntoVentaNaoLocalizado");
			}
			etiquetaMalote.setNombpuntoventa(puntoVenta.getNombpuntoventa());

			return etiquetaMalote;
		} catch (BusinessException e) {
			log.error(e.getMessage(), e);
			throw e;
		} catch (Exception e) {
			log.error(e.getMessage(), e);
		}

		return null;
	}

	@Override
	public void confirmarChegadaMalote(EtiquetaMalote etiquetaMalote) throws BusinessException {
		try {
			Calendar cDataInicial = Calendar.getInstance(LocaleUtil.getLocale());
			cDataInicial.setTime(DateUtil.normalizar(etiquetaMalote.getDataInicial()));

			Calendar cDataFinal = Calendar.getInstance(LocaleUtil.getLocale());
			cDataFinal.setTime(DateUtil.normalizar(etiquetaMalote.getDataFinal()));

			Empresa empresa = empresaDAO.obtenerID(etiquetaMalote.getEmpresaId());
			PuntoVenta puntoVenta = puntoVentaDAO.obtenerID(etiquetaMalote.getPuntoventaId());

			while (cDataInicial.compareTo(cDataFinal) <= 0) {
				Conferencia conferencia = obtenerConferenciaDataMovimento(cDataInicial.getTime(), etiquetaMalote.getPuntoventaId(), etiquetaMalote.getEmpresaId());
				if (conferencia == null) {
					conferencia = new Conferencia();
					conferencia.setDatamovimento(cDataInicial.getTime());
					conferencia.setEmpresa(empresa);
					conferencia.setPuntoVenta(puntoVenta);

					conferencia = suscribirOrActualizacion(conferencia);
				}
				cDataInicial.add(Calendar.DAY_OF_MONTH, 1);

				if (conferencia != null && conferencia.getIndmaloterecebido()) {
					continue;
				}
				confirmarChegadaMalote(conferencia);

			}

		} catch (BusinessException e) {
			log.error(e.getMessage(), e);
			throw e;
		} catch (Exception e) {
			log.error(e.getMessage(), e);
		}
	}

	@Override
	public boolean isConferenciaCompetenciaEncerrada(String competencia, Empresa empresa, PuntoVenta puntoVenta, boolean isDesconsideraPtVendaFechados) throws BusinessException {
		return conferenciaComissaoDAO.isConferenciaCompetenciaEncerrada(competencia, empresa, puntoVenta, isDesconsideraPtVendaFechados);
	}

	@Override
	public boolean isOcdSemConferencia(List<OcdVO> lsOcd) throws BusinessException {
		for (OcdVO ocd : lsOcd) {
			if (ocd.isExigeConferenciaAba() && (!ocd.isConferido() && ocd.getLogconferenciaId() == null)) {
				return true;
			}
		}
		return false;
	}

	@Override
	public DiaConferenciaComissaoVO carregarConferenciaRegistrada(Date datamovimento, Empresa empresa, PuntoVenta puntoVenta) throws BusinessException {
		return conferenciaComissaoDAO.carregarConferenciaRegistrada(datamovimento, empresa, puntoVenta);
	}

	@Override
	public List<String> quantidadeECFPorPuntoVenta(Conferencia conferencia) {
		return puntoVentaDAO.quantidadeECFPorPuntoVenta(conferencia);
	}

	@Override
	public void enviarEmailIrregularidadeECF(String email, String msg, String assunto) throws Exception {
		SendMail sendMail = new SendMail();
		String host = constanteService.buscarPorNomeConstante(SMTP_HOST).getValorconstante();
		String user = constanteService.buscarPorNomeConstante(SMTP_USER).getValorconstante();
		String emailFrom = constanteService.buscarPorNomeConstante(SMTP_EMAIL).getValorconstante();
		String port = constanteService.buscarPorNomeConstante(SMTP_PORT).getValorconstante();
		String password = constanteService.buscarPorNomeConstante(SMTP_PASS).getValorconstante();

		verificarDadosEmail(Arrays.asList(host, user, emailFrom, port, password));

		sendMail.setSmtpHost(host);
		sendMail.setSmtpUser(user);
		sendMail.setSmtpPassword(password);
		sendMail.setSmtpPort(port);
		sendMail.setEmailFrom(emailFrom);
		sendMail.setEmailTo(email);
		sendMail.setSubject(assunto);
		sendMail.setText(msg);
		sendMail.send();
	}

	private void verificarDadosEmail(List<String> asList) throws Exception {
		for (String s : asList) {
			if (s == null || s.isEmpty()) {
				throw new Exception(Labels.getLabel("informeIrregularidadeController.mail.configuracoes"));
			}
		}
	}

	@Override
	@Transactional(readOnly = true, propagation = Propagation.SUPPORTS)
	public void generacionAutomaticaConferencia() {
		List<PuntoVentaVO> lsPuntoVenta;
		List<ConferenciaComissaoVO> lsConferenciaComissao;
		Conferencia conferencia;
		// Perocorrer todas as empresas cadastradas
		List<Empresa> lsEmpresa = empresaService.obtenerTodos();
		for (Empresa empresa : lsEmpresa) {
			lsPuntoVenta = puntoVentaService.buscaPuntoVentaEmpresaSemECF(empresa);
			for (PuntoVentaVO puntoVentaVO : lsPuntoVenta) {
				try {
					PuntoVenta puntoVenta = new PuntoVenta(puntoVentaVO.getPuntoventaId(), puntoVentaVO.getNombpuntoventa());
					// Busca o Movimento para o dia de ontem, caso não exista aborta para este ponto de venda
					lsConferenciaComissao = carregarConferenciaComissao(null, empresa, puntoVenta, DateUtil.getYesterdayDate(), false);
					if ((CollectionUtils.isEmpty(lsConferenciaComissao)) || (!CollectionUtils.isEmpty(lsConferenciaComissao.get(0).getDias()) && lsConferenciaComissao.get(0).getDias().size() < 1)) {
						log.info("NÃO há conferência para o Ponto de Venda " + puntoVentaVO.getNombpuntoventa() + " da empresa " + empresa.getNombempresa() + " no dia " + DateUtil.getYesterdayDateString());
						continue;
					}

					// Confirma chegada do malote
					conferencia = obtenerConferenciaDataMovimento(DateUtil.getYesterdayDate(), puntoVentaVO.getPuntoventaId(), empresa.getEmpresaId());
					if (conferencia == null) {
						conferencia = new Conferencia();
						conferencia.setActivo(Boolean.TRUE);
						conferencia.setFecmodif(new Date());
						conferencia.setUsuarioId(1);
						conferencia.setEmpresa(empresa);
						conferencia.setPuntoVenta(new PuntoVenta(puntoVentaVO.getPuntoventaId()));
						conferencia.setDatamovimento(DateUtil.getYesterdayDate());
					} else {
						// Se existe a conferência com status conferido para esta empresa e ponto de venda no dia de ontem, aborta.
						if (Boolean.TRUE == conferencia.getIndconferido()) {
							log.info("Já existe conferência com status conferido para o Ponto de Venda " + puntoVentaVO.getNombpuntoventa() + " da empresa " + empresa.getNombempresa() + " no dia " + DateUtil.getYesterdayDateString());
							continue;
						}
					}

					// Valida se existe alguma pendência que impede o fechamento.
					if (!validaConferencia(conferencia)) {
						log.info("NÃO há bilhetes para conferir ou será necessário realizar Conferência Manual para o Ponto de Venda " + puntoVentaVO.getNombpuntoventa() + " da empresa " + empresa.getNombempresa() + " no dia " + DateUtil.getYesterdayDateString());
						continue;
					}

					// Confirma chegada do malote
					conferencia = confirmarChegadaMalote(conferencia);
					log.info("Realizado confirmação de chegada do malote para o Ponto de Venda " + puntoVentaVO.getNombpuntoventa() + " da empresa " + empresa.getNombempresa() + " no dia " + DateUtil.getYesterdayDateString());

					// Encerra Movimento
					encerrarMovimentoDiario(conferencia);
					log.info("Conferência de Movimento para o Ponto de Venda " + puntoVentaVO.getNombpuntoventa() + " da empresa " + empresa.getNombempresa() + " no dia " + DateUtil.getYesterdayDateString() + "realizada com sucesso.");
				} catch (BusinessException e) {
					log.error("Erro ao buscar/validar conferência para o dia " + DateUtil.getYesterdayDateString(), e);
					continue;
				}
			}
		}
	}

	private boolean validaConferencia(Conferencia conferencia) {
		try {

			List<BoletoComissao> boletosComissaos = carregarBilhetesComissao(null, conferencia, null, false);
			if (boletosComissaos == null || CollectionUtils.isEmpty(boletosComissaos)) {
				return false;
			}

			if (!validaBilhetesManual(boletosComissaos, conferencia)) {
				return false;
			}

			if (!validaBilhetesVendidos(boletosComissaos, conferencia)) {
				return false;
			}

			if (!validaBilhetesCancelados(boletosComissaos, conferencia)) {
				return false;
			}

			if (!validaBilhetesDevolvidos(boletosComissaos, conferencia)) {
				return false;
			}

			if (!validaBilhetesGap(boletosComissaos, conferencia)) {
				return false;
			}

			if (!validaBilhetesGapCancelados(boletosComissaos, conferencia)) {
				return false;
			}

			if (!validaBilhetesGapDevolvidos(boletosComissaos, conferencia)) {
				return false;
			}

			if (!validaEventosFinanceiros(boletosComissaos, conferencia)) {
				return false;
			}

			if (!validaOcds(conferencia)) {
				return false;
			}
			return true;
		} catch (BusinessException e) {
			log.error(e.getMessage(), e);
			return false;
		}
	}

	private boolean validaBilhetesManual(List<BoletoComissao> boletosComissaos, Conferencia conferencia) throws BusinessException {
		List<BoletoComissao> lsBilhetesManual = carregarBilhetesComissao(boletosComissaos, conferencia, BoletoStatusComissao.BOLETO_MANUAL, false);
		if (!CollectionUtils.isEmpty(lsBilhetesManual) && isBilhetesSemConferencia(lsBilhetesManual)) {
			return false;
		} else {
			return true;
		}
	}

	private boolean validaBilhetesVendidos(List<BoletoComissao> boletosComissaos, Conferencia conferencia) throws BusinessException {
		List<BoletoComissao> lsBilhetes = carregarBilhetesComissao(boletosComissaos, conferencia, BoletoStatusComissao.BOLETOS_VENDIDOS, false);
		if (!CollectionUtils.isEmpty(lsBilhetes) && isBilhetesSemConferencia(lsBilhetes)) {

			return false;
		} else {
			return true;
		}
	}

	private boolean validaBilhetesCancelados(List<BoletoComissao> boletosComissaos, Conferencia conferencia) throws BusinessException {
		List<BoletoComissao> lsBilhetesCancelados = carregarBilhetesComissao(boletosComissaos, conferencia, BoletoStatusComissao.BOLETO_CANCELADO, false);
		if (!CollectionUtils.isEmpty(lsBilhetesCancelados) && isBilhetesSemConferencia(lsBilhetesCancelados)) {
			return false;
		} else {
			return true;
		}
	}

	private boolean validaBilhetesDevolvidos(List<BoletoComissao> boletosComissaos, Conferencia conferencia) throws BusinessException {
		List<BoletoComissao> lsBilhetesDevolvidos = carregarBilhetesComissao(boletosComissaos, conferencia, BoletoStatusComissao.BOLETO_DEVOLVIDO, false);
		if (!CollectionUtils.isEmpty(lsBilhetesDevolvidos) && isBilhetesSemConferencia(lsBilhetesDevolvidos)) {
			return false;
		} else {
			return true;
		}
	}

	private boolean validaBilhetesGap(List<BoletoComissao> boletosComissaos, Conferencia conferencia) throws BusinessException {
		List<BoletoComissao> lsBilhetesGap = carregarBilhetesComissao(boletosComissaos, conferencia, BoletoStatusComissao.GAP_VENDIDOS, false);
		if (!CollectionUtils.isEmpty(lsBilhetesGap) && isBilhetesSemConferencia(lsBilhetesGap)) {
			return false;
		} else {
			return true;
		}
	}

	private boolean validaBilhetesGapCancelados(List<BoletoComissao> boletosComissaos, Conferencia conferencia) throws BusinessException {
		List<BoletoComissao> lsBilhetesGapCancelados = carregarBilhetesComissao(boletosComissaos, conferencia, BoletoStatusComissao.GAP_CANCELADO, false);
		if (!CollectionUtils.isEmpty(lsBilhetesGapCancelados) && isBilhetesSemConferencia(lsBilhetesGapCancelados)) {
			return false;
		} else {
			return true;
		}
	}

	private boolean validaBilhetesGapDevolvidos(List<BoletoComissao> boletosComissaos, Conferencia conferencia) throws BusinessException {
		List<BoletoComissao> lsBilhetesGapDevolvidos = carregarBilhetesComissao(boletosComissaos, conferencia, BoletoStatusComissao.GAP_DEVOLVIDO, false);
		if (!CollectionUtils.isEmpty(lsBilhetesGapDevolvidos) && isBilhetesSemConferencia(lsBilhetesGapDevolvidos)) {
			return false;
		} else {
			return true;
		}
	}

	private boolean validaEventosFinanceiros(List<BoletoComissao> boletosComissaos, Conferencia conferencia) throws BusinessException {
		List<EventosFinanceirosVO> lsEventosFinanceiros = carregarEventosFinanceiros(conferencia);
		if (!CollectionUtils.isEmpty(lsEventosFinanceiros) && isEventosFinanceirosSemConferencia(lsEventosFinanceiros)) {
			return false;
		} else {
			return true;
		}
	}

	private boolean validaOcds(Conferencia conferencia) throws BusinessException {
		List<OcdVO> lsOcds = carregarOcds(conferencia);
		if (!CollectionUtils.isEmpty(lsOcds) && isOcdSemConferencia(lsOcds)) {
			return false;
		} else {
			return true;
		}
	}

	@Override
	public Conferencia cancelarChegadaMalote(Conferencia conferencia) {
		return conferenciaComissaoDAO.cancelarChegadaMalote(conferencia);
	}

	@Override
	public boolean isConferidoVenta(BoletoComissao boletoComissao) {
		return conferenciaComissaoDAO.isConferidoVenta(boletoComissao);
	}

	@Override
	public void borrarLogConferenciaTransacaoId(Long transacaoId) throws BusinessException {
		conferenciaComissaoDAO.borrarLogConferenciaTransacaoId(transacaoId);
	}

	@Override
	public boolean isConferenciaCompetenciaEncerrada(Date dataInicial, Date dataFinal, Empresa empresa, PuntoVenta puntoVenta, boolean isDesconsideraPtVendaFechados) throws BusinessException {
		return conferenciaComissaoDAO.isConferenciaCompetenciaEncerrada(dataInicial, dataFinal, empresa, puntoVenta, isDesconsideraPtVendaFechados);
	}

	@Override
	public BigDecimal getComissaoPuntoVenta(Integer puntoventaId, Integer empresaId, Date dataInicial, Date dataFinal) throws BusinessException {
		return conferenciaComissaoDAO.getComissaoPuntoVenta(puntoventaId, empresaId, dataInicial, dataFinal);
	}



}
