package com.mx.dla.dda.contrato.generales.bos;

import java.sql.SQLException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.ibatis.exceptions.PersistenceException;
import org.apache.ibatis.executor.result.ResultMapException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Component;

import com.mx.dla.dda.contrato.generales.daos.OpcionesContratoDAO;
import com.mx.dla.dda.contrato.generales.dtos.BundleReturn;
import com.mx.dla.dda.contrato.generales.dtos.CambioEstatusDTO;
import com.mx.dla.dda.contrato.generales.dtos.ProcesoPendienteDTO;
import com.mx.dla.dda.contrato.generales.enums.CatalogoTipo;
import com.mx.dla.dda.contrato.generales.enums.Estatus;
import com.mx.dla.dda.contrato.generales.enums.MensajeTexto;
import com.mx.dla.dda.contrato.generales.enums.TipoMensaje;
import com.mx.dla.dda.contrato.transaccion.exceptions.dtos.TransaccionException;
import com.mx.dla.global.bos.BaseBO;

@Component
public class OpcionesContratoBO extends BaseBO{
	
	@Autowired
	private OpcionesContratoDAO opcionesContratoDAO;
	
	
	public void insertaComponentesContrato(Long idContrato, List<Long> idsComponentes, CatalogoTipo tipo) throws ResultMapException, SQLException, TransaccionException{
		
		Integer noTitulosEnServicio = null;
		try{
		for (Long idComponente: idsComponentes) {
			
				if(tipo.equals(CatalogoTipo.CATEGORIA)) {
					opcionesContratoDAO.insertarCategoria(idContrato, idComponente);
				}else if(tipo.equals(CatalogoTipo.SERVICIO)) {
					
					noTitulosEnServicio = opcionesContratoDAO.verificaPorcentajeTitulosEnServicio(idContrato, idComponente);
					if(noTitulosEnServicio == null) {
						opcionesContratoDAO.insertarServicio(idContrato, idComponente);
					}
					
				}else if(tipo.equals(CatalogoTipo.TERRITORIO)) {
					opcionesContratoDAO.insertarTerritorio(idContrato, idComponente);
				}else if(tipo.equals(CatalogoTipo.MEDIO)){
					opcionesContratoDAO.insertarMedioEntrega(idContrato, idComponente);
				}else if(tipo.equals(CatalogoTipo.FILIAL)){
					opcionesContratoDAO.insertarFilial(idContrato, idComponente);
				}else if(tipo.equals(CatalogoTipo.TYPE)){
					opcionesContratoDAO.insertarType(idContrato, idComponente);
				}
		}
		} catch (PersistenceException e) {
            throw new TransaccionException("Error al cargar los datos.", e);
        } catch (DataAccessException e) {
            throw new TransaccionException("Error al cargar los datos", e);
        }
	}
	
	public void registraTipoAmortizacion(Long idContrato, String tipoAmortizacion) throws ResultMapException, SQLException, TransaccionException{
		
		try {
			opcionesContratoDAO.registraTipoAmortizacion(idContrato, tipoAmortizacion);
		} catch (PersistenceException e) {
            throw new TransaccionException("Error al cargar los datos.", e);
        } catch (DataAccessException e) {
            throw new TransaccionException("Error al cargar los datos", e);
        }
	}

	public void eliminaComponentes(Long idContrato, CatalogoTipo tipo) throws ResultMapException, SQLException, TransaccionException{
		try{
			
			if(tipo.equals(CatalogoTipo.CATEGORIA)) {
				opcionesContratoDAO.eliminarCategorias(idContrato);
			}else if(tipo.equals(CatalogoTipo.SERVICIO)) {
				opcionesContratoDAO.eliminarServicios(idContrato);
			}else if(tipo.equals(CatalogoTipo.TERRITORIO)) {
				opcionesContratoDAO.eliminarTerritorios(idContrato);
			}else if(tipo.equals(CatalogoTipo.MEDIO)){
				opcionesContratoDAO.eliminarMediosEntrega(idContrato);
			}else if(tipo.equals(CatalogoTipo.FILIAL)){
				opcionesContratoDAO.eliminarFiliales(idContrato);
			}else if(tipo.equals(CatalogoTipo.TYPE)){
				opcionesContratoDAO.eliminarTypes(idContrato);
			}else if(tipo.equals(CatalogoTipo.AREA)){
				opcionesContratoDAO.eliminarContratoArea(idContrato);
			}
			
		} catch (PersistenceException e) {
            throw new TransaccionException("Error al cargar los datos.", e);
        } catch (DataAccessException e) {
            throw new TransaccionException("Error al cargar los datos", e);
        }
	}
	
