/**
 * 
 */
package com.rjconsultores.ventaboletos.relatorios.negocio;

import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

import com.rjconsultores.ventaboletos.relatorios.utilitarios.ExceptionConfiguracao;
import com.rjconsultores.ventaboletos.web.utilerias.NamedParameterStatement;

/**
 * @author Bruno H. G. Gouvêa <bruno@rjconsultores.com.br>
 * 
 */
public class CalculoImposto {

	static Map<String, HashMap<String, Object>> mapCacheConfigImposto = new HashMap<String, HashMap<String, Object>>();
	
	public static void limpaCache(){
		mapCacheConfigImposto = new HashMap<String, HashMap<String, Object>>();
	}

	public static BigDecimal getValorImpostoRelatorioReceitaDiaria(Connection conexao, Integer estadoId, Integer empresaId, String indInterestadual, BigDecimal tarifa, BigDecimal seguro, BigDecimal embarque, BigDecimal pedagio, BigDecimal bagagem, Boolean indBaseTarifa, Boolean indBaseSeguro, Boolean indBaseEmbarque, Boolean indBasePedagio, Boolean indBaseBagagem) throws Exception {
		HashMap<String, Object> configImposto = new HashMap<String, Object>();

		BigDecimal baseCalculo = BigDecimal.ZERO;
		BigDecimal icms;
		BigDecimal porcRedEstadualMunicipal;
		BigDecimal porcRedBaseIcms;

		BigDecimal valorIcms = BigDecimal.ZERO;

		// configImposto = (HashMap<String, Object>) getConfigImpostoByPuntoVenta(conexao, puntoVentaId);

		configImposto = (HashMap<String, Object>) getConfigImpostoByEstadoOrigem(conexao, estadoId, empresaId);

		if (configImposto == null)
			return BigDecimal.ZERO;

		icms = (BigDecimal) configImposto.get("ICMS");
		porcRedBaseIcms = (BigDecimal) configImposto.get("PORCREDBASEICMS");

		if (indInterestadual.equals("S"))
			porcRedEstadualMunicipal = (BigDecimal) configImposto.get("PORCREDESTADUAL");
		else
			porcRedEstadualMunicipal = (BigDecimal) configImposto.get("PORCREDMUNICIPAL");

		// Criação da base de calculo
		baseCalculo = indBaseTarifa && tarifa != null ? baseCalculo.add(tarifa) : baseCalculo;
		baseCalculo = indBaseSeguro && seguro != null ? baseCalculo.add(seguro) : baseCalculo;
		baseCalculo = indBaseEmbarque && embarque != null ? baseCalculo.add(embarque) : baseCalculo;
		baseCalculo = indBasePedagio && pedagio != null ? baseCalculo.add(pedagio) : baseCalculo;
		baseCalculo = indBaseBagagem && bagagem != null ? baseCalculo.add(bagagem) : baseCalculo;

		//System.out.println("baseCalculo="+baseCalculo);
		// Redução da base de calculo
		if (porcRedBaseIcms != null && !porcRedBaseIcms.equals(BigDecimal.ZERO))
			// BASE DE CALCULO = BASE DE CALCULO - ((PERCENTUAL DE REDUÇÃO / 100) * BASE DE CALCULO ))
			baseCalculo = baseCalculo.subtract(porcRedBaseIcms.divide(BigDecimal.valueOf(100)).multiply(baseCalculo));
		//System.out.println("baseCalculo1="+baseCalculo);

		// Calcula o valor do ICMS
		valorIcms = baseCalculo.multiply(icms.divide(BigDecimal.valueOf(100)));

		//System.out.println("valorIcms="+valorIcms);
		// Redução estadual
		if (porcRedEstadualMunicipal != null && !porcRedEstadualMunicipal.equals(BigDecimal.ZERO))
			valorIcms = valorIcms.subtract(porcRedEstadualMunicipal.divide(BigDecimal.valueOf(100)).multiply(valorIcms));

		//System.out.println("valorIcms1="+valorIcms);
		
		return valorIcms;
	}

