package com.mx.dla.dda.contrato.transaccion.titulos.bos;

import java.io.File;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import com.mx.dla.dda.carga.transaccion.ws.asociarTitulosTransCntVigentes.ResponseAsociarTitTransCntVigentesDTO;
import com.mx.dla.dda.catalogos.dtos.CatalogoDTO;
import com.mx.dla.dda.contrato.generales.daos.GeneralesDAO;
import com.mx.dla.dda.contrato.generales.dtos.ContratoDTO;
import com.mx.dla.dda.contrato.generales.enums.Movimiento;
import com.mx.dla.dda.contrato.titulo.constants.TipoCargaDocumento;
import com.mx.dla.dda.contrato.titulo.dtos.Lista;
import com.mx.dla.dda.contrato.titulo.dtos.RespuestaCargaExcel;
import com.mx.dla.dda.contrato.titulo.exception.TituloException;
import com.mx.dla.dda.contrato.transaccion.exceptions.dtos.TransaccionException;
import com.mx.dla.dda.contrato.transaccion.titulos.daos.TituloLoteTransDAO;
import com.mx.dla.dda.contrato.transaccion.titulos.daos.TituloTransDAO;
import com.mx.dla.dda.contrato.transaccion.titulos.dtos.TituloTransaccionExcel;
import com.mx.dla.dda.contrato.transaccion.titulos.dtos.TituloValidaEstatusDTO;
import com.mx.dla.dda.contrato.transaccion.ws.titulos.dtos.ParamCargaTitulosTRDTO;
import com.mx.dla.dda.contrato.transaccion.ws.titulos.dtos.ParamInventarioTitulosDTO;
import com.mx.dla.dda.contrato.transaccion.ws.titulos.dtos.ResponseCargaTitulosTRDTO;
import com.mx.dla.dda.contrato.transaccion.ws.titulos.dtos.ResponseNotificarInventarioTitulosDTO;
import com.mx.dla.dda.contrato.ws.cargaTitulos.ParamCargaTitulosDTO;
import com.mx.dla.dda.contrato.ws.cargaTitulos.ResponseCargaTitulosDTO;
import com.mx.dla.dda.excelMapper.bos.BeanPopulator;
import com.mx.dla.dda.excelMapper.bos.ExcelMapperTransform;
import com.mx.dla.dda.excelMapper.exceptions.ExcelMapperException;
import com.mx.dla.dda.restClient.bos.DLARestClient;
import com.mx.dla.dda.restClient.bos.DLARestClientFactory;
import com.mx.dla.dda.restClient.constants.DLARestServices;
import com.mx.dla.global.bos.BaseBO;

@Component
public class TituloTranBO extends BaseBO{

	@Autowired
	private GeneralesDAO generalesDAO;
	
	@Autowired
	private TituloLoteTransDAO tituloLoteDAO;
			
	@Autowired
	private TituloTransDAO tituloDAO;
	
	@Autowired
	private BeanPopulator beanPopulator;
	
	@Autowired
	protected ExcelMapperTransform excelMapperTransform;
	
	@Autowired
	private DLARestClientFactory dlaRestClientFactory;
	
	@Value("${uri.file.titulos}")
	protected String uriErrores;
	
	@Value("${uri.file.carga.titulosTR}")
	protected String uriCarga;
	
	public void init(Long idContrato, Date fechaInicio, boolean isAuto)
	{
		Lista lista = tituloDAO.buscarListaActual(idContrato, Lista.REAL);				
		if (lista == null) 
			lista =  this.crearListaNueva(idContrato, fechaInicio, Lista.REAL);	
		if (!isAuto) {
			this.createMirrorEntities(idContrato);
		}
	}
	
	public Lista crearListaNueva(Long idContrato, Date fechaInicio , String prefix)
	{
		Lista l = new Lista(idContrato, fechaInicio, prefix);				
		tituloDAO.insertarLista(l, prefix, idContrato, fechaInicio);
		return l;
	}

