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

import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.type.TypeReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.mx.dla.dda.contrato.amortizacion.daos.AmortizacionDAO;
import com.mx.dla.dda.contrato.fees.daos.FeesContratoDAO;
import com.mx.dla.dda.contrato.fees.dtos.FeesContratoPagoBD;
import com.mx.dla.dda.contrato.fees.dtos.FeesContratoPagoDTO;
import com.mx.dla.dda.contrato.fees.dtos.FeesFlatBD;
import com.mx.dla.dda.contrato.fees.dtos.FeesSuscriptorBD;
import com.mx.dla.dda.contrato.generales.bos.GeneralesBO;
import com.mx.dla.dda.contrato.generales.dtos.ContratoDTO;
import com.mx.dla.dda.contrato.titulo.bos.TitulosBussinesBO;
import com.mx.dla.global.bos.BaseBO;

@Service
public class FeesContratoBO extends BaseBO{
	
	@Autowired
	private FeesContratoDAO feesContratoDAO;
	
	@Autowired
	private AmortizacionDAO amortizacionDAO;

	@Autowired
	private FeesSuscriptorBO feesSuscriptorBO;

	@Autowired
	private FeesFlatBO feesFlatBO;
	
	@Autowired
	private FeesBonoBO feesBonoBO;
	
	@Autowired
	private FeesCategoriaBO feesCategoriaBO;
		
	@Autowired
	private GeneralesBO generalesBO;
	
	@Autowired
	private TitulosBussinesBO titulosBussinesBO;

	private ContratoDTO cto;
							
	public List<FeesContratoPagoDTO> getDatosFees(Long idContrato) throws Exception{		   
		   List<FeesContratoPagoDTO> datos = new ArrayList<FeesContratoPagoDTO>();
		   		   		   
		   List<FeesContratoPagoBD> periodos = feesContratoDAO.getPeriodos(idContrato);   //Se obtienen los periodos que puede llegar a tener un contrato		   		   		   		
		   
		   try{			   		   				   
				   if(periodos.isEmpty())                                                 //si no existe registro en bd
				   {			   			    			   			   
					   FeesContratoPagoDTO dato     = feesSuscriptorBO.crearSuscriptor(null,null);
					   FeesContratoPagoDTO datoFlat = feesFlatBO.crearFlat(null,null);					   
					   dato.setFlats(datoFlat.getFlats());					   
					   dato.setMaxAnios(datoFlat.getMaxAnios());
					   datos.add(dato);
				   }		   
				   
				   else
				   {   //se sacan los datos y se obtiene datos por periodo.
					   List<FeesSuscriptorBD> suscriptores = new ArrayList<FeesSuscriptorBD>();
					   List<FeesFlatBD>             flats  = new ArrayList<FeesFlatBD>();			   
					   List<Long>            idsPeriodos   = new ArrayList<Long>();
					   
					   for(FeesContratoPagoBD item: periodos)
						   idsPeriodos.add(item.getIdContratoPago());
					
					   if(periodos.get(0).getTipoPago().compareTo("ESCALA") == 0)
					   {
						   suscriptores = feesContratoDAO.getFeesSuscriptor(idsPeriodos);	
						   for(FeesContratoPagoBD periodo: periodos)
						   {					   
							   List<FeesSuscriptorBD> temporal = new ArrayList<FeesSuscriptorBD>();
							   for(FeesSuscriptorBD suscriptor : suscriptores)
							   {
								   if(periodo.getIdContratoPago().longValue() == suscriptor.getIdContratoPago().longValue())						   
									  temporal.add(suscriptor);						   
							   }
							   datos.add(feesSuscriptorBO.crearSuscriptor(periodo, temporal));
						   }
					   }
					   else if(periodos.get(0).getTipoPago().compareTo("FLAT") == 0)
					   {
						    flats =  feesContratoDAO.getFeesFlat(idsPeriodos);
						    for(FeesContratoPagoBD periodo: periodos)
							{					   
								List<FeesFlatBD> temporal = new ArrayList<FeesFlatBD>();
								for(FeesFlatBD flat : flats)
								{
								   if(periodo.getIdContratoPago().longValue() == flat.getIdContratoPago().longValue())						   
									  temporal.add(flat);						   
								}
								datos.add(feesFlatBO.crearFlat(periodo, temporal));
							}
			
					   }		
					   else if(periodos.get(0).getTipoPago().compareTo("NA") == 0)
					   {						    
						    for(FeesContratoPagoBD periodo: periodos)											  								
								datos.add(this.crearFeesNA(periodo));			
					   }
					   
				   }
		   }catch(Exception e){
			   logger.error("Error ",e);
			   throw new Exception(e);
		   }
		   
		   return datos;
	}
					
