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

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.sql.SQLException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
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.amortizacion.constants.TipoAmortizacion;
import com.mx.dla.dda.contrato.amortizacion.daos.AmortizacionDAO;
import com.mx.dla.dda.contrato.generales.daos.GeneralesDAO;
import com.mx.dla.dda.contrato.generales.dtos.AreaDTO;
import com.mx.dla.dda.contrato.generales.dtos.ContratoDTO;
import com.mx.dla.dda.contrato.generales.dtos.DetalleCatalogoContratoDTO;
import com.mx.dla.dda.contrato.generales.dtos.InfoDetalleContratoDTO;
import com.mx.dla.dda.contrato.generales.enums.Estatus;
import com.mx.dla.dda.contrato.transaccion.exceptions.dtos.TransaccionException;
import com.mx.dla.dda.excelMapper.bos.ExcelMapperTransform;
import com.mx.dla.dda.excelMapper.context.ExcelMapperContext;
import com.mx.dla.dda.excelMapper.dtos.ExcelMapper;
import com.mx.dla.dda.excelMapper.exceptions.ExcelMapperException;
import com.mx.dla.dda.restClient.bos.DLARestClientFactory;
import com.mx.dla.global.bos.BaseBO;

@Component
public class GeneralesBO extends BaseBO{

	@Autowired
	private GeneralesDAO generalesDAO;
	
	@Autowired
	private AmortizacionDAO amortizacionDAO;
	
	@Autowired
	private PoblarGeneralesBO poblarGeneralesBO;
	
	@Autowired
	private ExcelMapperContext excelMapperContext;
	
	@Autowired
	protected ExcelMapperTransform excelMapperTransform;
	
	@Autowired
	public DLARestClientFactory dlaRestClientFactory;
	
	public ContratoDTO registraContrato(Long campoEstudio, Long estatus, Long tipoOperacion, Long tipoContrato, 
			Date campoFechaInicio, Date campoFechaFin, Long apartado, String annios, String meses, 
			String tipoAmortizacion, Date fechaAutorizacion, String claveIva) throws ResultMapException, SQLException, TransaccionException {
		
		estatus = Estatus.Registro.getValor();
		ContratoDTO contratoNuevo = new ContratoDTO();
		Map<String, Object> paramNumeroContrato = new HashMap<String, Object>();
		boolean esVirtual = false;
		
		try{
			
			esVirtual = esEstudioVirtual(campoEstudio); //cambiar por la funcion que estara en Estudios BO
			
			contratoNuevo.setIdEstudio(campoEstudio);
			contratoNuevo.setIdEstatus(estatus);
			contratoNuevo.setIdTipoMovimiento(tipoOperacion);
			contratoNuevo.setIdTipoContrato(tipoContrato); 
			contratoNuevo.setIdApartado(null);
			contratoNuevo.setFechaFin(campoFechaFin);
			contratoNuevo.setFechaInicio(campoFechaInicio);
			contratoNuevo.setIdContratoOriginal(contratoNuevo.getIdContrato());
			contratoNuevo.setFechaAlta(new Date());
			contratoNuevo.setAnnios(annios);
			contratoNuevo.setMeses(meses);
			contratoNuevo.setIdApartado(apartado);
			contratoNuevo.setFechaAutorizacion(fechaAutorizacion);
			contratoNuevo.setClaveIva(claveIva);
			
			if(contratoNuevo.getIdTipoContrato() == 1){
				contratoNuevo.setAmortizable("SI");
			}else{
				contratoNuevo.setAmortizable("NO");
			}
			
			if (tipoContrato == 1) {
			
				if(tipoAmortizacion != null) {
					contratoNuevo.setTipoAmortizacion(TipoAmortizacion.EXCLUSIVIDAD.name());
				}else {
					contratoNuevo.setTipoAmortizacion(TipoAmortizacion.LINEAL.name());
				}
				
			}
			
			generalesDAO.registrarContrato(contratoNuevo);
			
			logger.debug(" idContrato desde insert : " + contratoNuevo.getIdContrato() + " tipoOperacion : " + tipoOperacion);
			
			paramNumeroContrato.put("idEstudio", campoEstudio);
			paramNumeroContrato.put("idTipo", tipoContrato);
			paramNumeroContrato.put("idContrato", contratoNuevo.getIdContrato());
			paramNumeroContrato.put("idMovimiento", tipoOperacion);
			paramNumeroContrato.put("numeroContrato","");
			
			if(esVirtual) {
				String ceros = "000000";
				ceros = ceros.substring(0, contratoNuevo.getIdContrato().toString().length());
				contratoNuevo.setNumeroContrato("ETV" + ceros + contratoNuevo.getIdContrato());
			} else {
				
				generalesDAO.llamarCrearNumeroContrato(paramNumeroContrato); //el return de la función regresa null, el número del contrato esta dentro del map
				logger.debug("Número de contrato recuperado : [{}]", paramNumeroContrato);
				contratoNuevo.setNumeroContrato((String) paramNumeroContrato.get("numeroContrato"));
			}
			
			logger.debug("Número de contrato seteado en ContratoDTO : [{}]", contratoNuevo.getNumeroContrato());
			generalesDAO.actualizaNumeroContrato(contratoNuevo.getIdContrato(), contratoNuevo.getNumeroContrato());
			
		} catch (PersistenceException e) {
            throw new TransaccionException("Error al cargar los datos de actualizacion ", e);
        } catch (DataAccessException e) {
            throw new TransaccionException("Error al cargar los datos de actualizacion ", e);
        }
			logger.debug(contratoNuevo.toString());
		
		return contratoNuevo;
	}
	
