package com.rjconsultores.ventaboletos.dao.hibernate;

import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.hibernate.Query;
import org.hibernate.SessionFactory;
import org.hibernate.transform.AliasToBeanResultTransformer;
import org.hibernate.type.BigDecimalType;
import org.hibernate.type.BooleanType;
import org.hibernate.type.DateType;
import org.hibernate.type.IntegerType;
import org.hibernate.type.StringType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Repository;

import com.rjconsultores.ventaboletos.constantes.TipoEventoExtra;
import com.rjconsultores.ventaboletos.dao.ComissaoDAO;
import com.rjconsultores.ventaboletos.entidad.Comissao;
import com.rjconsultores.ventaboletos.entidad.PuntoVenta;
import com.rjconsultores.ventaboletos.utilerias.DateUtil;
import com.rjconsultores.ventaboletos.vo.comissao.BoletoComissao;
import com.rjconsultores.ventaboletos.vo.comissao.HistoricoComissao;

@Repository("comissaoHibernateDAO")
public class ComissaoHibernateDAO extends GenericHibernateDAO<Comissao, Integer> implements ComissaoDAO {

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

	@SuppressWarnings("unchecked")
	@Override
	public List<BoletoComissao> buscarReceitasComissoes(Integer puntoVentaId, Integer empresaId, Date periodo) {

		StringBuffer sql = new StringBuffer();
		sql.append("select ");
		sql.append("b.marca_id as empresaId, b.puntoventa_id as puntoVentaId, ");
		sql.append("to_char(b.fechorventa, 'dd-mm-yyyy') as datavenda, b.indstatusboleto as indstatusboleto, ");
		sql.append("b.tipoventa_id as tipoVenta, b.motivocancelacion_id as motivoCancelacionId, ");
		sql.append("coalesce(sum(b.preciopagado), 0) as valorpagado, coalesce(sum(b.importeseguro), 0) as seguro, ");
		sql.append("coalesce(sum(b.importepedagio), 0) as pedagio, coalesce(sum(b.importetaxaembarque), 0) as embarque, ");
		sql.append("coalesce(sum(case when tee.cvetipoevento = :teeexcbag then ee.impingreso else 0 end), 0) as excessoBagagem, ");
		sql.append("coalesce(sum(case when tee.cvetipoevento = :teesegop then ee.impingreso else 0 end), 0) as seguroOpcional, ");
		sql.append("coalesce(sum(case when tee.cvetipoevento not in (:teesegop,:teeexcbag) then ee.impingreso else 0 end), 0) as seguroOutros, ");
		sql.append("case when b.ptovtaventa_id = b.puntoventa_id then 1 else 0 end as ptoVtaOrigem, ");
		sql.append("ei.icms as icmsBase, e.estado_id as estadoId ");
		sql.append("from boleto b ");
		sql.append("inner join parada origen on origen.parada_id = b.origen_id ");
		sql.append("inner join ciudad ci on origen.ciudad_id = ci.ciudad_id ");
		sql.append("inner join estado e on ci.estado_id = e.estado_id ");
		sql.append("inner join punto_venta p on b.puntoventa_id = p.puntoventa_id ");
		sql.append("inner join empresa_imposto ei on (ei.estado_id = e.estado_id ");
		sql.append("      and ei.empresa_id = b.marca_id and ei.activo = 1) ");
		/*sql.append("left join caja c on c.numoperacion = b.numoperacion and c.numfoliosistema = b.numfoliosistema ");
		sql.append("      and c.numfoliopreimpreso = b.numfoliopreimpreso and c.numseriepreimpresa = b.numseriepreimpresa ");*/
		sql.append("left join evento_extra ee on ee.boleto_id = b.boleto_id ");
		sql.append("left join tipo_evento_extra tee on tee.tipoeventoextra_id = ee.tipoeventoextra_id ");
		sql.append("where b.fechorventa between TO_DATE(:dataInicial,'DD/MM/YYYY HH24:MI') and TO_DATE(:dataFinal,'DD/MM/YYYY HH24:MI') ");
		sql.append("and b.marca_id = :empresaId ");
		sql.append("and (p.puntoventa_id = :puntoventaId or p.puntoventapadre_id = :puntoventaId) ");
		sql.append("group by b.marca_id, b.puntoventa_id, to_char(b.fechorventa, 'dd-mm-yyyy'), ");
		sql.append("b.indstatusboleto, b.tipoventa_id, b.motivocancelacion_id, b.ptovtaventa_id, ei.icms, e.estado_id ");
		sql.append("order by datavenda ");

		Query query = getSession().createSQLQuery(sql.toString())
				.addScalar("empresaId", IntegerType.INSTANCE)
				.addScalar("puntoVentaId", IntegerType.INSTANCE)
				.addScalar("datavenda", StringType.INSTANCE)
				.addScalar("tipoVenta", IntegerType.INSTANCE)
				.addScalar("indstatusboleto", StringType.INSTANCE)
				.addScalar("motivoCancelacionId", IntegerType.INSTANCE)
				.addScalar("valorpagado", BigDecimalType.INSTANCE)
				.addScalar("seguro", BigDecimalType.INSTANCE)
				.addScalar("pedagio", BigDecimalType.INSTANCE)
				.addScalar("embarque", BigDecimalType.INSTANCE)
				.addScalar("excessoBagagem", BigDecimalType.INSTANCE)
				.addScalar("seguroOpcional", BigDecimalType.INSTANCE)
				.addScalar("seguroOutros", BigDecimalType.INSTANCE)
				.addScalar("ptoVtaOrigem", BooleanType.INSTANCE)
				.addScalar("icmsBase", BigDecimalType.INSTANCE)
				.addScalar("estadoId", IntegerType.INSTANCE)
				.setResultTransformer(new AliasToBeanResultTransformer(BoletoComissao.class));

		Date inicioPeriodo = DateUtil.inicioFechaPeriodoMeses(periodo);
		Date fimPeriodo = DateUtil.fimFechaPeriodoMeses(periodo);
		
		query.setString("dataInicial", DateUtil.getStringDate(inicioPeriodo, "dd/MM/yyyy HH:mm"));
		query.setString("dataFinal", DateUtil.getStringDate(fimPeriodo, "dd/MM/yyyy HH:mm"));
		query.setInteger("puntoventaId", puntoVentaId);
		query.setInteger("empresaId", empresaId);
		query.setString("teeexcbag", TipoEventoExtra.EXCESSO_BAGAGEM.toString());
		query.setString("teesegop", TipoEventoExtra.SEGURO_OPCIONAL.toString());

		return query.list();
	}

