package com.rjconsultores.ventaboletos.dao.hibernate;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Calendar;
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.Query;
import org.hibernate.SessionFactory;
import org.hibernate.jdbc.Work;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Repository;

import com.rjconsultores.ventaboletos.dao.MonitoramentoCCFDAO;
import com.rjconsultores.ventaboletos.entidad.Empresa;
import com.rjconsultores.ventaboletos.entidad.Estado;
import com.rjconsultores.ventaboletos.entidad.FiscalImpressora;
import com.rjconsultores.ventaboletos.entidad.MonitoramentoCCF;
import com.rjconsultores.ventaboletos.entidad.PuntoVenta;
import com.rjconsultores.ventaboletos.entidad.Usuario;
import com.rjconsultores.ventaboletos.web.utilerias.NamedParameterStatement;

@Repository("monitoramentoCCFDAO")
public class MonitoramentoCCFHibernateDAO extends GenericHibernateDAO<MonitoramentoCCF, Integer>
implements MonitoramentoCCFDAO {
	private static final Logger log = LogManager.getLogger(MonitoramentoCCFHibernateDAO.class);
	private Connection con;
	Boolean jaexiste;
	
	@Autowired
	public MonitoramentoCCFHibernateDAO(
			@Qualifier("sessionFactory") SessionFactory factory) {
		setSessionFactory(factory);
	}
	
	private String getSQL(){
		StringBuilder sql = new StringBuilder();
		
		sql.append("    SELECT    ");
		sql.append("      fi.empresa_id as empresa,  "); 
		sql.append("      fi.numserie20 as numserie20,  "); 
		sql.append("      fi.fiscalimpressora_id as fiscalimpressora_id, ");  
		sql.append("      fi.estadolocal_id as estado,   ");
		sql.append("      c.FECCREACION as datamov,   ");
		sql.append("      fi.puntoventa_id as puntoventa_id,  "); 
		sql.append("      c.usuario_id as usuario_id, ");
		sql.append("      r4.contador as ccf, ");
		sql.append("      c.caja_id as cajaId, ");
		sql.append("      fi.numserie as numserie ");
		sql.append("   	FROM   ");
		sql.append("      caja c ");
		sql.append("   	  left join fiscal_r4 R4 on R4.CAJA_ID = c.CAJA_ID  ");  
		sql.append("      inner join fiscal_impressora fi on fi.numserie = c.SERIEIMPFISCAL   ");
		sql.append("    where   ");
		sql.append("      fi.numserie = :numserie   ");
		sql.append("      and trunc(c.FECCREACION) >= :data ");
		sql.append("      and c.ccf >= :ccfInicial ");
		sql.append("      and fi.activo = 1 ");
		sql.append(" 	  and c.activo = 1 ");
		sql.append(" 	  and ((c.indreimpresion = 0) or (c.indreimpresion = 1 and c.indstatusboleto in ('E')) or (c.indreimpresion = 1 and c.motivocancelacion_id =(select motivocancelacion_id from motivo_cancelacion where cvesistema = 'CANCELAMENTO_ECF') and c.ccf is not null)) ");
		sql.append(" 	  and c.ccf is not null ");
		sql.append(" 	  and r4.fiscalr4_id is not null ");
		sql.append("    order by c.ccf ");

		return sql.toString();
	}
		
	private String getSqlImpressorasComCCFInicial(){
		StringBuilder sb = new StringBuilder();
		sb.append(" select "); 
		sb.append("   SERIEIMPFISCAL, ");
		sb.append("   max(ccf) ");
		sb.append(" from ");
		sb.append("   caja "); 
		sb.append(" where "); 
		sb.append("   feccreacion <= :dataMenos2 ");
		sb.append("   and SERIEIMPFISCAL in (select distinct c2.SERIEIMPFISCAL "); 
		sb.append("		  from caja c2 where trunc(c2.FECCREACION) = :dataMenos1) ");
		sb.append("	group by SERIEIMPFISCAL  ");
		return sb.toString();
	}
	
	@Override
	public Map<String, Integer> obterImpressorasComCCFInicial(Date data){
		Map<String, Integer> impressoras = new HashMap<String, Integer>();
		NamedParameterStatement stmt = null;
	    ResultSet rset = null;
	    try{
			final Calendar c = Calendar.getInstance();
			c.setTime(data);
			c.add(Calendar.DAY_OF_MONTH, -1);
			stmt = new NamedParameterStatement(con, getSqlImpressorasComCCFInicial());
			stmt.setDate("dataMenos2", new java.sql.Date(c.getTime().getTime()));
			stmt.setDate("dataMenos1", new java.sql.Date(data.getTime()));
			
        	rset = stmt.executeQuery();
	
			while (rset.next()) {
				impressoras.put(rset.getString(1), rset.getInt(2));
			}			
		} catch (Exception e){
			log.error("", e);
		} finally {
            if(stmt != null) {
            	try { stmt.close(); } catch (SQLException e) { log.error("", e); }
            }
            if(rset != null) {
            	try { rset.close(); } catch (SQLException e) { log.error("", e); }
            }
        }
	    return impressoras;
	}
		
	public List<MonitoramentoCCF> buscaQuebraCCF(final String numserie, final Date data, final Integer ccfInicial){
		final List<MonitoramentoCCF> result = new ArrayList<MonitoramentoCCF>();
		
    	NamedParameterStatement stmt = null;
    	ResultSet rset = null;
    	try{
        	stmt = new NamedParameterStatement(con, getSQL());
			stmt.setString("numserie", numserie);
			stmt.setDate("data", new java.sql.Date(data.getTime()));
			stmt.setInt("ccfInicial", ccfInicial);
			
			rset = stmt.executeQuery();
	
			while (rset.next()) {
				Integer empresaId = rset.getInt("empresa");
				Integer estadoId = rset.getInt("estado");
				Date dataMov = rset.getDate("datamov");
				FiscalImpressora fiscalImpressora = new FiscalImpressora(rset.getInt("fiscalimpressora_id"));
				Empresa empresa = empresaId != null && empresaId != 0 ? new Empresa(empresaId) : null;
				Estado estado = estadoId != null && estadoId != 0 ? new Estado(estadoId) : null;
				PuntoVenta puntoVenta = new PuntoVenta(rset.getInt("puntoventa_id"));
				Usuario usuario = new Usuario(rset.getInt("usuario_id"));
				Integer ccf = rset.getInt("ccf");
				Integer ccf2 = null;
				
				if (rset.next()){
					ccf2 = rset.getInt("ccf");
					Date aux = dataMov;
					if (ccf2 - ccf > 1){ 
						for (int i = ccf +1; i < ccf2; i++){
							Calendar c = Calendar.getInstance();
							c.setTime(aux);
							c.add(Calendar.DATE, +1);
							aux = c.getTime();
							
							MonitoramentoCCF m = new MonitoramentoCCF();
							m.setDataMonitoramento(new Date());
							m.setDataOcorrencia(dataMov);
							m.setDiasAlertaAberto(new Date());
							m.setImpressora(fiscalImpressora);
							m.setEmpresa(empresa);
							m.setEstadoInstalacao(estado);
							m.setPuntoventa(puntoVenta);
							m.setSequenciaCCFQuebrada(i);
							m.setUsuario(usuario);
							result.add(m);
						}
					}
				}		
			}
    	} catch (Exception e){
			log.error("", e);
		} finally {
    		if(stmt != null) {
            	try { stmt.close(); } catch (SQLException e) { log.error("", e); }
            }
            if(rset != null) {
            	try { rset.close(); } catch (SQLException e) { log.error("", e); }
            }
        }
		return result;
	}
	
	public List<MonitoramentoCCF> obtenerTodos(){
		StringBuilder hql = new StringBuilder();
		hql.append("SELECT m FROM MonitoramentoCCF m ");
		hql.append("left join m.empresa ");
		hql.append("ORDER BY m.empresa, m.impressora.numserie20, m.sequenciaCCFQuebrada ");
		Query query = getSession().createQuery(hql.toString());
		
		return query.list();
	}
	
	private String getMonitoramentoCCFSQL(){
		StringBuilder sql = new StringBuilder();

		sql.append(" select count(*) ");
		sql.append(" from monitoramento_ccf ");
		sql.append(" where SEQUENCIA_CCF_QUEBRADA = :seq and fiscalimpressora_id = :fiscalimpressoraId ");

		return sql.toString();
	}
	
	@Override
	public MonitoramentoCCF suscribir(final MonitoramentoCCF entity){
		jaexiste = false;
		try{
			getSession().doWork(new Work() {
		        public void execute(Connection connection) throws SQLException 
		        { 
		        	NamedParameterStatement stmt = null;
		        	ResultSet rset = null;
		        	try{
						log.debug("salvando ccf " + entity.getSequenciaCCFQuebrada() + " para impressora " + entity.getImpressora().getFiscalimpressoraId());
						stmt = new NamedParameterStatement(connection, getMonitoramentoCCFSQL());
						stmt.setInt("seq", entity.getSequenciaCCFQuebrada());
						stmt.setInt("fiscalimpressoraId", entity.getImpressora().getFiscalimpressoraId());
						rset = stmt.executeQuery();
						if (rset.next()){
							if (rset.getInt(1) > 0){
								jaexiste = true;
								return;
							}
						}	
		        	} finally {
                        if(stmt != null) {
                        	stmt.close();
                        }
                        if(rset != null) {
                        	rset.close();
                        }
                        if(connection != null) {
                        	//connection.close();
                        }
                    }
		        }
			});
			if (!jaexiste) {
				return super.suscribir(entity);
			} else {
				return entity;
			}
		} catch (Exception e){
			log.error("", e);
			return entity;
		} 
	}
	
	@Override
	public void setConnection(Connection con) {
		this.con = con;
	}
}