	public void actualizaTipoAmortizacion(Long idContrato, String tipoAmortizacion) throws ResultMapException, SQLException, TransaccionException{
		
		try {
			opcionesContratoDAO.actualizaTipoAmortizacion(idContrato, tipoAmortizacion);
		} catch (PersistenceException e) {
            throw new TransaccionException("Error al cargar los datos.", e);
        } catch (DataAccessException e) {
            throw new TransaccionException("Error al cargar los datos", e);
        }
	}
	
	public void actulizaEstatus(Long idEstatus, Long idContrato, String expediente) throws ResultMapException, SQLException, TransaccionException {
		
		CambioEstatusDTO cambioEstatusDTO = new CambioEstatusDTO();
		
		try{
			
			opcionesContratoDAO.actualizaEstatus(idEstatus, idContrato);
			cambioEstatusDTO.setIdEstatus(idEstatus);
			cambioEstatusDTO.setIdContrato(idContrato);
			cambioEstatusDTO.setExpediente(expediente);
			cambioEstatusDTO.setFechaEstatus(new Date());
			opcionesContratoDAO.registraCambioEstatus(cambioEstatusDTO);
			
		} catch (PersistenceException e) {
            throw new TransaccionException("Error al cargar los datos.", e);
        } catch (DataAccessException e) {
            throw new TransaccionException("Error al cargar los datos", e);
        }
		
	}
	
	public boolean tieneFechaAutorizacion(Long idContrato) throws ResultMapException, SQLException, TransaccionException {
		boolean respuesta = false;
		
		Date fechaAutorizacion = null;
		
		try {
			
			fechaAutorizacion = opcionesContratoDAO.obtenerFechaAutorizacion(idContrato);
			
			if(fechaAutorizacion != null){
				respuesta = true;
			}
			
		}  catch (PersistenceException e) {
            throw new TransaccionException("Error al cargar los datos.", e);
        } catch (DataAccessException e) {
            throw new TransaccionException("Error al cargar los datos", e);
        }
		
		return respuesta;
	}
	
	public void actualizaFechaAutorizacion(Date fechaAutorizacion, Long idContrato) throws ResultMapException, SQLException, TransaccionException {
		
		try{
			
			opcionesContratoDAO.actualizaFechaAutorizacion(fechaAutorizacion, idContrato);
		
		} catch (PersistenceException e) {
            throw new TransaccionException("Error al cargar los datos.", e);
        } catch (DataAccessException e) {
            throw new TransaccionException("Error al cargar los datos", e);
        }
	}
	
	public void ponEnNullMesesPjeExclusivo(Long idContrato) throws ResultMapException, SQLException, TransaccionException {
		
		try {
			
			opcionesContratoDAO.ponEnNullMesesPjeExclusivo(idContrato);
			
		} catch (PersistenceException e) {
            throw new TransaccionException("Error al cargar los datos.", e);
        } catch (DataAccessException e) {
            throw new TransaccionException("Error al cargar los datos", e);
        }
		
	}
	
	public Long actualizaEstatusPadreContrato(Long idContrato, String expediente) throws ResultMapException, SQLException, TransaccionException {

		Long idPadre = null;
		Long estatusPadre = null;

		try {

			idPadre = opcionesContratoDAO.obtenerIdPadreContrato(idContrato);
			estatusPadre = opcionesContratoDAO.obtenerEstatusPadreContrato(idPadre);

			logger.debug("idPadre: {}", idPadre);
			logger.debug("estatusPadre: {}", estatusPadre);

			if (idContrato.longValue() != idPadre.longValue()) {
				logger.debug("paso evaluacion: idContrato ({}) vs idPadre ({})", idContrato.longValue(), idPadre.longValue());
				if (estatusPadre.longValue() == Estatus.Vigente.getValor().longValue()) {
					logger.debug("paso evaluacion: estatusPadre ({}) vs Estatus.Vigente ({})", estatusPadre.longValue(), Estatus.Vigente.getValor().longValue());
					actulizaEstatus(Estatus.Autorizado.getValor(), idPadre, expediente);
				}
			}

		} catch (PersistenceException e) {
            throw new TransaccionException("Error al cargar los datos.", e);
        } catch (DataAccessException e) {
            throw new TransaccionException("Error al cargar los datos", e);
        }

		return idPadre;
	}
	
