package com.rjconsultores.ventaboletos.relatorios.impl;

import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import com.rjconsultores.ventaboletos.constantes.Constantes;
import com.rjconsultores.ventaboletos.entidad.PuntoVenta;
import com.rjconsultores.ventaboletos.relatorios.utilitarios.DataSource;
import com.rjconsultores.ventaboletos.relatorios.utilitarios.Relatorio;
import com.rjconsultores.ventaboletos.relatorios.utilitarios.RelatorioVendasComissaoBean;
import com.rjconsultores.ventaboletos.relatorios.utilitarios.RelatorioVendasComissaoCancelamentoBean;
import com.rjconsultores.ventaboletos.web.utilerias.NamedParameterStatement;

import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;

public class RelatorioVendasComissaoEstavel extends Relatorio {
	
	private static Logger log = LogManager.getLogger(RelatorioVendasComissaoEstavel.class);

	private List<RelatorioVendasComissaoBean> lsDadosRelatorio;
	private List<RelatorioVendasComissaoCancelamentoBean> lsDadosRelatorioCancelamento;
	
	private Timestamp fecInicio;
	private Timestamp fecFinal;
	private Integer empresaId;
	private Boolean apenasCancelados;
	private String stringLsPuntoVentaId;
	
	public RelatorioVendasComissaoEstavel(Map<String, Object> parametros, Connection conexao) throws Exception {
		super(parametros, conexao);
		
		this.setCustomDataSource(new DataSource(this) {

			@SuppressWarnings("unchecked")
			@Override
			public void initDados() throws Exception {
				Map<String, Object> parametros = this.relatorio.getParametros();
				fecInicio = (Timestamp) parametros.get("dataFiltroInicial");
				fecFinal = (Timestamp) parametros.get("dataFiltroFinal");
				if(parametros.get("EMPRESA_ID")!=null){
					empresaId =  Integer.valueOf(parametros.get("EMPRESA_ID").toString());
				}
				apenasCancelados = (Boolean) parametros.get("apenasCancelados");
				
				List<PuntoVenta> lsPuntoVentaParam = (List<PuntoVenta>) parametros.get("lsPuntoVenta");
				List<String> lsNombPuntoVenta = new ArrayList<String>();
				List<String> lsPuntoVentaId = new ArrayList<String>();
				for (PuntoVenta puntoVenta : lsPuntoVentaParam) {
					lsPuntoVentaId.add("'" + String.valueOf(puntoVenta.getPuntoventaId()) + "'");
					lsNombPuntoVenta.add(puntoVenta.getNombpuntoventa());
				}
				stringLsPuntoVentaId = StringUtils.join(lsPuntoVentaId.toArray(new String[0]), ',');
				String nombPuntoVenta = !lsNombPuntoVenta.isEmpty() ? StringUtils.join(lsNombPuntoVenta.toArray(new String[0]), ',') : "Todas;";
				parametros.put("nombPuntoVenta", nombPuntoVenta);
				
				Connection conexao = this.relatorio.getConexao();
				processarVendasComissao(conexao);
				
				if (apenasCancelados) {
					setCollectionDataSource(new JRBeanCollectionDataSource(lsDadosRelatorioCancelamento));
				} else {
					setCollectionDataSource(new JRBeanCollectionDataSource(lsDadosRelatorio));
				}
				
			}

		});
	}
	
	private void processarVendasComissao(Connection conexao) {
		ResultSet rset = null;
		NamedParameterStatement stmt = null;
		
		try {
			
			/* Processando vendas normais */
			stmt = carregarNamedParameterStatement(conexao);
			rset = stmt.executeQuery();
			if (apenasCancelados) {
				processarResultadoCancelamento(rset);
			} else {
				processarResultado(rset);				
			}
			fecharConexaoBanco(stmt, rset);

		} catch (Exception e) {
			log.error(e.getMessage(), e);
		}
		
	}
	
	private void fecharConexaoBanco(NamedParameterStatement stmt, ResultSet rset) {
		try {
			if(rset != null) {
				rset.close();
			}
			if(stmt != null) {
				stmt.close();
			}
		} catch (SQLException e) {
			log.error(e.getMessage(), e);
		}
	}