	public Lista buscarListaActual(Long idContrato, String prefix)
	{
		Lista lista = tituloDAO.buscarListaActual(idContrato, prefix);
		
        return lista;									
	}
	
	public void createMirrorEntities(Long idContrato)
	{
		tituloLoteDAO.borrarTitulosPorContratoTran(Lista.MIRROR, idContrato);
		tituloLoteDAO.borrarListaPorIdContrato    (Lista.MIRROR, idContrato);						
		tituloLoteDAO.moverLista                  (Lista.REAL, Lista.MIRROR, idContrato);
		tituloLoteDAO.moverTitulos                (Lista.REAL, Lista.MIRROR, idContrato);									
	}
			
	public void guardarCambiosPermanente(Long idContrato)
	{
		TituloValidaEstatusDTO estatus = null;
		ResponseNotificarInventarioTitulosDTO responsenotificainventario = null;
		
		tituloLoteDAO.borrarTitulosPorContratoTran(Lista.REAL, idContrato);
		tituloLoteDAO.borrarListaPorIdContrato    (Lista.REAL, idContrato);		
		tituloLoteDAO.moverLista                  (Lista.MIRROR, Lista.REAL, idContrato);
		tituloLoteDAO.moverTitulos                (Lista.MIRROR, Lista.REAL, idContrato);
		
		     //may-17
		     try{	
		    	     
		    	     // llamada a SP DDA_CNT_CALCULAR_MG
		    	     tituloLoteDAO.calcularMG(idContrato);		    	     
		    	     
		    	     //se recupera estatus del contrato
		    	     estatus= this.validaEstatusContrato(idContrato);
		    	     
		    	     Long idEstatus = estatus.getEstatus();
		    	     //si el estatus es vigente se llama al WS - WS_TRANSACCIONTITULOS_NOTIFICAR_INVENTARIOS
		    	     if(idEstatus == 5){
		    	    	 
		    	    	 responsenotificainventario = this.notificarInventarioTitulos(idContrato);
		    	     
		    	     }else{
		    	    	 logger.info("notificarInventarioTitulos. No se Notifico, el contrato no esta vigente: "+idContrato);
		    	     }
		    	     
		     } catch(Exception e)
			 {
					logger.error("Error.calcularMG - al notificar el contrato:__"+e);
			 }
	}
	
	//may-17 
	public TituloValidaEstatusDTO validaEstatusContrato(Long idContrato) throws TransaccionException
	{
		TituloValidaEstatusDTO estatuscontrato = null;
		
		try{
			
			estatuscontrato = tituloLoteDAO.validaEstatusContrato(idContrato);
			
		}catch (Exception ex) {
			throw new TransaccionException("Error.TituloTranBO - al validar el estatus del Contrato.", ex);
		}
		
		return estatuscontrato;
	}
	
	//may-17
	public ResponseNotificarInventarioTitulosDTO notificarInventarioTitulos(Long idContrato) throws TransaccionException{
		
		ResponseNotificarInventarioTitulosDTO response = null;
		ParamInventarioTitulosDTO request = new ParamInventarioTitulosDTO();
		DLARestClient client = null;
		
		try{
			  Long idContratoTrans = idContrato;
			  
			    client = dlaRestClientFactory.getClient(DLARestServices.WS_TRANSACCIONTITULOS_NOTIFICAR_INVENTARIOS);
				request.setIdContrato(idContratoTrans.toString());
				logger.debug("REQUEST - WS_TRANSACCIONTITULOS_NOTIFICAR_INVENTARIOS : [{}]", request);
				response = client.get(request, ResponseNotificarInventarioTitulosDTO.class);

				logger.debug("RESPONSE . WS_TRANSACCIONTITULOS_NOTIFICAR_INVENTARIOS : [{}]", response);

                			
			
		}catch(Exception ex){
			throw new TransaccionException("Error al ejecutar el recalculo de pago.", ex);
		}
		
		return response;
	}
		