	public static Map<String, Object> getConfigImpostoByEstadoOrigem(Connection conexao, Integer idEstado, Integer empresaId) throws SQLException, ExceptionConfiguracao {

		HashMap<String, Object> cacheConfig = null;

		// Verifica se já existe configuração na memoria, caso não exista, realiza busca no banco
		if (!mapCacheConfigImposto.containsKey(idEstado.toString() + "-" + empresaId.toString())) {

			Boolean isBuscouConfig = false;

			StringBuilder sql = new StringBuilder();

			sql.append("  SELECT EI.*, ES.NOMBESTADO, EM.NOMBEMPRESA ");
			sql.append("    FROM ESTADO ES ");
			sql.append("   INNER JOIN EMPRESA EM ");
			sql.append("      ON (EM.EMPRESA_ID = :EMPRESA_ID) ");
			sql.append("    LEFT JOIN EMPRESA_IMPOSTO EI ");
			sql.append("      ON (ES.ESTADO_ID = EI.ESTADO_ID AND EM.EMPRESA_ID = EI.EMPRESA_ID) ");
			sql.append("   WHERE ES.ESTADO_ID = :ORIGEM_ESTADO_ID ");
			sql.append("     AND NVL(EI.ACTIVO, 1) = 1 ");

			NamedParameterStatement stmt = new NamedParameterStatement(conexao, sql.toString());
			stmt.setInt("ORIGEM_ESTADO_ID", idEstado);
			stmt.setInt("EMPRESA_ID", empresaId);
			ResultSet rs = stmt.executeQuery();

			if (rs.next()) {
				isBuscouConfig = true;
				if (rs.getBigDecimal("ICMS") != null) {

					cacheConfig = new HashMap<String, Object>();

					cacheConfig.put("PORCREDBASEICMS", rs.getBigDecimal("PORCREDBASEICMS"));
					cacheConfig.put("PORCREDESTADUAL", rs.getBigDecimal("PORCREDESTADUAL"));
					cacheConfig.put("INDTARIFAESTADUAL", rs.getBoolean("INDTARIFAESTADUAL"));
					cacheConfig.put("INDSEGUROESTADUAL", rs.getBoolean("INDSEGUROESTADUAL"));
					cacheConfig.put("INDTXEMBARQUEESTADUAL", rs.getBoolean("INDTXEMBARQUEESTADUAL"));
					cacheConfig.put("INDPEDAGIOESTDUAL", rs.getBoolean("INDPEDAGIOESTDUAL"));
					cacheConfig.put("PORCREDMUNICIPAL", rs.getBigDecimal("PORCREDMUNICIPAL"));
					cacheConfig.put("INDTARIFAMUNICIPAL", rs.getBoolean("INDTARIFAMUNICIPAL"));
					cacheConfig.put("INDSEGUROMUNICIPAL", rs.getBoolean("INDSEGUROMUNICIPAL"));
					cacheConfig.put("INDTXEMBARQUEMUNICIPAL", rs.getBoolean("INDTXEMBARQUEMUNICIPAL"));
					cacheConfig.put("INDPEDAGIOMUNICIPAL", rs.getBoolean("INDPEDAGIOMUNICIPAL"));

					cacheConfig.put("INDJANEIRO", rs.getBoolean("INDJANEIRO"));
					cacheConfig.put("INDFEVEREIRO", rs.getBoolean("INDFEVEREIRO"));
					cacheConfig.put("INDMARCO", rs.getBoolean("INDMARCO"));
					cacheConfig.put("INDABRIL", rs.getBoolean("INDABRIL"));
					cacheConfig.put("INDMAIO", rs.getBoolean("INDMAIO"));
					cacheConfig.put("INDJUNHO", rs.getBoolean("INDJUNHO"));
					cacheConfig.put("INDJULHO", rs.getBoolean("INDJULHO"));
					cacheConfig.put("INDAGOSTO", rs.getBoolean("INDAGOSTO"));
					cacheConfig.put("INDSETEMBRO", rs.getBoolean("INDSETEMBRO"));
					cacheConfig.put("INDOUTUBRO", rs.getBoolean("INDOUTUBRO"));
					cacheConfig.put("INDNOVEMBRO", rs.getBoolean("INDNOVEMBRO"));
					cacheConfig.put("INDDEZEMBRO", rs.getBoolean("INDDEZEMBRO"));

					cacheConfig.put("ICMS", rs.getBigDecimal("ICMS"));
					cacheConfig.put("PORCREDBASEICMS", rs.getBigDecimal("PORCREDBASEICMS"));
				}
				String estado = rs.getString("NOMBESTADO");
				String empresa = rs.getString("NOMBEMPRESA");

				if (!isBuscouConfig) {
					if (!rs.isClosed())
						rs.close();
					if (!stmt.isClosed())
						stmt.close();
					throw new ExceptionConfiguracao("Não foi possivel obter a configuração de imposto para o estado: " + estado + " empresa: " + empresa);
				}
			}
			;

			if (!rs.isClosed())
				rs.close();
			if (!stmt.isClosed())
				stmt.close();

			if (!isBuscouConfig)
				throw new ExceptionConfiguracao("Não foi possivel obter a configuração de imposto para agência " + idEstado.toString());

			mapCacheConfigImposto.put(idEstado.toString() + "-" + empresaId.toString(), cacheConfig);

		} else
			cacheConfig = mapCacheConfigImposto.get(idEstado.toString() + "-" + empresaId.toString());

		return cacheConfig;

	}