	private void processarResultado(ResultSet rset) throws SQLException {
		if(lsDadosRelatorio == null) {
			lsDadosRelatorio = new ArrayList<RelatorioVendasComissaoBean>();
		}
		while (rset.next()) {
			RelatorioVendasComissaoBean relatorioVendaComissao = new RelatorioVendasComissaoBean();
			relatorioVendaComissao.setNumPuntoVenta(rset.getString("NUMPUNTOVENTA"));
			relatorioVendaComissao.setNombPuntoVenta(rset.getString("NOMBPUNTOVENTA"));
			boolean indreimpresion = rset.getBoolean("INDREIMPRESION");
			String indstatusboleto = rset.getString("INDSTATUSBOLETO");
			Long motivocancelacionId = rset.getLong("MOTIVOCANCELACION_ID");
			if(isDevolucaoOrCancelamentoCaja(indstatusboleto, motivocancelacionId, indreimpresion) && StringUtils.isNotBlank(rset.getString("NUMPTOVTAVENTA"))) {
				relatorioVendaComissao.setNumPuntoVenta(rset.getString("NUMPTOVTAVENTA"));
				relatorioVendaComissao.setNombPuntoVenta(rset.getString("NOMBPTOVTAVENTA"));
			} 
			
			int indice = lsDadosRelatorio.indexOf(relatorioVendaComissao);
			if(indice > -1) {
				relatorioVendaComissao = lsDadosRelatorio.get(indice);
			}
			
			BigDecimal total = rset.getBigDecimal("TOTAL");
			BigDecimal totalTaxas = rset.getBigDecimal("TOTAL_TAXAS");

			if(isVenda(indstatusboleto, indreimpresion) || isTroca(indstatusboleto, indreimpresion)) {
				relatorioVendaComissao.setTotalVendas(relatorioVendaComissao.getTotalVendas().add(total));
				relatorioVendaComissao.setTotalTaxasVendas(relatorioVendaComissao.getTotalTaxasVendas().add(totalTaxas));
			} else if(isCancelamentoCaja(indstatusboleto, motivocancelacionId, indreimpresion)) {
				relatorioVendaComissao.setTotalVendasCanceladas(relatorioVendaComissao.getTotalVendasCanceladas().add(total));
				relatorioVendaComissao.setTotalTaxasVendasCanceladas(relatorioVendaComissao.getTotalTaxasVendasCanceladas().add(totalTaxas));
			} else if(isDevolucaoCaja(indstatusboleto, motivocancelacionId, indreimpresion) ||
					  isDevolucaoOcdCaja(indstatusboleto, motivocancelacionId, indreimpresion) ||
					  isDevolucaoTrocaCaja(indstatusboleto, motivocancelacionId, indreimpresion)) {
				relatorioVendaComissao.setTotalVendasDevolucao(relatorioVendaComissao.getTotalVendasDevolucao().add(total));
				relatorioVendaComissao.setTotalTaxasVendasDevolucao(relatorioVendaComissao.getTotalTaxasVendasDevolucao().add(totalTaxas));
			}
			
			if(indice == -1) {
				lsDadosRelatorio.add(relatorioVendaComissao);
			}
		}
		
	}
	
	private void processarResultadoCancelamento(ResultSet rset) throws SQLException {
		if(lsDadosRelatorioCancelamento == null) {
			lsDadosRelatorioCancelamento = new ArrayList<RelatorioVendasComissaoCancelamentoBean>();
		}
		while (rset.next()) {
			RelatorioVendasComissaoCancelamentoBean relatorioVendaComissao = new RelatorioVendasComissaoCancelamentoBean();
			relatorioVendaComissao.setNumFolioSistema(rset.getString("NUMFOLIOSISTEMA"));
			relatorioVendaComissao.setCorridaId(rset.getInt("CORRIDA_ID"));
			relatorioVendaComissao.setFecHorViaje(rset.getTimestamp("FECHORVIAJE"));
			relatorioVendaComissao.setNumAsiento(rset.getString("NUMASIENTO"));
			relatorioVendaComissao.setPrecioTotalPagado(rset.getBigDecimal("TOTAL"));
			relatorioVendaComissao.setFecHorVenta(rset.getTimestamp("FECHORVENTA"));
			relatorioVendaComissao.setNombPuntoVenta(rset.getString("NOMBPUNTOVENTA"));
			lsDadosRelatorioCancelamento.add(relatorioVendaComissao);
		}
		
	}
	
	private boolean isCancelamento(String indstatusboleto) {
		return "C".equals(indstatusboleto);
	}

	private boolean isVenda(String indstatusboleto, boolean indreimpresion) {
		return "V".equals(indstatusboleto) && !indreimpresion;
	}
	
	private boolean isTroca(String indstatusboleto, boolean indreimpresion) {
		return "T".equals(indstatusboleto) && !indreimpresion;
	}
	
	private boolean isCancelamentoCaja(String indstatusboleto, Long motivocancelacionId, boolean indreimpresion) {
		return isCancelamento(indstatusboleto) && Constantes.MVO_CANCEL_CANCELACION.equals(motivocancelacionId) && !indreimpresion;
	}
	
	private boolean isDevolucaoCaja(String indstatusboleto, Long motivocancelacionId, boolean indreimpresion) {
		return isCancelamento(indstatusboleto) && Constantes.MVO_CANCEL_DEVOLUCAO.equals(motivocancelacionId) && !indreimpresion;
	}