	public byte [] generateExcelReport(Long  idLista) throws ExcelMapperException, IOException
	{
		logger.debug("Descargar archivo de excel [{}]", idLista);
		List<TituloTransaccionExcel> lista = new ArrayList<TituloTransaccionExcel>();
		try
		{
			lista = tituloDAO.obtenerTitulosExcel(idLista);			
			if(lista == null || lista.isEmpty())
			{
				lista = new ArrayList<TituloTransaccionExcel>();
				lista.add(beanPopulator.initObject(TituloTransaccionExcel.class));
			}			   											
			logger.debug("Descargar archivo, se han  obtenido [{}]",lista.size());
			
		}catch(Exception e)
		{
			logger.error("Error al buscar contenido de titulos");
		}
		
		byte[] fileExcel = excelMapperTransform.transformObjectToExcel(lista,"tituloTransaccionExportarLista",TituloTransaccionExcel.class);
		logger.debug("Descargar archivo, se ha generado binario.");
		return fileExcel; 
	}
	
	public String generaNombreDescarga(){
		Date a = new Date();
		SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy");
		String fileFileName = "plantilla-"+sdf.format(a)+".xlsx";
		return fileFileName;
	}
	
	//jun-17
	public RespuestaCargaExcel cargaMasivaTitulos(String inicioLista, Long idContrato, String tc, File fileUpload, String fileName, Long idLista, String expediente) throws TituloException, Exception {
		
		RespuestaCargaExcel r = new RespuestaCargaExcel();		
        /*													
		                        idLista  = this.ajustarListaEnmiendas(tc, inicioLista, idContrato, idLista);  
		File                    archivo  = this.guardarArchivoSistema(idContrato, expediente, fileName, fileUpload);			
		ParamCargaTitulosDTO    request  = this.generaObjetoRequestRest(idContrato, expediente, idLista, tc, archivo.getCanonicalPath(), inicioLista);						
		ResponseCargaTitulosDTO response = this.llamarRestCargaTitulos(request,idContrato);		
	                            r        = this.actualizaLista(idContrato);	 
	    */
		idLista  = this.ajustarListaEnmiendas(tc, inicioLista, idContrato, idLista);  
		File                    archivo  = this.guardarArchivoSistema(idContrato, expediente, fileName, fileUpload);			
		ParamCargaTitulosTRDTO    request  = this.generaObjRequestWs(idContrato, expediente, idLista, tc, archivo.getCanonicalPath(), inicioLista);						
		ResponseCargaTitulosTRDTO response = this.llamadaRestCargaTransaccionesTitulos(request,idContrato);		
	                            r        = this.actualizaLista(idContrato);
	                            
		r.setResponseTR(response);
		
		return r;
	}
	
	 /*
	   * Metodo que crea una nueva lista. si el contrato es una enmienda y el usuario carga titulos vía excel, 
	   * y ha seleccionado la opción nueva lista.
	*/	
	public Long ajustarListaEnmiendas(String tc, String inicioLista, Long idContrato, Long idLista) throws ParseException{
		if(tc.compareTo(TipoCargaDocumento.NUEVA.getValue()) == 0)
		{
			SimpleDateFormat formatter = new SimpleDateFormat("MM-dd-yyyy");
			Date fecha   = formatter.parse(inicioLista);
			Lista listaA = tituloDAO.buscarListaActual(idContrato, Lista.MIRROR);												
			tituloDAO.actualizarFechaFinLista(listaA.getIdLista(), Lista.MIRROR, this.calculaFechaMenosUnDia(fecha));
			Lista nueva  = this.crearListaNueva(idContrato, fecha, Lista.MIRROR);
			idLista = nueva.getIdLista();
		}
		return idLista;
	}
	
	public File guardarArchivoSistema(Long idContrato, String expediente, String fileName, File fileUpload) throws IOException{
		byte [] f = FileUtils.readFileToByteArray(fileUpload);
		File d = new File(uriCarga + idContrato + expediente + fileName);
		 
		d.setExecutable(true, false);
        d.setReadable(true, false);
        d.setWritable(true, false);
		
        logger.debug("Absolute path [{}]  -  [{}]",d.getCanonicalPath() , d.getPath());
		FileUtils.writeByteArrayToFile(d, f);
		return d;
	}
	
