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

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

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.mx.dla.dda.contrato.common.daos.DocumentoDAO;
import com.mx.dla.dda.contrato.common.dtos.DocumentoDTO;
import com.mx.dla.dda.contrato.fees.daos.FeesContratoDAO;
import com.mx.dla.dda.contrato.generales.enums.Estatus;
import com.mx.dla.dda.contrato.generales.enums.Movimiento;
import com.mx.dla.dda.contrato.listado.daos.ListadoDAO;
import com.mx.dla.dda.contrato.listado.dtos.ContratoListaDTO;
import com.mx.dla.dda.contrato.listado.dtos.ListadoBD;
import com.mx.dla.dda.contrato.listado.dtos.RequestListadoDTO;
import com.mx.dla.global.bos.BaseBO;

@Component
public class ListadoContratoBO extends BaseBO{
	
	@Autowired
	private ListadoDAO listadoDAO;
	
	@Autowired
	private DocumentoDAO documentoDAO;
	
	@Autowired
	private FeesContratoDAO feesContratoDAO;
			
	public List<ContratoListaDTO> getListadoContratos(RequestListadoDTO request) throws ParseException{
		   List<ContratoListaDTO> listado = new ArrayList<ContratoListaDTO>();
		   List<ListadoBD>      listadoBD = listadoDAO.getContratosListado(request);
		   				   
		   for(ListadoBD bd : listadoBD)
		   {
			   int tipo = bd.getIndentar();
			  		
			   if(bd.getEstatus() != null && bd.getEstatus().equals(Estatus.Rechazado.getDescripcion()) && !request.getRechazado())
				  tipo = -1;
			   
			   switch(tipo)
			   {
				       case 0:
						   listado.add(listadoBD2ListadoDTO(bd,0));
						   break;				   	   
					   case 1:
						   ContratoListaDTO cto = listadoBD2ListadoDTO(bd,1);
						   if(cto.getEstatus().compareTo(Estatus.Vigente.getDescripcion()) == 0)
						   {
							   cto.setAdendum (true);
							   cto.setEnmienda(true);   
						   }					   
						   listado.add(cto);
						   break;				   
					   case 2:						   
						   asignarHijos2Nivel(listado, bd);
						   break;					   					   
					   case 3:
						   asignarHijos3Nivel(listado, bd);
					   break;
					   case -1:
						   logger.info("Cto Rechazado no ver.");
					   break;				  
			   }			   
		   }		   		   
		 
		   for(ContratoListaDTO c : safeList(listado))
		   {
			   boolean res = this.verificarHijos(c);
			   if(!res)
			      quitarLinks(c);
		   }		       			
		   return listado;
	}
	
	
	public boolean verificarHijos(ContratoListaDTO cto){
		boolean resultado = true;
		
		if( cto == null || cto.getEstatus() == null)
			return true;
		else if(cto.getHijos() != null && !cto.getHijos().isEmpty())
		{
			for(int i=0; i<cto.getHijos().size();i++)
			{
				boolean res = verificarHijos(cto.getHijos().get(i));
				if(!res)
				  return false;
			}						
		}			
		
		if(  cto != null && cto.getEstatus() != null && cto.getEstatus().equals(Estatus.Vigente.getDescripcion())  ||  cto.getEstatus().equals(Estatus.Autorizado.getDescripcion()) )
			resultado = true;
		else
			resultado = false;		
		return resultado;		 							    
	}
	
	public void quitarLinks(ContratoListaDTO cto){		
		
		if( cto != null)
		{
			cto.setAdendum(false);
		    cto.setEnmienda(false);
		}			
		
		if(cto != null && cto.getHijos() != null && !cto.getHijos().isEmpty())
		{
			for(int i=0; i<cto.getHijos().size();i++)
			{
				cto.getHijos().get(i).setAdendum(false);
				cto.getHijos().get(i).setEnmienda(false);
				quitarLinks(cto.getHijos().get(i));
			}						
		}									 							   
	}
	
	public void verificarHijosVigente(ContratoListaDTO cto){		
		
		if(cto.getEstatus() != null && cto.getHijos() != null && !cto.getHijos().isEmpty() &&
		   (cto.getEstatus().equals(Estatus.Vigente.getDescripcion())  ||  cto.getEstatus().equals(Estatus.Autorizado.getDescripcion())) )
		{
			boolean add = false;			
			for(ContratoListaDTO c : safeList(cto.getHijos()))
			{	
			   if(c.getEstatus().equals(Estatus.Rechazado.getDescripcion()))
				    add = true;
			   if( (c.getEstatus().equals(Estatus.Vigente.getDescripcion()) ||  c.getEstatus().equals(Estatus.Autorizado.getDescripcion())) )
					add = true;
				this.verificarHijosVigente(c);
			}
			
			if(!add)
			{
				cto.setAdendum(false);
			    cto.setEnmienda(false);	
			}
		}
		else if( cto.getEstatus() != null && 
				( cto.getHijos() == null || (cto.getHijos() != null && cto.getHijos().isEmpty() ))  &&
			    ( cto.getEstatus().equals(Estatus.Vigente.getDescripcion())  ||  cto.getEstatus().equals(Estatus.Autorizado.getDescripcion())) )
		{
			cto.setAdendum(true);
		    cto.setEnmienda(true);
		}
		else{
			cto.setAdendum(false);
		    cto.setEnmienda(false);
		}
	}
		