	private boolean isDevolucaoTrocaCaja(String indstatusboleto, Long motivocancelacionId, boolean indreimpresion) {
		return isCancelamento(indstatusboleto) && Constantes.MVO_CANCEL_TROCA.equals(motivocancelacionId) && !indreimpresion;
	}
	
	private boolean isDevolucaoOcdCaja(String indstatusboleto, Long motivocancelacionId, boolean indreimpresion) {
		return isCancelamento(indstatusboleto) && Constantes.MVO_CANCEL_GERACAO_OCD.equals(motivocancelacionId) && !indreimpresion;
	}
	
	private boolean isDevolucaoOrCancelamentoCaja(String indstatusboleto, Long motivocancelacionId, boolean indreimpresion) {
		return isCancelamentoCaja(indstatusboleto, motivocancelacionId, indreimpresion) ||
			   isDevolucaoCaja(indstatusboleto, motivocancelacionId, indreimpresion) || 
			   isDevolucaoOcdCaja(indstatusboleto, motivocancelacionId, indreimpresion) ||
			   isDevolucaoTrocaCaja(indstatusboleto, motivocancelacionId, indreimpresion);
	}
	
	private NamedParameterStatement carregarNamedParameterStatement(Connection conexao) throws SQLException {
		String sql = apenasCancelados ? getSqlCancelados() : getSql();
		log.info(sql);
		
		NamedParameterStatement stmt = new NamedParameterStatement(conexao, sql);
		
		if(fecInicio != null) {
			stmt.setTimestamp("fecInicio", fecInicio);
		}
		if(fecFinal != null) {
			stmt.setTimestamp("fecFinal", fecFinal);
		}
		if(empresaId != null){
			stmt.setInt("EMPRESA_ID", empresaId);
		}
		
		return stmt;
	}

	protected String getSql() {
		
		String query = "SELECT PV.PUNTOVENTA_ID, PV.NUMPUNTOVENTA, PV.NOMBPUNTOVENTA, C.PTOVTAVENTA_ID, PV1.NUMPUNTOVENTA as NUMPTOVTAVENTA, PV1.NOMBPUNTOVENTA AS NOMBPTOVTAVENTA, C.INDSTATUSBOLETO, C.MOTIVOCANCELACION_ID, C.INDREIMPRESION, "
				+ "SUM(COALESCE (C.PRECIOPAGADO,0) + COALESCE (C.IMPORTETAXAEMBARQUE,0) + COALESCE (C.IMPORTESEGURO,0) + COALESCE (C.IMPORTEPEDAGIO,0) + COALESCE (C.IMPORTEOUTROS,0)) AS TOTAL, "
				+ "SUM(COALESCE (C.IMPORTETAXAEMBARQUE,0) + COALESCE (C.IMPORTESEGURO,0) + COALESCE (C.IMPORTEPEDAGIO,0) + COALESCE (C.IMPORTEOUTROS,0)) AS TOTAL_TAXAS "
				+ "FROM CAJA C "
				+ "JOIN PUNTO_VENTA PV ON PV.PUNTOVENTA_ID = C.PUNTOVENTA_ID "
				+ "JOIN MARCA M ON M.MARCA_ID = C.MARCA_ID "
				+ "LEFT JOIN PUNTO_VENTA PV1 ON PV1.PUNTOVENTA_ID = C.PTOVTAVENTA_ID "
				+ "WHERE ((C.INDSTATUSBOLETO = 'V' AND C.INDREIMPRESION = 0) "
				+ "OR (C.INDSTATUSBOLETO = 'T' AND C.INDREIMPRESION = 0) "
				+ "OR (C.INDCANCELACION = 1 AND C.INDSTATUSBOLETO = 'C')) "
				+ "AND (C.MOTIVOCANCELACION_ID IS NULL OR C.MOTIVOCANCELACION_ID NOT IN (10, 32, 99)) "
				+ "AND C.FECHORVENTA BETWEEN CAST (:fecInicio AS DATE) AND CAST(:fecFinal AS DATE) ";
		
		if (StringUtils.isNotBlank(stringLsPuntoVentaId)) {
			query += "AND C.PUNTOVENTA_ID IN(" + stringLsPuntoVentaId + ") ";
		}
		
		if(parametros.get("EMPRESA_ID")!= null){
			query += "AND M.EMPRESA_ID =:EMPRESA_ID ";
		}
		
		//foi adicionado indreimpresion = 0 para boleto. Foi analisado e chegou-se ao entendimento que os registros de boleto são sempre válidos		
		query += "GROUP BY PV.PUNTOVENTA_ID, PV.NUMPUNTOVENTA, PV.NOMBPUNTOVENTA, C.PTOVTAVENTA_ID, PV1.NUMPUNTOVENTA, PV1.NOMBPUNTOVENTA, C.INDSTATUSBOLETO, C.MOTIVOCANCELACION_ID, C.INDREIMPRESION "
				+ "UNION "
				+ "SELECT PV3.PUNTOVENTA_ID, PV3.NUMPUNTOVENTA, PV3.NOMBPUNTOVENTA, B.PTOVTAVENTA_ID, PV4.NUMPUNTOVENTA as NUMPTOVTAVENTA, PV4.NOMBPUNTOVENTA AS NOMBPTOVTAVENTA, B.INDSTATUSBOLETO, B.MOTIVOCANCELACION_ID, 0, " 
				+ "COALESCE (B.PRECIOPAGADO,0) + COALESCE (B.IMPORTETAXAEMBARQUE,0) + COALESCE (B.IMPORTESEGURO,0) + COALESCE (B.IMPORTEPEDAGIO,0) + COALESCE (B.IMPORTEOUTROS,0) AS TOTAL, "
				+ "COALESCE (B.IMPORTETAXAEMBARQUE,0) + COALESCE (B.IMPORTESEGURO,0) + COALESCE (B.IMPORTEPEDAGIO,0) + COALESCE (B.IMPORTEOUTROS,0) AS TOTAL_TAXAS "
				+ "FROM BOLETO B "
				+ "JOIN PUNTO_VENTA PV3 ON PV3.PUNTOVENTA_ID = B.PUNTOVENTA_ID "
				+ "LEFT JOIN PUNTO_VENTA PV4 ON PV4.PUNTOVENTA_ID = B.PTOVTAVENTA_ID "
				+ "JOIN MARCA M2 ON M2.MARCA_ID = B.MARCA_ID "
				+ "WHERE B.INDSTATUSBOLETO = 'C' "
				+ "AND B.MOTIVOCANCELACION_ID IN(10, 32, 99) "
				+ "AND B.FECHORVENTA BETWEEN CAST (:fecInicio AS DATE) AND CAST(:fecFinal AS DATE) ";
		
		if (StringUtils.isNotBlank(stringLsPuntoVentaId)) {
			query += "AND B.PUNTOVENTA_ID IN(" + stringLsPuntoVentaId + ") ";
		}
		
		if(parametros.get("EMPRESA_ID")!= null){
			query += "AND M2.EMPRESA_ID = :EMPRESA_ID ";
		}
		
		query += "ORDER BY NUMPUNTOVENTA, NUMPTOVTAVENTA, INDSTATUSBOLETO ";
		
		return query;
		
	}
	