	public void guardarPagosFees(List<FeesContratoPagoDTO> periodos, Long idContrato) throws ParseException, Exception{		
		   		 
		try
		{
		   feesCategoriaBO.guardarCategorias(periodos, idContrato);
		   for(FeesContratoPagoDTO  periodo : periodos)
		   {				   
			   if(periodo.getTipoPago().compareTo("ESCALA") == 0)			   				   				   				 
				   feesSuscriptorBO.guardarSuscriptor(periodo, idContrato);			  			   				   				   			  
			   else if(periodo.getTipoPago().compareTo("FLAT") == 0)
				   feesFlatBO.guardarFlat(periodo, idContrato);
			   else if(periodo.getTipoPago().compareTo("NA") == 0)
				   this.guardarFeesNA(idContrato);
		   }
		}catch(Exception e){
			   logger.error("Error ",e);
			   throw new Exception(e);
		}
	}						
						
	public void editarPagosFees(List<FeesContratoPagoDTO> periodos, Long idContrato)throws ParseException, Exception{
		   
		try
		{
		   feesCategoriaBO.editarCategorias(periodos, idContrato);
		   logger.info("Se han editado las categorias");
		   		   
		   if(periodos.get(0).getTipoPago().compareTo("ESCALA") == 0)			//Se eliminan los datos dinamicos anteriores			   				  				  					   
			   feesSuscriptorBO.eliminarRangosCostoSuscriptor(idContrato);			   			   				   				   			  
		   else if(periodos.get(0).getTipoPago().compareTo("FLAT") == 0)
			   feesFlatBO.eliminarPagosFlat(idContrato);   
					   
		   for(FeesContratoPagoDTO  periodo : periodos)                         //Se hacen las insercciones de los nuevos datos
		   {
			   if(periodo.getTipoPago().compareTo("ESCALA") == 0)
			   {				  				   
				   if(periodo.getIdContratoPago() <=0 )
					   feesSuscriptorBO.guardarSuscriptor(periodo, idContrato);
				   else
					   feesSuscriptorBO.editarSuscriptor(periodo);
			   }			   				   				   			   
			   else if(periodo.getTipoPago().compareTo("FLAT") == 0)
			   {				   
				   if(periodo.getIdContratoPago() <=0 )
					   feesFlatBO.guardarFlat(periodo, idContrato);
				   else
					   feesFlatBO.editarFlat(periodo);
			   }				   
		   }
		   		   
		}catch(Exception e){
		   logger.error("Error {}",e);
		   throw new Exception(e);
		}
	}
													
	public void eliminarPagosFees(Long idContrato)throws ParseException, Exception{		
		String tipo = feesContratoDAO.getTipoFees(idContrato);				
		try
		{
			 if(tipo.compareTo("ESCALA") == 0)			   
				 feesSuscriptorBO.eliminarSuscriptores(idContrato);				   			   
			 else if(tipo.compareTo("FLAT") == 0)
				 feesFlatBO.eliminarFlats(idContrato);
			 else if(tipo.compareTo("NA") == 0)
				 feesContratoDAO.eliminarContratoPagoXCto(idContrato);
		}catch(Exception e){
			logger.error("Error {}",e);
			throw new Exception(e);
		}
	}									
				