	public void registraContratoProceso(Long idContrato) throws ResultMapException, SQLException, TransaccionException {
		logger.debug("En registraContratoProceso --  idContrato : [{}]", idContrato );
		try{
			amortizacionDAO.insertContratoProceso(idContrato, 0);
		} catch (PersistenceException e) {
            throw new TransaccionException("Error al cargar los datos de actualizacion ", e);
        } catch (DataAccessException e) {
            throw new TransaccionException("Error al cargar los datos de actualizacion ", e);
        }
		
	}
	
	public String actualizaContratoProceso(Long idContrato, Integer valorAmortizacion) throws ResultMapException, SQLException, TransaccionException{
		
		String mensaje = "OK";
		
		try{
			amortizacionDAO.updateContratoProceso(idContrato, valorAmortizacion);
		} catch (PersistenceException e) {
            throw new TransaccionException("Error al cargar los datos de actualizacion ", e);
        } catch (DataAccessException e) {
            throw new TransaccionException("Error al cargar los datos de actualizacion ", e);
        }
		
		return mensaje;
	}
	
	public ContratoDTO obtenContrato(Long idContrato) throws ResultMapException, SQLException, TransaccionException {
		
		ContratoDTO contrato = null;
		
		try{
			contrato = generalesDAO.obtenerContrato(idContrato);
		} catch (PersistenceException e) {
            throw new TransaccionException("Error al cargar los datos de actualizacion ", e);
        } catch (DataAccessException e) {
            throw new TransaccionException("Error al cargar los datos de actualizacion ", e);
        }
		
		return contrato;
	}
	
	public void actualizaContrato(Long campoContrato, Long campoEstudio, Date campoFechaInicio, Date campoFechaFin, 
									Long apartado, String annios, String meses, Date campoFechaAutorizacion, String indicador) throws ResultMapException, SQLException, TransaccionException {
		try{
			generalesDAO.actualizaContrato(campoContrato, campoEstudio, campoFechaInicio, campoFechaFin, apartado, annios, meses, campoFechaAutorizacion, indicador);
		} catch (PersistenceException e) {
            throw new TransaccionException("Error al cargar los datos de actualizacion ", e);
        } catch (DataAccessException e) {
            throw new TransaccionException("Error al cargar los datos de actualizacion ", e);
        }
	}
	
	public void cambiarAddendum (Long idContrato, String numeroContrato) throws ResultMapException, SQLException, TransaccionException {
		numeroContrato = numeroContrato.substring(0, 9) + "A";
try {
	generalesDAO.cambiarAddendum(idContrato, numeroContrato);
        } catch (PersistenceException e) {
            throw new TransaccionException("Error al cargar los datos de actualizacion ", e);
        } catch (DataAccessException e) {
            throw new TransaccionException("Error al cargar los datos de actualizacion ", e);
        }
	}
	
	public boolean eliminaContrato(Long idContrato) throws ResultMapException, SQLException, TransaccionException {
		
		Long noError = 0L;
		boolean respuestaDeEliminar = false;
		
		Map<String, Object> parametroSP = new HashMap<String, Object>();
		
		parametroSP.put("idContrato", idContrato);
		parametroSP.put("noError", 0L);
		parametroSP.put("strError", "");
		
		try{
			generalesDAO.llamarEliminaContrato(parametroSP);
			logger.debug("noError : [{}]", parametroSP.get("noError"));
			logger.debug("strError : [{}]", parametroSP.get("strError"));
			noError = (Long) parametroSP.get("noError");
			
			if(noError >= 0) {
				respuestaDeEliminar = true;
			}
		} catch (PersistenceException e) {
            throw new TransaccionException("Error al cargar los datos de actualizacion ", e);
        } catch (DataAccessException e) {
            throw new TransaccionException("Error al cargar los datos de actualizacion ", e);
        }
		
		return respuestaDeEliminar;
	}	
	