	public void registraProcesoPendiente(Long idContrato, String clave, Integer estatus) throws ResultMapException, SQLException, TransaccionException {
		
		ProcesoPendienteDTO procesoPendiente = new ProcesoPendienteDTO();
		
		procesoPendiente.setClave(clave);
		procesoPendiente.setIdContrato(idContrato);
		procesoPendiente.setEstatus(estatus);
		
		try {
			
			opcionesContratoDAO.registraProcesoPendiente(procesoPendiente);
			
		} catch (PersistenceException e) {
            throw new TransaccionException("Error al cargar los datos.", e);
        } catch (DataAccessException e) {
            throw new TransaccionException("Error al cargar los datos", e);
        }
		
	}
	
	
	public boolean esContratoAmortizable(Long idContrato) throws ResultMapException, SQLException, TransaccionException {
		boolean respuesta = false;
		String valor = "";
		
		try {
			
			valor = opcionesContratoDAO.obtenerValorAmortizable(idContrato);
			
			if(valor.equals("SI")) {
				respuesta = true;
			}
			
		} catch (PersistenceException e) {
            throw new TransaccionException("Error al cargar los datos.", e);
        } catch (DataAccessException e) {
            throw new TransaccionException("Error al cargar los datos", e);
        }
		
		return respuesta;
	}
	
	public String obtenerNumeroContrato(Long idContrato) throws ResultMapException, SQLException, TransaccionException {
		String numeroContrato = "";
		try {
			
			numeroContrato = opcionesContratoDAO.obtenerNumeroContrato(idContrato);
			
		} catch (PersistenceException e) {
            throw new TransaccionException("Error al cargar los datos.", e);
        } catch (DataAccessException e) {
            throw new TransaccionException("Error al cargar los datos", e);
        }
		
		return numeroContrato;
	}
	
	public boolean llamarAjustaAddendum(Long idContrato) throws ResultMapException, SQLException, TransaccionException {
		boolean respuesta = true;
		
		Map<String, Object> parametroSP = new HashMap<String, Object>();
		parametroSP.put("idContrato", idContrato);
		
		try {
			
			opcionesContratoDAO.llamarAjustaAddendum(parametroSP);
			
		} catch (PersistenceException e) {
            throw new TransaccionException("Error al cargar los datos.", e);
        } catch (DataAccessException e) {
            throw new TransaccionException("Error al cargar los datos", e);
        }
		
		return respuesta;
	}
	
	public boolean llamarReportePagos(Long idContrato) throws ResultMapException, SQLException, TransaccionException {
		boolean respuesta = true;
		
		Map<String, Object> parametroSP = new HashMap<String, Object>();
		parametroSP.put("idContrato", idContrato);
		
		try {
			
			opcionesContratoDAO.llamarReportePagos(parametroSP);
			
		} catch (PersistenceException e) {
            throw new TransaccionException("Error al cargar los datos.", e);
        } catch (DataAccessException e) {
            throw new TransaccionException("Error al cargar los datos", e);
        }
		
		return respuesta;
	}
	
	public boolean llamarAmortizacionInicial(Long idContrato) throws ResultMapException, SQLException, TransaccionException {
		boolean respuesta = true;
		
		Map<String, Object> parametroSP = new HashMap<String, Object>();
		parametroSP.put("idContrato", idContrato);
		
		try {
			
			opcionesContratoDAO.llamarAmortizacionInicial(parametroSP);
			
		} catch (PersistenceException e) {
            throw new TransaccionException("Error al cargar los datos.", e);
        } catch (DataAccessException e) {
            throw new TransaccionException("Error al cargar los datos", e);
        }
		
		return respuesta;
	}
	