	public static BigDecimal getValorImposto(Connection conexao, Integer idEstado, Integer empresaId, String indInterestadual, BigDecimal tarifa, BigDecimal seguro, BigDecimal embarque, BigDecimal pedagio) throws Exception {
		HashMap<String, Object> configImposto = new HashMap<String, Object>();

		BigDecimal baseCalculo = BigDecimal.ZERO;
		BigDecimal icms;
		BigDecimal porcRedEstadualMunicipal;

		BigDecimal porcRedBaseIcms;

		BigDecimal valorIcms = BigDecimal.ZERO;

		Boolean indTarifaMunicipal;
		Boolean indSeguroMunicipal;
		Boolean indTxEmbarqueMunicipal;
		Boolean indPedagioMunicipal;
		Boolean indTarifaEstadual;
		Boolean indSeguroEstadual;
		Boolean indTxEmbarqueEstadual;
		Boolean indPedagioEstadual;

		configImposto = (HashMap<String, Object>) getConfigImpostoByEstadoOrigem(conexao, idEstado, empresaId);

		if (configImposto == null)
			return BigDecimal.ZERO;

		icms = (BigDecimal) configImposto.get("ICMS");
		porcRedBaseIcms = (BigDecimal) configImposto.get("PORCREDBASEICMS");

		if (indInterestadual.equals("S")) {
			porcRedEstadualMunicipal = (BigDecimal) configImposto.get("PORCREDESTADUAL");

			indTarifaEstadual = (Boolean) configImposto.get("INDTARIFAESTADUAL");
			indSeguroEstadual = (Boolean) configImposto.get("INDSEGUROESTADUAL");
			indTxEmbarqueEstadual = (Boolean) configImposto.get("INDTXEMBARQUEESTADUAL");
			indPedagioEstadual = (Boolean) configImposto.get("INDPEDAGIOESTDUAL");

			// Criação da base de calculo
			baseCalculo = indTarifaEstadual && tarifa != null ? baseCalculo.add(tarifa) : baseCalculo;
			baseCalculo = indSeguroEstadual && seguro != null ? baseCalculo.add(seguro) : baseCalculo;
			baseCalculo = indTxEmbarqueEstadual && embarque != null ? baseCalculo.add(embarque) : baseCalculo;
			baseCalculo = indPedagioEstadual && pedagio != null ? baseCalculo.add(pedagio) : baseCalculo;
		} else {
			porcRedEstadualMunicipal = (BigDecimal) configImposto.get("PORCREDMUNICIPAL");

			indTarifaMunicipal = (Boolean) configImposto.get("INDTARIFAMUNICIPAL");
			indSeguroMunicipal = (Boolean) configImposto.get("INDSEGUROMUNICIPAL");
			indTxEmbarqueMunicipal = (Boolean) configImposto.get("INDTXEMBARQUEMUNICIPAL");
			indPedagioMunicipal = (Boolean) configImposto.get("INDPEDAGIOMUNICIPAL");

			baseCalculo = indTarifaMunicipal && tarifa != null ? baseCalculo.add(tarifa) : baseCalculo;
			baseCalculo = indSeguroMunicipal && seguro != null ? baseCalculo.add(seguro) : baseCalculo;
			baseCalculo = indTxEmbarqueMunicipal && embarque != null ? baseCalculo.add(embarque) : baseCalculo;
			baseCalculo = indPedagioMunicipal && pedagio != null ? baseCalculo.add(pedagio) : baseCalculo;
		}

		// Redução da base de calculo
		if (porcRedBaseIcms != null && !porcRedBaseIcms.equals(BigDecimal.ZERO))
			// BASE DE CALCULO = BASE DE CALCULO - ((PERCENTUAL DE REDUÇÃO / 100) * BASE DE CALCULO ))
			baseCalculo = baseCalculo.subtract(porcRedBaseIcms.divide(BigDecimal.valueOf(100)).multiply(baseCalculo));


		// Calcula o valor do ICMS
		valorIcms = baseCalculo.multiply(icms.divide(BigDecimal.valueOf(100)));


		// Redução estadual/municipal
		if (porcRedEstadualMunicipal != null && !porcRedEstadualMunicipal.equals(BigDecimal.ZERO))
			valorIcms = valorIcms.subtract(porcRedEstadualMunicipal.divide(BigDecimal.valueOf(100)).multiply(valorIcms));


		return valorIcms;
	}
}