	public void cambiaEstudioVirtualContrato(Long idContrato, Long idEstudioOficial, Long idEstudio, boolean eliminaVirtual) throws ResultMapException, SQLException, TransaccionException {
		
		ContratoDTO contrato;
		Map<String, Object> paramNumeroContrato = new HashMap<String, Object>();
		
		try {
			
			generalesDAO.actualizaIdEstudioContrato(idContrato, idEstudioOficial);
			
			contrato = generalesDAO.obtenerContrato(idContrato);
			
			paramNumeroContrato.put("idEstudio", idEstudioOficial);
			paramNumeroContrato.put("idTipo", contrato.getIdTipoContrato());
			paramNumeroContrato.put("idContrato", contrato.getIdContrato());
			paramNumeroContrato.put("idMovimiento", contrato.getIdTipoMovimiento());
			paramNumeroContrato.put("numeroContrato","");
			
			generalesDAO.llamarCrearNumeroContrato(paramNumeroContrato);
			contrato.setNumeroContrato((String) paramNumeroContrato.get("numeroContrato"));
			
			generalesDAO.actualizaNumeroContrato(contrato.getIdContrato(), contrato.getNumeroContrato());
			generalesDAO.actulizaEstudioTitulos(idEstudio, idEstudioOficial);
			
			if(eliminaVirtual) {
				generalesDAO.eliminaEstudioVirtual(idEstudio);
			}
			
			
			
		} catch (PersistenceException e) {
            throw new TransaccionException("Error al cargar los datos de actualizacion ", e);
        } catch (DataAccessException e) {
            throw new TransaccionException("Error al cargar los datos de actualizacion ", e);
        }
		
	}
	
	/*Function to EstudiosBO*/
	public boolean esEstudioVirtual(Long idEstudio) throws ResultMapException, SQLException, TransaccionException {
		String idSap = null;
		
		try {
			idSap = generalesDAO.obtenIdSapEstudio(idEstudio);
		} catch (PersistenceException e) {
            throw new TransaccionException("Error al cargar los datos de actualizacion ", e);
        } catch (DataAccessException e) {
            throw new TransaccionException("Error al cargar los datos de actualizacion ", e);
        }
		
		if(idSap == null) {
			return true;
		} else {
			return false;
		}
	}
	
	public String obtenerFechaSAP() throws ResultMapException, SQLException, TransaccionException {
		String fechaSAP = null;
		
		try {
			
			fechaSAP = generalesDAO.obtenerFechaSAP();
			
		} catch (PersistenceException e) {
            throw new TransaccionException("Error al cargar los datos de actualizacion ", e);
        } catch (DataAccessException e) {
            throw new TransaccionException("Error al cargar los datos de actualizacion ", e);
        }
		
		return fechaSAP;
	}
	
	public AreaDTO obtenerAreaPorExpediente(String expediente) throws ResultMapException, SQLException, TransaccionException {
		
		AreaDTO area = null;
		
		try {
			area = generalesDAO.obtenerAreaPorExpediente(expediente);
		} catch (PersistenceException e) {
            throw new TransaccionException("Error al cargar los datos de actualizacion ", e);
        } catch (DataAccessException e) {
            throw new TransaccionException("Error al cargar los datos de actualizacion ", e);
        }
		
		return area;
	}
	
	public AreaDTO obtenerAreaPorOrdenWF(Integer ordenWF) throws ResultMapException, SQLException, TransaccionException {
		AreaDTO area = null;
		
		try {
			area = generalesDAO.obtenerAreaPorOrdenWF(ordenWF);
		} catch (PersistenceException e) {
            throw new TransaccionException("Error al cargar los datos de actualizacion ", e);
        } catch (DataAccessException e) {
            throw new TransaccionException("Error al cargar los datos de actualizacion ", e);
        }
		
		return area;
	}
	
	public List<AreaDTO> obtenerAreasFinalizadoras() throws ResultMapException, SQLException, TransaccionException {
		List<AreaDTO> areas = null;
		
		try {
			areas = generalesDAO.obtenerAreasFinalizadoras();
		} catch (PersistenceException e) {
            throw new TransaccionException("Error al cargar los datos de actualizacion ", e);
        } catch (DataAccessException e) {
            throw new TransaccionException("Error al cargar los datos de actualizacion ", e);
        }
		
		return areas;
	}
	