	public ParamCargaTitulosDTO generaObjetoRequestRest(Long idContrato, String expediente, Long idLista, String tipoCambio, String archivo, String fechaInicioLista){					
		ParamCargaTitulosDTO request = new ParamCargaTitulosDTO();
		
		request.setNombreArchivo        (FilenameUtils.getName(archivo));
		request.setIdContrato           (idContrato.toString());
		request.setIdListaActual        (idLista.toString());
		request.setTipoLista            (TipoCargaDocumento.NUEVA.getValue().equals(tipoCambio)  ? "NUEVA" : "ACTUAL");
		request.setTipoCarga            (TipoCargaDocumento.ANEXAR.getValue().equals(tipoCambio) ? "AGREGAR" : "REEMPLAZAR");
		request.setExpediente           (expediente);				
		request.setFechaInicioListaNueva(fechaInicioLista != null ?  fechaInicioLista : "");
		logger.debug("Request carga titulos [{}]",request);
		return request;
	}
	
	//JUN-17 carga de titulos en transacciones
	public ParamCargaTitulosTRDTO generaObjRequestWs(Long idContrato, String expediente, Long idLista, String tipoCambio, String archivo, String fechaInicioLista){					
		ParamCargaTitulosTRDTO request = new ParamCargaTitulosTRDTO();
		
		request.setNombreArchivo        (FilenameUtils.getName(archivo));
		request.setIdContrato           (idContrato.toString());
		request.setIdListaActual        (idLista.toString());
		request.setTipoLista            (TipoCargaDocumento.NUEVA.getValue().equals(tipoCambio)  ? "NUEVA" : "ACTUAL");
		request.setTipoCarga            (TipoCargaDocumento.ANEXAR.getValue().equals(tipoCambio) ? "AGREGAR" : "REEMPLAZAR");
		request.setExpediente           (expediente);				
		request.setFechaInicioListaNueva(fechaInicioLista != null ?  fechaInicioLista : "");
		logger.debug("Request carga transacciones titulos [{}]",request);
		
		return request;
	}
	
	public ResponseCargaTitulosDTO llamarRestCargaTitulos(ParamCargaTitulosDTO request, Long idContrato ) throws TituloException{
		
		DLARestClient           c        = dlaRestClientFactory.getClient(DLARestServices.CARGA_TITULOS);						
		ResponseCargaTitulosDTO response = c.get(request, ResponseCargaTitulosDTO.class );		
		logger.info("Response carga titulos [{}]",response);
		
		/*ResponseCargaTitulosDTO response = new ResponseCargaTitulosDTO(); 
		CargaPrincipalDTO c = new CargaPrincipalDTO();
        c.setID_CARGA("1");
        c.setTOTAL_ERROR("10");
        response.setDatosCarga(c);
        response.setResultado(false);
        response.setMensaje("prueba errores");
        */				
		this.generaArchivoErrores(response, idContrato);						
		return response;
	}
	
	//jun-17
	public ResponseCargaTitulosTRDTO llamadaRestCargaTransaccionesTitulos(ParamCargaTitulosTRDTO request, Long idContrato ) throws TituloException{
		
		DLARestClient           c        = dlaRestClientFactory.getClient(DLARestServices.WS_TRANSACCION_TITULOS_CARGA);						
		ResponseCargaTitulosTRDTO response = c.get(request, ResponseCargaTitulosTRDTO.class );		
		logger.info("Response carga titulos [{}]",response);
				
		this.generaExcelErrores(response, idContrato);						
		return response;
	}
	
