package com.ejie.ad74a.dao.iml;

import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;
import javax.sql.DataSource;

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.ParameterizedPreparedStatementSetter;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import com.ejie.ad74a.dao.LiquidacionDao;
import com.ejie.ad74a.model.Concepto;
import com.ejie.ad74a.model.ConfigSipca;
import com.ejie.ad74a.model.Liquidacion;
import com.ejie.ad74a.util.UtilProperties;
import com.ejie.ad74a.util.Utilidades;
import com.ejie.ad74a.util.constantes.ConstantesBatch;

/**
 * Implentacion de la capa de persistencia para liquidaciones en AE01B
 * 
 * @author BICUGUAL
 *
 */
@Repository
public class LiquidacionDaoImpl implements LiquidacionDao {

	public static final String DBLINK = "@AE01B_DBL0.BATERA.EUSKADI.EUS";
	public static final String T_LIQUIDACIONES = "AE01B.AE01B00T00" + DBLINK;
	public static final String T_LIQUIDACIONES_ESPEJO = "AD74A.AE01B00T02";
	public static final String SEQUENCE_LIQUIDACIONES_ESPEJO = "SEQ_LIQUIDACIONES_ESPEJO.NEXTVAL";
	public static final String T_CONCEPTOS_LIQ = "AE01B.AE01B01T00" + DBLINK;
	public static final String T_CONFIG_SIPCA = "AE01B.AE01B07T00" + DBLINK;
	public static final String T_TIPOS_INGRESO = "AE01B.AE01B30T00" + DBLINK;
	public static final String SEQUENCE_LIQUIDACIONES = "AE01B.AE01B00T00_SEQ.NEXTVAL";

	private JdbcTemplate jdbcTemplate;

	@Resource
	public void setDataSource(DataSource dataSource) {
		this.jdbcTemplate = new JdbcTemplate(dataSource);
	}

	@Override
	public ConfigSipca getConfigSipca() {

		String sql = "SELECT ID_CONFIGURACION_07, " + "COD_ENTIDAD_07, " + "NUM_ENTIDAD_07, " + "SUFIJO_07, "
				+ "DIAS_CARGO_07 " + "FROM " + T_CONFIG_SIPCA;
		return jdbcTemplate.queryForObject(sql, new ConfigSipcaMapper());
	}

	@Override
	public Integer getDiasLimPag() {
		String sql = "SELECT DIAS_LIM_PAG_30 FROM " + T_TIPOS_INGRESO + " WHERE ID_TIPO_INGRESO_30 = 2";
		return jdbcTemplate.queryForObject(sql, Integer.class);
	}

	@Override
	public int volcarLiquidacionesEspejoAFinales(String idEjecucion) {

		StringBuilder insert = new StringBuilder("INSERT INTO ").append(T_LIQUIDACIONES)
				.append("(EJERCICIO_00, ID_TIPO_INGRESO_00, COD_ORIGEN_00, IMPORTE_00, F_EMISION_00, ")
				.append(" F_LIMITE_PAGO_00, ID_TERRITORIO_00, EXPEDIENTE_00, CONCEPTO_00, TIPO_TERCERO_00, TERCERO_00, ")
				.append(" NOM_RAC_SOC_00, APELLIDO1_00, APELLIDO2_00, IND_DOMIC_00, IBAN_00, F_MANDATO_00, ")
				.append(" F_CARGO_00, ESTADO_LIQ_00, MANDATO_00 , USU_ALTA_00, F_ALTA_00, ID_EJEC_PROCES_00 ) ")
				.append(" SELECT ")
				.append(" EJERCICIO_00, ID_TIPO_INGRESO_00, COD_ORIGEN_00, IMPORTE_00, F_EMISION_00, ")
				.append(" F_LIMITE_PAGO_00, ID_TERRITORIO_00, EXPEDIENTE_00, CONCEPTO_00, TIPO_TERCERO_00, TERCERO_00, ")
				.append(" NOM_RAC_SOC_00, APELLIDO1_00, APELLIDO2_00, IND_DOMIC_00, IBAN_00, F_MANDATO_00, ")
				.append(" F_CARGO_00, ESTADO_LIQ_00, MANDATO_00 , USU_ALTA_00, F_ALTA_00, ID_EJEC_PROCES_00  ")
				.append(" FROM ").append(T_LIQUIDACIONES_ESPEJO).append(" WHERE ID_EJEC_PROCES_00=?");
		return jdbcTemplate.update(insert.toString(), idEjecucion);
	}

	@Override
	public int deleteLiquidacionesEspejoEjecucion(String idEjecucion) {
		StringBuilder delete = new StringBuilder("DELETE FROM ").append(T_LIQUIDACIONES_ESPEJO)
				.append(" WHERE ID_EJEC_PROCES_00 = ?");
		return jdbcTemplate.update(delete.toString(), idEjecucion);
	}