	public List<DetalleCatalogoContratoDTO> detalleContrato(Long idContrato) throws ResultMapException, SQLException, TransaccionException{
		List<DetalleCatalogoContratoDTO> detalleCompleto = new ArrayList<DetalleCatalogoContratoDTO>();
		
		try {
			InfoDetalleContratoDTO detalleContrato = generalesDAO.obtenDetalleContrato(idContrato);
			List<DetalleCatalogoContratoDTO> catalogosContrato = generalesDAO.obtenDetalleCatalogos(idContrato);
			
			detalleCompleto.add(creaDetalleCatalogoContrato("Número Contrato", detalleContrato.getNumeroContrato()));
			detalleCompleto.add(creaDetalleCatalogoContrato("Estudio", detalleContrato.getDescripcionEstudio()));
			detalleCompleto.add(creaDetalleCatalogoContrato("Vigencia", poblarGeneralesBO.formateaFecha(detalleContrato.getFechaInicio()) + " - " + 
			poblarGeneralesBO.formateaFecha(detalleContrato.getFechaFin())));
			detalleCompleto.add(creaDetalleCatalogoContrato("Estatus", detalleContrato.getDescripcionEstatus()));
			detalleCompleto.add(creaDetalleCatalogoContrato("Apartado", detalleContrato.getDescripcionApartado()));
			
			if(detalleContrato.getFechaAutorizacion() != null) {
				detalleCompleto.add(creaDetalleCatalogoContrato("Fecha Autorización", poblarGeneralesBO.formateaFecha(detalleContrato.getFechaAutorizacion())));
			}
			
			for(DetalleCatalogoContratoDTO cc:catalogosContrato){
				detalleCompleto.add(cc);
			}
			
		} catch (PersistenceException e) {
            throw new TransaccionException("Error al cargar los datos de actualizacion ", e);
        } catch (DataAccessException e) {
            throw new TransaccionException("Error al cargar los datos de actualizacion ", e);
        }
		
		return detalleCompleto;
	}
	
	public DetalleCatalogoContratoDTO creaDetalleCatalogoContrato(String tipo, String value) {
		DetalleCatalogoContratoDTO dcc = new DetalleCatalogoContratoDTO();
		dcc.setTipo(tipo);
		dcc.setLista(value);
		return dcc;
	}
	
	public InputStream h(Long idContrato) throws ResultMapException, SQLException, TransaccionException {
		
		byte[] bytesExcel = null;
		ExcelMapper mapper = null;
		InputStream is = null;
		
		try {
			mapper = excelMapperContext.getExcelMapper("detalleContrato");
			bytesExcel = excelMapperTransform.transformObjectToExcel(detalleContrato(idContrato), mapper, DetalleCatalogoContratoDTO.class);
			is =  new ByteArrayInputStream(bytesExcel);
		} catch (ExcelMapperException e) {
			logger.error("[{}]", e);
		} catch (IOException e) {
			logger.error("[{}]", e);
		}
		
		return is;
	}
	
	public void crearListaNuevaTransaccion(Long idContrato, Date fechaInicio) throws ResultMapException, SQLException, TransaccionException {
		try {
			generalesDAO.crearListaNuevaTransaccion(idContrato, fechaInicio);
		} catch (PersistenceException e) {
            throw new TransaccionException("Error al cargar los datos de actualizacion ", e);
        } catch (DataAccessException e) {
            throw new TransaccionException("Error al cargar los datos de actualizacion ", e);
        }
	}
	
	
	public void actualizaFechaInicioLista(Long idContrato, Date fechaInicio ) throws ResultMapException, SQLException, TransaccionException {
		try {
			logger.info("en Generales BO TIPO CONTRATO :" + idContrato + "|" + fechaInicio );
			
			DateFormat formatoEntrada = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
			String fecha = formatoEntrada.format(fechaInicio);
			logger.info("en Generales BO fechaInicio 11111111:" + fecha );
			
			SimpleDateFormat formatoFecha = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
			Date fechaInicioLista = formatoFecha.parse(fecha);
			
			logger.info("en Generales BO fechaInicio 2222222:" + fechaInicioLista );
			
			generalesDAO.actualizaFechaLista(idContrato, fechaInicio);
				
		} catch (PersistenceException e) {
            throw new TransaccionException("Error al cargar los datos de actualizacion ", e);
        } catch (DataAccessException e) {
            throw new TransaccionException("Error al cargar los datos de actualizacion ", e);
        } catch (ParseException e) {
        	throw new TransaccionException("Error al cargar los datos de actualizacion ", e);
		}
	}
	
}