	protected String getSqlCancelados() {
		
		String query = "SELECT B.NUMFOLIOSISTEMA, B.CORRIDA_ID, B.FECHORVIAJE, B.NUMASIENTO, B.PRECIOPAGADO, B.FECHORVENTA, COALESCE(PV2.NOMBPUNTOVENTA, PV1.NOMBPUNTOVENTA) NOMBPUNTOVENTA, " 
				+ "(COALESCE (B.PRECIOPAGADO,0) + COALESCE (B.IMPORTETAXAEMBARQUE,0) + COALESCE (B.IMPORTESEGURO,0) + COALESCE (B.IMPORTEPEDAGIO,0) + COALESCE (B.IMPORTEOUTROS,0)) AS TOTAL " 
				+ "FROM BOLETO B "
				+ "JOIN MARCA M ON M.MARCA_ID = B.MARCA_ID "
				+ "LEFT JOIN PUNTO_VENTA PV1 ON PV1.PUNTOVENTA_ID = B.PUNTOVENTA_ID "
				+ "LEFT JOIN PUNTO_VENTA PV2 ON PV2.PUNTOVENTA_ID = B.PTOVTAVENTA_ID "
				+ "WHERE B.INDSTATUSBOLETO = 'C' "
				+ "AND (B.MOTIVOCANCELACION_ID IN(10, 32, 99)) "
				+ "AND B.FECHORVENTA BETWEEN CAST (:fecInicio AS DATE) AND CAST(:fecFinal AS DATE) "; 
		
		if(parametros.get("EMPRESA_ID")!= null) {
			query += "AND M.EMPRESA_ID =:EMPRESA_ID ";
		}
		
		if (StringUtils.isNotBlank(stringLsPuntoVentaId)) {
			query += "AND B.PUNTOVENTA_ID IN(" + stringLsPuntoVentaId + ") ";
		}
		
		return query;
		
	}
	
	@Override
	protected void processaParametros() throws Exception {
	}
	
	public List<RelatorioVendasComissaoBean> getLsDadosRelatorio() {
		return lsDadosRelatorio;
	}
	
	@Override
	public String getNome() {
		if (apenasCancelados) {
			return "RelatorioVendasComissaoCancelamento";
		}
		return super.getNome();
	}

}