	public List<ContratoListaDTO> asignarHijos2Nivel(List<ContratoListaDTO> listado, ListadoBD bd){		
			for(ContratoListaDTO contrato : safeList(listado))
			{		
				if(contrato.getIdContrato() != null && (contrato.getIdContrato().longValue() == bd.getIdPadre().longValue()))
				{
					ContratoListaDTO cto = listadoBD2ListadoDTO(bd,2);					
																			
					if(cto.getDescripcion().compareTo(Movimiento.Adendum.getDescripcion()) == 0 && 
					    (cto.getEstatus().compareTo(Estatus.Vigente.getDescripcion()) == 0 || cto.getEstatus().compareTo(Estatus.Autorizado.getDescripcion()) == 0) )
					{												
						cto.setEnmienda(true);
						cto.setAdendum (false);
					}																							
						
					contrato.getHijos().add(cto);					
					contrato.setAdendum (true);
					contrato.setEnmienda(true);
				}
			}
			return listado;
	}
	
	public List<ContratoListaDTO> asignarHijos3Nivel(List<ContratoListaDTO> listado, ListadoBD bd){			
		    for(ContratoListaDTO contrato : listado)
		    {
		    	for(ContratoListaDTO ctoHijo : safeList(contrato.getHijos()) )
			    {
		    		if(ctoHijo.getIdContrato().longValue() == bd.getIdContratoOriginal().longValue())
		    		{
		    			ContratoListaDTO cto = listadoBD2ListadoDTO(bd,3);		    					    			
		    			ctoHijo.getHijos().add(cto);
		    					    			
		    			if(ctoHijo.getDescripcion().compareTo(Movimiento.Adendum.getDescripcion()) == 0)
				    	{
		    				ctoHijo.setEnmienda(true);
		    				ctoHijo.setAdendum (false);
				    	}		    			
		    		}		    		  
			    }	
		    }						
			return listado;		
	}

	public ContratoListaDTO listadoBD2ListadoDTO(ListadoBD bd, int tipo){		
		   ContratoListaDTO contrato = new ContratoListaDTO();
		   
		   contrato.setAbierto         (false);
		   if (Objects.nonNull(bd.getNumeroContrato()) && bd.getNumeroContrato().endsWith("V")) {
			   contrato.setDescripcion     ("Virtual");
		   }
		   else
		   {
			   contrato.setDescripcion     (bd.getConcepto());
		   }
		   contrato.setNumeroContrato  (bd.getNumeroContrato());
		   contrato.setFechaInicio     (bd.getFechaInicio());
		   contrato.setFechaFin        (bd.getFechaFin());
		   contrato.setEstatus         (bd.getEstatus());		   		   
		   contrato.setIdContrato      (bd.getIdContrato());
		   contrato.setHijos           (new ArrayList<ContratoListaDTO>());
		   
		   if(tipo == 0)
		   {
			   contrato.setEncabezadoTitulo(true);					   		   			
			   boolean colap  = bd.getColapsable().intValue() == 1 ? true : false;
			   contrato.setColapsable(colap); 
		   }		      
		   
		   List<DocumentoDTO> documentos = bd.getNumDocumentos().intValue() > 0 && tipo != 0 ? new ArrayList<DocumentoDTO>():null;
		   contrato.setDocumentos      (documentos);
		   return contrato;
	}

	public DocumentoDTO getDocumento(Long idContratoDocto){
		return documentoDAO.buscarDocumento(idContratoDocto);
	}	
	
	public List<ContratoListaDTO> getDocumentos(Long id){
		   List<ContratoListaDTO> obj = new ArrayList<ContratoListaDTO>();
		   ContratoListaDTO cto = new ContratoListaDTO();
		   cto.setDocumentos(documentoDAO.buscarDocumentos(id));
		   obj.add(cto);
		   return obj;
	}
	
	//funcionalidad comun de secciones para crear addendum
	public Long crearAdendum(Map<String,Object> params){		
		   listadoDAO.crearAdendum(params);
		   Integer id = (Integer)params.get("idContratoNuevo"); 
		   String idS = String.valueOf(id);
		   Long idL = Long.parseLong(idS);
		   return idL;
	}

	//funcionalidad comun de secciones para crear enmienda
	public Long crearEmnienda(Map<String,Object> params){		   
		   listadoDAO.crearEmnienda(params);
		   Integer id = (Integer)params.get("idNuevo"); 
		   String idS = String.valueOf(id);
		   Long idL = Long.parseLong(idS);
		   return idL;
	}
			
	@SuppressWarnings("unchecked")
	public static <T> List<T> safeList(final List<T> other) {
		return other == null ? Collections.EMPTY_LIST : other;
	}
}