	@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
	public void guardarProcesoFees(String request, String requestBono, Integer inflacion, 
			                       Long idContrato, String operacion,  String periodosEliminar, String categoriasEliminar) throws ParseException, Exception{
		ObjectMapper mapper = new ObjectMapper();
		
		List<FeesContratoPagoDTO> datos = mapper.readValue(request, new TypeReference<List<FeesContratoPagoDTO>>(){});		
		if(datos != null)
		{
			if(operacion.compareTo("nuevo") == 0){			                //Se guarda la informacion por primera vez
		    	this.guardarPagosFees(datos,idContrato);
		    	logger.info("Se guarda informacion por primera vez.");
		    }
		    				    
		    else if(operacion.compareTo("resetear") == 0)                  //Se guarda la informacion cuando se cambia el tipo de fees
		    {			    	
		    	logger.info("Se guarda informacion resetear.");
		    	this.eliminarPagosFees(idContrato);
		    	feesCategoriaBO.eliminarCategorias(idContrato);
		    	this.guardarPagosFees(datos, idContrato);			
		    }
		    
		    else if(operacion.compareTo("limpiar") == 0)                  //Se guarda la informacion cuando se eliminan todos los periodos
		    {			    	
		    	this.eliminarPagosFees(idContrato);
		    	feesCategoriaBO.eliminarCategorias(idContrato);
				logger.info("Se guarda informacion limpiar.");
		    }
		    				    
		    else if(operacion.compareTo("actualizar") == 0)                //Se actualiza la informacion del fees actual
		    {				    	 
		    	if(periodosEliminar != null)                                    //Se verifica si eliminos periodos el usuario
				{
		    		List<FeesContratoPagoDTO> periodosBorrar = mapper.readValue(periodosEliminar, new TypeReference<List<FeesContratoPagoDTO>>(){});						
					for(FeesContratoPagoDTO item : periodosBorrar)
					{
						if(item.getTipoPago().compareTo("ESCALA") == 0)
							feesSuscriptorBO.eliminarSuscriptor(item);
						else
							feesFlatBO.eliminarFlat(item);
					}										
					logger.info("Se eliminan los periodos.");
				}
		    	
		    	if(categoriasEliminar != null)                                     //Se procesa las categorias eliminadas en el portal
				{				    		
		    		List<FeesContratoPagoDTO> feesEliminar = mapper.readValue(categoriasEliminar, new TypeReference<List<FeesContratoPagoDTO>>(){});						
					for(FeesContratoPagoDTO item : feesEliminar)
					{							
						if(item.getTipoPago().compareTo("0") == 0)              //Se verifica si se elimino categoria en suscriptor													
							datos = feesSuscriptorBO.eliminarCategoriaSuscriptor(item.getCategorias().get(0).getIdCategoria(), datos);								
						   
						if(item.getTipoPago().compareTo("1") == 0)              //Se verifica si se elimino categoria en flat
							datos = feesCategoriaBO.eliminarCategoriaFlat(item.getCategorias().get(0).getIdCategoria(), datos);
						   
						if(item.getTipoPago().compareTo("2") == 0)              //Se verifica si se elimino un rango en bonos flats
							feesBonoBO.eliminarRangoBono(item);
					}
					logger.info("Se eliminan las categorias.");
				}
		    					    					    											    					    	
				if(datos.size() > 0)                                            //se actulizan el resto de los datos
				{
					if(datos.get(0).getCategorias() != null || datos.get(0).getFlats() != null)
					{
						this.editarPagosFees(datos,idContrato);
						logger.info("se editan los datos.");
					}				
						  
				}                                            						   
				else
				{
					feesCategoriaBO.eliminarCategorias(idContrato);
					logger.info("se elimian categorias??.");
				}
				
		    }				
			amortizacionDAO.updateContratoProceso(idContrato,1); //Se actualiza la bandera de modificacion para titulos en amortizacion
		}
		
		titulosBussinesBO.procesoActualizacionTitulosEnmienda(idContrato);
		feesBonoBO.guardarBono(requestBono, idContrato);
		this.actualizarInflacionCto(inflacion, idContrato);
	}

	public int verificarCategoriasTitulos (String operacion, Long id){
		int numero = 0;
		if(operacion.compareTo("1") == 0) //verificar elimnacion categoria			 
			 numero = feesCategoriaBO.getCategoriasTitulosXCategoria(id).size();
			 
		else if(operacion.compareTo("2") == 0) //verificar eliminacion periodo
			numero = feesCategoriaBO.getCategoriasTitulosXContrato(id).size();
			 
		else if(operacion.compareTo("3") == 0) //verificar fees completo			
		     numero = feesCategoriaBO.getCategoriasTitulosXContrato(id).size();
		return numero;
	}
	
	public String actualizarCostoTitulos(Map<String, Object> paramNumeroContrato){
		
		return feesCategoriaBO.actualizarCostoTitulos(paramNumeroContrato);
	}
									
	public FeesContratoPagoDTO crearFeesNA(FeesContratoPagoBD pagoBD){
		   FeesContratoPagoDTO fee = new FeesContratoPagoDTO();
		   
		   if(pagoBD == null)
		      fee.setTipoPago("NA");   				   
		   else
		      fee.setTipoPago(pagoBD.getTipoPago());			   				  			   			   			   					   	   			   						   			   			   		   		   
		   return fee;
	}
	
	public void guardarFeesNA(Long idContrato) throws ParseException, Exception{						
		   FeesContratoPagoBD contratoPago = new FeesContratoPagoBD();
		   contratoPago.setIdContrato(idContrato);
		   contratoPago.setTipoPago("NA");					
		   feesContratoDAO.guardarContratoPago(contratoPago);
	}
	
	public List<String> getVigenciaContrato(Long idContrato) throws ParseException{
		   List<String> fechas = new ArrayList<String>();		   
		   String inicio = feesContratoDAO.fechaInicio(idContrato);
		   String fin    = feesContratoDAO.fechaFin(idContrato);
		   fechas.add(inicio);
		   fechas.add(fin);		   
		   return fechas;
	}		

	public void actualizarInflacionCto(Integer inflacion, Long idContrato)
	{
		String inflaCto = inflacion != null ? String.valueOf(inflacion) : "";
		feesContratoDAO.actualizarInflacionCto(inflaCto, idContrato);
	}
	
	public Long obtenerEdoContrato(Long idContrato){
		this.cto = generalesBO.obtenContrato(idContrato);
		return cto.getIdEstatus();
	}
	
	public Integer getInflacionCto(){
		Integer inflacion = null;
		if(cto.getInflacion() != null && cto.getInflacion().compareTo("") != 0 && Integer.parseInt(cto.getInflacion()) > 0 )
		   inflacion = Integer.parseInt(cto.getInflacion());
		return inflacion;
	}

	public String getCostoTotal(Long idContrato) {
		return feesContratoDAO.getCostoTotal(idContrato);
	}
	
 }