	//jun-17
	public void generaExcelErrores(ResponseCargaTitulosTRDTO response, Long idContrato) throws TituloException{		
		try
		{
			if(!response.getDatosCarga().getTOTAL_ERROR().equals("0"))
			{			
				List<TituloTransaccionExcel> a = new ArrayList<TituloTransaccionExcel>();
				
				a = tituloDAO.obtenerTitulosExcelError(Long.parseLong(response.getDatosCarga().getID_CARGA()));
				logger.debug("{}", a.toString());
				byte[] fileExcel = excelMapperTransform.transformObjectToExcel(a, "tituloTransaccionExcel", TituloTransaccionExcel.class);
							
				File destFile = new File(uriErrores + idContrato+".xlsx");
				FileUtils.writeByteArrayToFile(destFile, fileExcel);			
			}
		
		} catch (ExcelMapperException e) {
			logger.error("Errores [{}]", e.getSErrors());
			logger.error("Error al leer el archivo", e);
		
		} catch (Exception e) {
			logger.error("Error ",e);
			throw new TituloException("Ocurrio un error al subir el documento transacciones.Titulo");
		}
	}
	
	public void generaArchivoErrores(ResponseCargaTitulosDTO response, Long idContrato) throws TituloException{		
		try
		{
			if(!response.getDatosCarga().getTOTAL_ERROR().equals("0"))
			{			
				List<TituloTransaccionExcel> a = new ArrayList<TituloTransaccionExcel>();
				
				a = tituloDAO.obtenerTitulosExcelError(Long.parseLong(response.getDatosCarga().getID_CARGA()));
				logger.debug("{}", a.toString());
				byte[] fileExcel = excelMapperTransform.transformObjectToExcel(a, "tituloTransaccionExcel", TituloTransaccionExcel.class);
							
				File destFile = new File(uriErrores + idContrato+".xlsx");
				FileUtils.writeByteArrayToFile(destFile, fileExcel);			
			}
		
		} catch (ExcelMapperException e) {
			logger.error("Errores [{}]", e.getSErrors());
			logger.error("Error al leer el archivo", e);
		
		} catch (Exception e) {
			logger.error("Error ",e);
			throw new TituloException("Ocurrio un error al subir el documento");
		}
	}
	
	public RespuestaCargaExcel actualizaLista(Long idContrato){
		RespuestaCargaExcel r = new RespuestaCargaExcel();		
		Lista listaA = tituloDAO.buscarListaActual(idContrato, Lista.REAL);
		r.setLista(listaA);		
		return r;
	}
	
	public List<TipoCargaDocumento> buscaTipoCargaDocumento(Long idContrato)
	{
		List<TipoCargaDocumento>  r = new ArrayList<TipoCargaDocumento>();
		r.add(TipoCargaDocumento.ANEXAR);
		r.add(TipoCargaDocumento.REEMPLAZAR);
		
		ContratoDTO contrato = generalesDAO.obtenerContrato(idContrato);
		if(contrato.getIdTipoMovimiento().intValue() == Movimiento.Enmienda.getValor().intValue())		
		   r.add(TipoCargaDocumento.NUEVA);		
		return r;
	}
	
	public List<CatalogoDTO> buscaListas(Long idContrato)
	{
		return tituloDAO.buscarCatListaByContrato(idContrato, Lista.REAL);		
	}
	
	public List<Long> buscaListasValidas(Long idContrato)
	{
		return tituloDAO.buscarListaValidas(idContrato, Lista.REAL);		
	}
	
	public byte [] buscarArchivoDeErrores(Long idContrato) throws  IOException
	{
		File file = new File(uriErrores+idContrato+".xlsx");
		logger.debug("busca archivo en [{}]",file.getAbsolutePath());
		byte [] errores = FileUtils.readFileToByteArray(file);
		return errores; 
	}									
	
	public Integer buscarNumTitulosContratados(Long idContrato) throws  IOException
	{
		return tituloDAO.obtenerNumTitulos(idContrato);
	}
	
	public Date calculaFechaMenosUnDia(Date in)
	{
		Calendar cal = Calendar.getInstance();
		cal.setTime(in);
		cal.set(Calendar.DAY_OF_YEAR, cal.get(Calendar.DAY_OF_YEAR)-1);
		return cal.getTime();
	}		
}