	@Override
	public int createLiquidacionesEspejoBatch(List<Liquidacion> lstLiquidaciones, String idEjecucion, int batchSize,
			boolean modoPrueba) {

		StringBuilder insert = new StringBuilder("INSERT INTO ").append(T_LIQUIDACIONES_ESPEJO).append(
				"(ID_LIQUIDACION_ESPEJO, EJERCICIO_00, ID_TIPO_INGRESO_00, COD_ORIGEN_00, IMPORTE_00, F_EMISION_00, ")
				.append(" F_LIMITE_PAGO_00, ID_TERRITORIO_00, EXPEDIENTE_00, CONCEPTO_00, TIPO_TERCERO_00, TERCERO_00, ")
				.append(" NOM_RAC_SOC_00, APELLIDO1_00, APELLIDO2_00, IND_DOMIC_00, IBAN_00, F_MANDATO_00, ")
				.append(" F_CARGO_00, ESTADO_LIQ_00, MANDATO_00 , USU_ALTA_00, F_ALTA_00, ID_EJEC_PROCES_00, MODO_PRUEBA ) ")
				.append(" VALUES ( ").append(SEQUENCE_LIQUIDACIONES_ESPEJO)
				.append(", ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, CURRENT_DATE, ?, ? )");

		int[][] updateCounts = jdbcTemplate.batchUpdate(insert.toString(), lstLiquidaciones, batchSize,
				new ParameterizedPreparedStatementSetter<Liquidacion>() {
					public void setValues(PreparedStatement ps, Liquidacion liquidacion) throws SQLException {

						// Primero trunca los campos a la definici�n del campo en BBDD
						String codOrigen = Utilidades.truncString(liquidacion.getCodOrigen(), 10);
						String expediente = Utilidades.truncString(liquidacion.getExpediente(), 25);
						String concepto = Utilidades.truncString(liquidacion.getConcepto(), 150);
						String tercero = Utilidades.truncString(liquidacion.getTercero(), 20);
						String nomRacSoc = Utilidades.truncString(liquidacion.getNomRacSoc(), 40);
						String apellido1 = Utilidades.truncString(liquidacion.getApellido1(), 25);
						String apellido2 = Utilidades.truncString(liquidacion.getApellido2(), 25);
						String iban = Utilidades.truncString(liquidacion.getIban(), 34);
						String mandato = Utilidades.truncString(liquidacion.getMandato(), 35);
						// Asigna los campos a la insert
						ps.setInt(1, liquidacion.getEjercicio());
						ps.setLong(2, liquidacion.getIdTipoIngreso().getValue());
						ps.setString(3, codOrigen);
						ps.setBigDecimal(4, liquidacion.getImporte());
						ps.setDate(5, new Date(liquidacion.getfEmision().getTime()));

						ps.setDate(6, new Date(liquidacion.getfLimitePago().getTime()));
						ps.setInt(7, liquidacion.getIdTerritorio());
						ps.setString(8, expediente);
						ps.setString(9, concepto);
						ps.setInt(10, liquidacion.getTipoTercero());
						ps.setString(11, tercero);

						ps.setString(12, nomRacSoc);
						ps.setString(13, apellido1);
						ps.setString(14, apellido2);
						ps.setInt(15, liquidacion.getIndDomic());
						ps.setString(16, iban);
						ps.setDate(17, new Date(liquidacion.getfMandato().getTime()));

						ps.setDate(18, new Date(liquidacion.getfCargo().getTime()));
						ps.setInt(19, liquidacion.getEstadoLiq());
						ps.setString(20, mandato);
						ps.setString(21, UtilProperties.Props.USER_PROCESS.val());
						ps.setString(22, idEjecucion);
						ps.setInt(23, modoPrueba ? ConstantesBatch.VAL_NUM_SI : ConstantesBatch.VAL_NUM_NO);
					}
				});

		return updateCounts.length;
	}

	@Override
	public int createConceptosLiquidacion(String idEjecucion) {

		String insert = "INSERT INTO " + T_CONCEPTOS_LIQ
				+ "(ID_LIQUIDACION_01, ID_CONCEPTO_01, IMPORTE_01, NUMLINEA_01,	USU_ALTA_01, F_ALTA_01 )" + "SELECT "
				+ "ID_LIQUIDACION_00, " + "? AS ID_CONCEPTO, " + "IMPORTE_00, " + "? AS NUM_LINEA, " + "? , "
				+ "CURRENT_DATE " + " FROM	" + T_LIQUIDACIONES + " WHERE ID_EJEC_PROCES_00 = ?";

		return jdbcTemplate.update(insert, 2, 1, UtilProperties.Props.USER_PROCESS.val(), idEjecucion);
	}