	public boolean llamarAmortizacionCpv(Long idContrato) throws ResultMapException, SQLException, TransaccionException {
		boolean respuesta = true;
		
		Map<String, Object> parametroSP = new HashMap<String, Object>();
		parametroSP.put("idContrato", idContrato);
		
		try {
			
			opcionesContratoDAO.llamarAmortizacionCpv(parametroSP);
			
		} catch (PersistenceException e) {
            throw new TransaccionException("Error al cargar los datos.", e);
        } catch (DataAccessException e) {
            throw new TransaccionException("Error al cargar los datos", e);
        }
		
		return respuesta;
	}
	
	public BundleReturn cancelarContrato(Date fechaCancelacion, Long idContrato, String expedienteUsuario, Long tipoContrato) throws ResultMapException, SQLException, TransaccionException{
		
		BundleReturn respuesta = new BundleReturn();
		List<Long> idFacturas = null;
		
		respuesta.setCadena(MensajeTexto.CONTRATO_NO_CANCELADO.getTexto());
		respuesta.setNumero(TipoMensaje.ERROR.getValor());
		respuesta.setEstado(false);
		
		try{
			
			idFacturas = opcionesContratoDAO.obtenerIdFacturas(fechaCancelacion, idContrato);
			
			if(idFacturas.size() == 0){
				
				respuesta.setCadena(MensajeTexto.CONTRATO_CANCELADO.getTexto());
				respuesta.setNumero(TipoMensaje.EXITO.getValor());
				respuesta.setEstado(true);
				
				actulizaEstatus(Estatus.Cancelado.getValor(), idContrato, expedienteUsuario);
				
				if(tipoContrato != 2)
					opcionesContratoDAO.eliminaDespuesFechaCancelacion(fechaCancelacion, idContrato);
				
				opcionesContratoDAO.actualizafechaCancelacion(fechaCancelacion, idContrato);
			}
			
		} catch (PersistenceException e) {
            throw new TransaccionException("Error al cargar los datos.", e);
        } catch (DataAccessException e) {
            throw new TransaccionException("Error al cargar los datos", e);
        }
		
		
		return respuesta;
	}
	
	public void insertaTotalTitulos(Long idContrato, Integer totalTitulos) throws ResultMapException, SQLException, TransaccionException {
		try {
			logger.info("Insertando Total Titulos");
			opcionesContratoDAO.insertaTotalTitulos(idContrato, totalTitulos);
		}  catch (PersistenceException e) {
            throw new TransaccionException("Error al cargar los datos.", e);
        } catch (DataAccessException e) {
            throw new TransaccionException("Error al cargar los datos", e);
        }
	}
	
	public boolean validaTotalTitulos(Long idContrato) throws ResultMapException, SQLException, TransaccionException {
		Long idConQuery = null;
		boolean resp = false;
		try {
			logger.info("Valida Total Titulos");
			idConQuery = opcionesContratoDAO.validaTotalTitulos(idContrato);
			if(idConQuery != null)
				resp = true;
		}  catch (PersistenceException e) {
            throw new TransaccionException("Error al cargar los datos.", e);
        } catch (DataAccessException e) {
            throw new TransaccionException("Error al cargar los datos", e);
        }
		
		return resp;
	}
	
	public void actualizaTotalTitulos(Long idContrato, Integer totalTitulos) throws ResultMapException, SQLException, TransaccionException {
		try {
			logger.info("Actualiza Total Titulos");
			opcionesContratoDAO.actulizaTotalTitulos(idContrato, totalTitulos);
		}  catch (PersistenceException e) {
            throw new TransaccionException("Error al cargar los datos.", e);
        } catch (DataAccessException e) {
            throw new TransaccionException("Error al cargar los datos", e);
        }
	}
	
	public void actualizaEstadosBypassWorkflow(Long idContrato, String expediente) throws ResultMapException, SQLException, TransaccionException{
		try {
			opcionesContratoDAO.actualizaEstatus(Estatus.Notificacion.getValor(), idContrato);
			opcionesContratoDAO.completaWorkflowContrato(idContrato, expediente);
		}  catch (PersistenceException e) {
            throw new TransaccionException("Error al cargar los datos.", e);
        } catch (DataAccessException e) {
            throw new TransaccionException("Error al cargar los datos", e);
        }
	}

}