	@Override
	public Comissao buscaComissaoVigencia(Integer puntoVentaId, Integer empresaId, String competencia) {

		StringBuilder hql = new StringBuilder();
		hql.append(" from Comissao c ");
		hql.append(" where c.activo = 1 ");
		hql.append("   AND c.puntoVenta.puntoventaId = :puntoventaId ");
		hql.append("   AND c.empresaId = :empresaId ");
		hql.append("   AND c.competencia = :periodo ");

		Query query = getSession().createQuery(hql.toString());
		query.setString("periodo", competencia);
		query.setInteger("puntoventaId", puntoVentaId);
		query.setInteger("empresaId", empresaId);

		return (Comissao) query.uniqueResult();
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<HistoricoComissao> buscaHistoricoComissao(Map<String, Object> parametros) {

		/*String competenciaInicio = DateUtil.getStringDate(periodoInicio, "MM/yyyy");
		String competenciaFim = DateUtil.getStringDate(periodoFim, "MM/yyyy");*/

		StringBuilder sql = new StringBuilder();
		sql.append("SELECT c.competencia AS competencia, pv.nombpuntoventa, pv.numpuntoventa, ");
		sql.append("  c.datapagamento AS dataPagamento, ");
		sql.append("  c.comissao_bpr AS comissaoBpr, ");
		sql.append("  c.receita_excessobagagem AS receitaExcessobagagem, ");
		sql.append("  c.receita_seguroopcional AS receitaSeguroopcional, ");
		sql.append("  c.receita_seguro AS receitaSeguro, ");
		sql.append("  c.descontos_fixos AS descontosFixos, ");
		sql.append("  c.descontos_eventuais AS descontosEventuais, ");
		sql.append("  c.royaties AS royaties, ");
		sql.append("  c.iss_retido AS issRetido, ");
		sql.append("  c.bonificacao_metas AS bonificacaoMetas, ");
		sql.append("  c.entregas_passagem AS entregasPassagem, ");
		sql.append("  c.receita_outros AS receitaOutros, ");
		sql.append("  c.receita_bpr AS receitaBPR, ");
		sql.append("  c.devolvidos AS devolvidos, ");
		sql.append("  c.receita_bruta_excessobagagem AS receitaBrutaExcessoBagagem, ");
		sql.append("  c.receita_bruta_seguroopcional AS receitaBrutaSeguroopcional, ");
		sql.append("  c.receita_bruta_seguro AS receitaBrutaSeguro, ");
		sql.append("  c.indpago AS indPago, ");
		sql.append("  CASE WHEN c.indpago = 1 THEN 'PAGO' ELSE 'PENDENTE' END AS pagamento, ");
		sql.append("  up.nombusuario AS usuarioPagamento, ");
		sql.append("  ul.nombusuario AS usuarioLancamento, ");
		sql.append("  e.nombempresa, e.cnpj, ");
		sql.append("  pa.numagencia as agencia, pa.numconta || '-' || pa.digito as conta, if.nome as banco, ");
		sql.append("  ci.nombciudad as cidade, pv.descCorreo, pv.razonsocial, pv.numdocpuntoventa as cnpjPuntoventa, ");
		sql.append("  c.data_inicial as dataInicial, c.data_final as dataFinal, ");
		sql.append("  c.receita_gap as receitaGAP, c.empresa_id as empresaId ");
		sql.append("FROM comissao c ");
		sql.append("JOIN punto_venta pv on pv.puntoventa_id = c.puntoventa_id ");
		sql.append("JOIN empresa e on e.empresa_id = c.empresa_id ");
		sql.append("LEFT JOIN ptovta_agencia pa on pa.ptovtaagencia_id = pv.ptovtaagencia_id ");
		sql.append("LEFT JOIN insti_financeira if on if.instifinanceira_id = pa.instifinanceira_id ");
		sql.append("LEFT JOIN colonia co on co.colonia_id = pv.colonia_id ");
		sql.append("LEFT JOIN ciudad ci on ci.ciudad_id = co.ciudad_id ");
		sql.append("LEFT JOIN usuario up ON up.usuario_id = c.usuariopagamento_id ");
		sql.append("LEFT JOIN usuario ul ON ul.usuario_id = c.usuario_id ");
		sql.append("WHERE c.activo = 1 ");
		
		if(parametros.containsKey("empresaId")) {
			sql.append("  AND c.empresa_id    = :empresaId ");
		}
		
		if(parametros.containsKey("competenciaInicial") && parametros.containsKey("competenciaFinal")) {
			sql.append("  AND TO_DATE(c.competencia,'MM/YYYY') BETWEEN TO_DATE(:competenciaInicial,'MM/YYYY') and TO_DATE(:competenciaFinal,'MM/YYYY') ");
		}
		
		if(parametros.containsKey("dataInicial") && parametros.containsKey("dataFinal")) {
			sql.append("  AND ((TO_DATE(:dataInicial,'dd/mm/yyyy') between c.data_inicial and c.data_final) OR (TO_DATE(:dataFinal,'dd/mm/yyyy') between c.data_inicial and c.data_final)) ");
		}
		
		if(parametros.containsKey("puntoventaId")) {
			sql.append("  AND c.puntoventa_id = :puntoventaId ");
		}
		
		if(parametros.containsKey("competenciaInicio") && parametros.containsKey("competenciaFim")) {
			sql.append("ORDER BY pv.nombpuntoventa, TO_DATE(c.competencia,'MM/YYYY') ");
		}
		
		if(parametros.containsKey("dataInicial") && parametros.containsKey("dataFinal")) {
			sql.append("ORDER BY pv.nombpuntoventa, c.data_inicial ");
		}

		Query query = getSession().createSQLQuery(sql.toString())
				.addScalar("competencia", StringType.INSTANCE)
				.addScalar("nombpuntoventa", StringType.INSTANCE)
				.addScalar("numpuntoventa", StringType.INSTANCE)
				.addScalar("dataPagamento", DateType.INSTANCE)
				.addScalar("comissaoBpr", BigDecimalType.INSTANCE)
				.addScalar("receitaExcessobagagem", BigDecimalType.INSTANCE)
				.addScalar("receitaSeguroopcional", BigDecimalType.INSTANCE)
				.addScalar("receitaSeguro", BigDecimalType.INSTANCE)
				.addScalar("descontosFixos", BigDecimalType.INSTANCE)
				.addScalar("descontosEventuais", BigDecimalType.INSTANCE)
				.addScalar("royaties", BigDecimalType.INSTANCE)
				.addScalar("issRetido", BigDecimalType.INSTANCE)
				.addScalar("bonificacaoMetas", BigDecimalType.INSTANCE)
				.addScalar("entregasPassagem", BigDecimalType.INSTANCE)
				.addScalar("receitaOutros", BigDecimalType.INSTANCE)
				.addScalar("indPago", BooleanType.INSTANCE)
				.addScalar("pagamento", StringType.INSTANCE)
				.addScalar("usuarioPagamento", StringType.INSTANCE)
				.addScalar("usuarioLancamento", StringType.INSTANCE)
				.addScalar("nombempresa", StringType.INSTANCE)
				.addScalar("cnpj", StringType.INSTANCE)
				.addScalar("conta", StringType.INSTANCE)
				.addScalar("banco", StringType.INSTANCE)
				.addScalar("cidade", StringType.INSTANCE)
				.addScalar("agencia", StringType.INSTANCE)
				.addScalar("descCorreo", StringType.INSTANCE)
				.addScalar("razonsocial", StringType.INSTANCE)
				.addScalar("cnpjPuntoventa", StringType.INSTANCE)
				.addScalar("receitaBPR", BigDecimalType.INSTANCE)
				.addScalar("devolvidos", BigDecimalType.INSTANCE)
				.addScalar("receitaBrutaExcessoBagagem", BigDecimalType.INSTANCE)
				.addScalar("receitaBrutaSeguroopcional", BigDecimalType.INSTANCE)
				.addScalar("receitaBrutaSeguro", BigDecimalType.INSTANCE)
				.addScalar("dataInicial", DateType.INSTANCE)
				.addScalar("dataFinal", DateType.INSTANCE)
				.addScalar("receitaGAP", BigDecimalType.INSTANCE)
				.addScalar("empresaId", IntegerType.INSTANCE)
				.setResultTransformer(new AliasToBeanResultTransformer(HistoricoComissao.class));

		setParametros(query, parametros);

		return query.list();
	}
	
	@Override
	@SuppressWarnings("unchecked")
	public List<PuntoVenta> buscaPuntoVentasEmpresaComComissaoParametrizada(Integer empresaId) {
		StringBuilder sQuery = new StringBuilder("SELECT NEW com.rjconsultores.ventaboletos.entidad.PuntoVenta(pv.puntoventaId, pv.nombpuntoventa) FROM PtovtaComissao c ");
		sQuery.append("JOIN c.puntoventaId pv ")
			  .append("JOIN c.empresaId e ")
			  .append("WHERE pv.activo = 1 ")
			  .append("AND e.empresaId = :empresaId ")
			  .append("AND c.activo = 1")
			  .append("AND pv.statusaprobacion = 'A'");
		Query qr = getSession().createQuery(sQuery.toString());
		qr.setParameter("empresaId", empresaId);
		
		return qr.list();
	}
	
	@Override
	@SuppressWarnings("unchecked")
	public List<PuntoVenta> buscaPuntoVentasComComissaoParametrizada() {
		StringBuilder sQuery = new StringBuilder("SELECT NEW com.rjconsultores.ventaboletos.entidad.PuntoVenta(pv.puntoventaId, pv.nombpuntoventa) FROM PtovtaComissao c ");
		sQuery.append("JOIN c.puntoventaId pv ")
			  .append("JOIN c.empresaId e ")
			  .append("WHERE pv.activo = 1 ")
			  .append("AND c.indretercomissao = 1 ")
			  .append("AND c.activo = 1")
			  .append("AND pv.statusaprobacion = 'A'");
		Query qr = getSession().createQuery(sQuery.toString());
		;
		
		return qr.list();
	}

	@Override
	public Comissao buscaComissaoVigencia(Integer puntoVentaId, Integer empresaId, Date dataInicial, Date dataFinal) {
		StringBuilder hql = new StringBuilder();
		hql.append(" from Comissao c ");
		hql.append(" where c.activo = 1 ");
		hql.append("   AND c.puntoVenta.puntoventaId = :puntoventaId ");
		hql.append("   AND c.empresaId = :empresaId ");
		hql.append("   AND ((TO_DATE(:dataInicial,'dd/mm/yyyy') between c.dataInicial and c.dataFinal) OR (TO_DATE(:dataFinal,'dd/mm/yyyy') between c.dataInicial and c.dataFinal))");

		Query query = getSession().createQuery(hql.toString());
		query.setString("dataInicial", DateUtil.getStringDate(dataInicial, "dd/MM/yyyy"));
		query.setString("dataFinal", DateUtil.getStringDate(dataFinal, "dd/MM/yyyy"));
		query.setInteger("puntoventaId", puntoVentaId);
		query.setInteger("empresaId", empresaId);

		return (Comissao) query.uniqueResult();
	}
	
	@SuppressWarnings("rawtypes")
	private void setParametros(Query qr, Map<String, Object> parametros) {
		for (Entry<String, Object> parametro : parametros.entrySet()) {
			if (parametro.getValue() instanceof Collection) {
				qr.setParameterList(parametro.getKey(), (Collection) parametro.getValue());
			} else if (parametro.getValue() instanceof List) {
				qr.setParameterList(parametro.getKey(), (List) parametro.getValue());
			} else {
				qr.setParameter(parametro.getKey(), parametro.getValue());
			}
		}
	}

}