	private class ConfigSipcaMapper implements RowMapper<ConfigSipca> {

		public ConfigSipca mapRow(ResultSet rs, int rowNum) throws SQLException {

			ConfigSipca item = new ConfigSipca();
			item.setIdConfiguracion(rs.getLong("ID_CONFIGURACION_07"));
			item.setCodEntidad(rs.getString("COD_ENTIDAD_07"));
			item.setNumEntidad(rs.getString("NUM_ENTIDAD_07"));
			item.setSufijo(rs.getString("SUFIJO_07"));
			item.setDiasCargo(rs.getInt("DIAS_CARGO_07"));

			return item;
		}
	}

	@Override
	public Long createLiquidacionAyto(Liquidacion liquidacion) {

		Long idLiquidacion = jdbcTemplate.queryForObject("SELECT " + SEQUENCE_LIQUIDACIONES + " FROM dual" + DBLINK,
				Long.class);

		String insert = "INSERT INTO " + T_LIQUIDACIONES
				+ "(ID_LIQUIDACION_00, EJERCICIO_00, ID_TIPO_INGRESO_00, COD_ORIGEN_00, IMPORTE_00, F_EMISION_00, "
				+ " F_LIMITE_PAGO_00, ID_TERRITORIO_00, EXPEDIENTE_00, CONCEPTO_00, TIPO_TERCERO_00, TERCERO_00, "
				+ " NOM_RAC_SOC_00, IND_DOMIC_00, IBAN_00, F_MANDATO_00, "
				+ " F_CARGO_00, ESTADO_LIQ_00, MANDATO_00 , USU_ALTA_00, F_ALTA_00 ) " + " VALUES("
				+ ":idLiquidacion, :ejercicio, :idTipoIngreso, :codOrigen, :importe, :fEmision, "
				+ ":fLimitePago, :idTerritorio, :expediente, :concepto, :tipoTercero, :tercero, "
				+ ":nombre, :indDomic, :iban, :fMandato, " + ":fCargo, :estadoLiq, :mandato, :usuario, CURRENT_DATE)";

		MapSqlParameterSource parameters = new MapSqlParameterSource().addValue("idLiquidacion", idLiquidacion)
				.addValue("ejercicio", liquidacion.getEjercicio())
				.addValue("idTipoIngreso", liquidacion.getIdTipoIngreso().getValue())
				.addValue("codOrigen", liquidacion.getCodOrigen()).addValue("importe", liquidacion.getImporte())
				.addValue("fEmision", liquidacion.getfEmision()).addValue("fLimitePago", liquidacion.getfLimitePago())
				.addValue("idTerritorio", liquidacion.getIdTerritorio())
				.addValue("expediente", liquidacion.getExpediente()).addValue("concepto", liquidacion.getConcepto())
				.addValue("tipoTercero", liquidacion.getTipoTercero()).addValue("tercero", liquidacion.getTercero())
				.addValue("nombre", liquidacion.getNomRacSoc()).addValue("indDomic", liquidacion.getIndDomic())
				.addValue("iban", liquidacion.getIban()).addValue("fMandato", liquidacion.getfMandato())
				.addValue("fCargo", liquidacion.getfCargo()).addValue("estadoLiq", liquidacion.getEstadoLiq())
				.addValue("mandato", liquidacion.getMandato())
				.addValue("usuario", UtilProperties.Props.USER_PROCESS.val());

		NamedParameterJdbcTemplate namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(jdbcTemplate);
		namedParameterJdbcTemplate.update(insert, parameters);

		return idLiquidacion;

	}

	@Override
	public void createConceptoAyto(Concepto concepto) {
		String insert = "INSERT INTO " + T_CONCEPTOS_LIQ
				+ "(ID_LIQUIDACION_01, ID_CONCEPTO_01, IMPORTE_01, NUMLINEA_01,	USU_ALTA_01, F_ALTA_01 ) "
				+ " VALUES(?, ?, ?, ?, ?, CURRENT_DATE ) ";

		jdbcTemplate.update(insert, concepto.getIdLiquidacion(), concepto.getIdConcepto().getValue(),
				concepto.getImporte(), 1, UtilProperties.Props.USER_PROCESS.val());
	}

	@Transactional(readOnly = true)
	public Collection<String> comprobarLiquidacionesGeneradas(String idEjecucion) {
		Collection<String> errors = new ArrayList<>();
		StringBuilder sql;
		Integer auxContador;
		Map<String, Object> auxMap;

		final String sinDniValor = "SIN_DNI";
		/*- COMPROBAR QUE NO HAY NINGUN TERCERO_00 CON DNI 'SIN_DNI' */
		sql = new StringBuilder("SELECT COUNT(1) FROM ").append(T_LIQUIDACIONES_ESPEJO).append(" WHERE ID_EJEC_PROCES_00 = ? ");
		sql.append(" AND UPPER(TERCERO_00) = ? ");
		if ((auxContador = jdbcTemplate.queryForObject(sql.toString(), new Object[] { idEjecucion, sinDniValor },
				Integer.class)) > 0) {
			errors.add(String.format(
					"Existen %s registros en las liquidaciones generadas, en los que se ha indicado un tercero '%s'",
					auxContador, sinDniValor));
		}

//		/*- COMPROBAR IBAN_00, TERCERO_00, NOM_RAC_SOC_00 NO SEAN NULL */
//		sql = new StringBuilder("SELECT COUNT(1) FROM ").append(T_LIQUIDACIONES_ESPEJO).append(" WHERE ID_EJEC_PROCES_00 = ? ");
//		sql.append(" AND (TERCERO_00 IS NULL OR (IBAN_00 IS NULL AND IND_DOMIC_00 = 1) OR NOM_RAC_SOC_00 IS NULL OR TIPO_TERCERO_00 IS NULL)");
//		if ((auxContador = jdbcTemplate.queryForObject(sql.toString(), new Object[] { idEjecucion },
//				Integer.class)) > 0) {
//			errors.add(String.format(
//					"Existen %s registros en las liquidaciones generadas, en los que el n\u00FAmero de identificaci\u00F3n, el tipo de identificaci\u00F3n, el iban o la raz\u00F3n social est\u00E1n vac\u00EDos",
//					auxContador));
//		}


		/*- COMPROBAR QUE EL NUMERO DE MENSUALIDADES GENERADAS SEA IGUAL AL NUMERO DE LIQUIDACIONES REGISTRADAS */
		sql = new StringBuilder("SELECT ");
		sql.append("(SELECT COUNT(1) FROM ").append(CopagoBeneficiarioDaoImpl.T_MENSUALIDADES_ESPEJO).append(" WHERE ID_EJEC_PROCES_89=?) mensualidades, ");
		sql.append("(SELECT COUNT(1) FROM ").append(LiquidacionDaoImpl.T_LIQUIDACIONES_ESPEJO).append(" WHERE ID_EJEC_PROCES_00=?) liquidaciones ");
		sql.append("FROM DUAL");
		auxMap = jdbcTemplate.queryForMap(sql.toString(), idEjecucion, idEjecucion);
		if (!auxMap.get("mensualidades").equals(auxMap.get("liquidaciones"))) {
			errors.add(String.format(
					"El n\u00FAmero de mensualidades generadas (%s) no coincide con el n\u00FAmero de liquidaciones obtenidas (%s)",
					auxMap.get("mensualidades"), auxMap.get("liquidaciones")));
		}

		// ...¿mas?

		return errors;
	}
	
	private RowMapper<Liquidacion> rwMap = new RowMapper<Liquidacion>() {
		public Liquidacion mapRow(ResultSet resultSet, int rowNum) throws SQLException {
			Liquidacion liquidacion = new Liquidacion();
			liquidacion.setIdLiquidacion(resultSet.getLong("IDLIQUIDACIONESPEJO"));
			liquidacion.setCodOrigen(resultSet.getString("CODORIGEN00"));
			liquidacion.setTipoTercero(resultSet.getInt("TIPOTERCERO00"));
			liquidacion.setTercero(resultSet.getString("TERCERO00"));
			liquidacion.setNomRacSoc(resultSet.getString("NOMRACSOC00"));
			liquidacion.setApellido1(resultSet.getString("APELLIDO100"));
			liquidacion.setApellido2(resultSet.getString("APELLIDO200"));
			liquidacion.setIban(resultSet.getString("IBAN00"));			
			liquidacion.setExpediente(resultSet.getString("EXPEDIENTE00"));			
			return liquidacion;
		}
	};
	
	@Transactional(readOnly = true)
	public List<Liquidacion> obtenerLiquidacionesGeneradasEspejo(String idEjecucion) {
		
		StringBuilder sql = new StringBuilder();
		sql.append("SELECT ID_LIQUIDACION_ESPEJO IDLIQUIDACIONESPEJO, COD_ORIGEN_00 CODORIGEN00, TIPO_TERCERO_00 TIPOTERCERO00, TERCERO_00 TERCERO00, ");
		sql.append("APELLIDO1_00 APELLIDO100, APELLIDO2_00 APELLIDO200, NOM_RAC_SOC_00 NOMRACSOC00, IBAN_00 IBAN00, EXPEDIENTE_00 EXPEDIENTE00 ");
		sql.append("FROM ").append(LiquidacionDaoImpl.T_LIQUIDACIONES_ESPEJO).append(" WHERE ID_EJEC_PROCES_00=?");		
		
		return this.jdbcTemplate.query(sql.toString(), this.rwMap, idEjecucion);
		
	}
}
