package com.mx.dla.dda.contrato.license.titulo.bos;

import java.lang.reflect.InvocationTargetException;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import org.apache.commons.beanutils.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.mx.dla.dda.contrato.common.bos.CommonRestBO;
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.dtos.FechasDTO;
import com.mx.dla.dda.contrato.generales.dtos.InfoDetalleContratoDTO;
import com.mx.dla.dda.contrato.generales.enums.Movimiento;
import com.mx.dla.dda.contrato.license.terminos.daos.TerminosFeeDAO;
import com.mx.dla.dda.contrato.license.titulo.daos.TituloFeeDAO;
import com.mx.dla.dda.contrato.license.titulo.daos.TituloFeeDmDAO;
import com.mx.dla.dda.contrato.terminos.dtos.TerminoBD;
import com.mx.dla.dda.contrato.titulo.dtos.AmortizacionSAP;
import com.mx.dla.dda.contrato.titulo.dtos.SapNum;
import com.mx.dla.dda.contrato.titulo.dtos.Titulo;
import com.mx.dla.dda.contrato.titulos.dtos.CatTitulo;
import com.mx.dla.dda.contrato.titulos.dtos.ResponseValorTituloDTO;
import com.mx.dla.global.bos.BaseBO;

@Component
public class TituloFeeBussinesBO extends BaseBO{

	@Autowired
	protected CommonRestBO commonRestBO;
	
	@Autowired
	protected GeneralesDAO generalesDAO;
	
	@Autowired
	private TituloFeeDmDAO tituloDmDAO;
			
	@Autowired
	protected TituloFeeDAO tituloDAO;
	
	@Autowired
	private TerminosFeeDAO terminosDAO;
	
	/**
	 * @see Se obtiene el costo de un titulo
	 */
	public String obtieneCostoTitulo(Long idContrato)
	{
		String valorS = null;
		try
		{
			TerminoBD term = terminosDAO.getTermino(idContrato);
			
			int numero   = term.getTotalTitulos() == null ? 0 : Integer.parseInt(term.getTotalTitulos());						
			double costo = term.getCosto() == null ? 0 : Double.parseDouble(term.getCosto());
			
			DecimalFormat df = new DecimalFormat("#.##########");		
			df.setRoundingMode(RoundingMode.CEILING);
			
			Double valor  = costo / numero;		
			valorS = df.format(valor);
						
		}
		catch(Exception e)
		{
			logger.error("Ocurrio un error al tratar de generar los costos",e);
		}
		return valorS;
	}
	
	public void actualizaCostoTituloExcel(Long idContrato)
	{		
		try
		{
			TerminoBD term = terminosDAO.getTermino(idContrato);
			
			int numero   = term.getTotalTitulos() == null ? 0 : Integer.parseInt(term.getTotalTitulos());						
			double costo = term.getCosto() == null ? 0 : Double.parseDouble(term.getCosto());
			
			DecimalFormat df = new DecimalFormat("#.##########");		
			df.setRoundingMode(RoundingMode.CEILING);
			
			Double valor  = costo / numero;					
			tituloDAO.actualizarCostoTitulosExcel(df.format(valor), idContrato);						
		}
		catch(Exception e)
		{
			logger.error("Ocurrio un error al tratar de generar los costos",e);
		}		
	}
	
	/**
	 * @see Se notifica a Sap actualizacion de los costos de los titulos
	 */
	public void actualizaCostoTodosLosTitulos(ContratoDTO contrato)
	{
		try
		{
			ResponseValorTituloDTO response = commonRestBO.llamadaCostoTitulo(contrato.getFechaInicio(), contrato.getIdContrato(), "ESPEJO");
			if(!response.getResultado())			
			    logger.error("No fue posible actualizar el costo razon:[{}]",response.getMensaje());		
		}
		catch(Exception e)
		{
			logger.error("Ocurrio un error al tratar de generar los costos",e);
		}
	}
	
	/**
	 * @see Se agrega un titulo al catalogo
	 */
	public CatTitulo actualizaCatalogoTitulos(String descTitulo, ContratoDTO contrato)
	 {
		 CatTitulo ct = tituloDAO.buscarCatalogoTituloPorDesc(contrato.getIdEstudio(), descTitulo); 
		 if(ct == null)
		 {
			 ct = new CatTitulo();
			 ct.setDescTitulo(descTitulo);
			 ct.setIdEstudio(contrato.getIdEstudio());
			 tituloDAO.insertarCatTitulo(ct);
		 }
		 return ct;
	}
	
	/*public void procesoActualizacionTitulosEnmienda(Long idCto)
	{
		InfoDetalleContratoDTO detalle = generalesDAO.obtenDetalleContrato(idCto);
		if(detalle.getTipoMovimiento().intValue() == Movimiento.Enmienda.getValor().intValue())
		{			
			List<Titulo>  titulos = tituloDmDAO.buscarTitulosEnmiendaSincro(idCto);
			logger.debug("Se inicia el proceso de sincronizacion con enmiendas con titulos:{}",titulos.size());
			for(Titulo t: titulos)
				 actualizarBanderasContratosAnteriores(t,"T");
		}		
	}*/	
	
	/**
	 * @see Se actualizan banderas en bd para cambio en un titulo
	 */
	public void actualizarBanderasContratosAnteriores(Titulo titulo, String prefix)
	{				 
			InfoDetalleContratoDTO detalle = generalesDAO.obtenDetalleContrato(titulo.getIdContrato());
			if(detalle.getTipoMovimiento().intValue() == Movimiento.Enmienda.getValor().intValue())
			{
			    logger.info("Actualizacion banderas cambio de titulo-enmienda");
			    logger.info(titulo.toString());				
			                        tituloDmDAO.borrarRegistroSAPNUM(String.valueOf(titulo.getIdContrato()));
			    SapNum  anterior  = tituloDmDAO.getAumentosDisminXTitulo(titulo.getIdTituloCntorig());							
				
			    Double aumentos   = anterior == null || anterior.getAumento()     == null ? 0.0 : Double.parseDouble(anterior.getAumento());
			    Double disminucion= anterior == null || anterior.getDisminucion() == null ? 0.0 : Double.parseDouble(anterior.getDisminucion());  
			    Double diferencia = Double.parseDouble(titulo.getCosto()) - ( aumentos - disminucion); 
													
			    logger.info("Diferencia {}", diferencia);
				if(diferencia != 0)
				{
					if(titulo.getFechaNotifsap() != null)
					{															
						SapNum sapNum = new SapNum(titulo.getIdContrato(), titulo.getIdTituloCnt(), titulo.getIdTituloCntorig());
						if(diferencia > 0)
						{
							titulo.setAjustoValor(1L);																					
							sapNum.setAumento(String.valueOf(diferencia));
						}							
						else
						{
							titulo.setAjustoValor(-1L);												
							sapNum.setDisminucion(String.valueOf(diferencia*-1));						
						}
											
						tituloDmDAO.actualizarTituloVar(titulo, prefix);																									 															
						tituloDmDAO.insertarSapSubnum(sapNum);
						logger.info("Diferencia diferente a 0 se actuliza titulo");
						
						if(sapNum.getDisminucion() != null)
						   this.asignarDiferenciaSubNum(Double.parseDouble(sapNum.getDisminucion()), titulo.getIdTituloCntorig());										
					}	
				}
				else
				{
					logger.info("Diferencia 0 se actuliza titulo");
					titulo.setAjustoValor(0L);
					tituloDmDAO.actualizarTituloVar(titulo, prefix);
				}
			}
	}
	
	public void asignarDiferenciaSubNum(Double disminucion, Long idTituloCntOrig){		 
	     Calendar cal = Calendar.getInstance();
	     cal.setTime(new Date());
	     int year = cal.get(Calendar.YEAR);
	     
		 List<SapNum> disminuciones     = tituloDmDAO.buscaSubNumDisminucion(idTituloCntOrig);
		 List<AmortizacionSAP> amortSub = tituloDmDAO.buscaMaxSubNumByFechaAmort(idTituloCntOrig, year);		 
		 
		 logger.debug("Disminuciones {}", disminuciones.toString());
		 logger.debug("SubNum Amorti {}", amortSub.toString());
		 
		 Double totalDisponible = 0.0;
		 Boolean asignado       = false;
		 
		 for(AmortizacionSAP m : amortSub)
		 {			  			 
			 Double disponible     = Double.parseDouble(m.getVnc()) - Double.parseDouble(m.getMontoAcumulado());
			 totalDisponible       = totalDisponible + disponible;			 			
			 
			 if(disponible >= disminucion)
			 {	
				 SapNum sapNum = getSapNum(disminuciones.get(0).getIdContrato(), disminuciones.get(0).getIdTituloCNT(), disminuciones.get(0).getIdTituloCtoOrig(), disminucion, disminuciones.get(0).getIdRegistroSAP(), m.getSubNumero());
				 tituloDmDAO.actualizarSubNum(sapNum);				 
				 logger.debug("'disponible >= disminucion' se actualiza {} con valor {}", disminuciones.get(0).getIdRegistroSAP(), disminucion);
				 asignado = true;				 
			 }			
			 if(asignado)
				break;
		 }
		 
		 
		 logger.info("Se ha asignado la disminucion? {}", asignado);
		 if(!asignado)
		 {			 
			 int cont = 0;
			 for(AmortizacionSAP a : amortSub)
			 {
				 if(disminucion <= 0) break;				 
				 Double disponible = Double.parseDouble(a.getVnc()) - Double.parseDouble(a.getMontoAcumulado());				 
					
				 if(cont >= disminuciones.size())
				 {						 
					 SapNum sapNum = getSapNum(disminuciones.get(0).getIdContrato(), disminuciones.get(0).getIdTituloCNT(), disminuciones.get(0).getIdTituloCtoOrig(), disminucion, null, a.getSubNumero()); 					 
					 if(disminucion >= disponible)
					 {
						 sapNum.setDisminucion(String.valueOf(disponible));
						 disminucion = disminucion - disponible;
					 }					 																	 					 
					 else					
					 {
						 sapNum.setDisminucion(String.valueOf(disminucion));
						 disminucion = 0.0;
					 } 											
					 logger.debug("Nuevo registro con valor de amortizacion {}", disminucion);					 
					 tituloDmDAO.insertarSapSubnum(sapNum);					 					 
				 }
				 else 
				 {
					 SapNum sapNum = getSapNum(disminuciones.get(cont).getIdContrato(), disminuciones.get(cont).getIdTituloCNT(), disminuciones.get(cont).getIdTituloCtoOrig(), null, disminuciones.get(cont).getIdRegistroSAP(), a.getSubNumero());					 
					 if(disminucion >= disponible)
					 {					
						 disminucion = disminucion - disponible;					
						 sapNum.setDisminucion(String.valueOf(disponible));
						 logger.debug("'disminucion >= disponible' se actualiza {} con valor {}", disminuciones.get(cont).getIdRegistroSAP(), disponible);						 
						 cont++;					 
					 }				   
					 else
					 {					
						 sapNum.setDisminucion(String.valueOf(disminucion));						 
						 logger.debug("No asignado 'disponible >= disminucion', se actualiza {} con valor {}", disminuciones.get(cont).getIdRegistroSAP(), disminucion);
						 disminucion = 0.0;						 
					 } 
					 tituloDmDAO.actualizarSubNum(sapNum);					 
				 }				 			
				 logger.debug("disminucion {}", disminucion);				 				 
			 }			 			 
				 			 
			 if(disminucion > 0 )
			 {				 
				 logger.debug("Nuevo con valor {}", disminucion);
				 SapNum sapNum = getSapNum(disminuciones.get(0).getIdContrato(), disminuciones.get(0).getIdTituloCNT(), disminuciones.get(0).getIdTituloCtoOrig(), disminucion, null, null);
				 tituloDmDAO.insertarSapSubnum(sapNum); 	 
			 }			 							 
		 }
	}
		
	private SapNum getSapNum(Long idContrato, Long idTituloCNT,Long idTituloCNTORI, Double disminucion, Long idRegistroSap, String subnumero){
		    SapNum sapNum = new SapNum(idContrato, idTituloCNT, idTituloCNTORI);
		    
		    if(disminucion != null)
		       sapNum.setDisminucion(String.valueOf(disminucion));
		    if(idRegistroSap != null)
			   sapNum.setIdRegistroSAP(idRegistroSap);
		    if(subnumero != null)
			   sapNum.setSubnumero(subnumero);
		    return sapNum;
	}
	
	public ContratoDTO calculaFechasInicioFinValidacion(ContratoDTO contrato)
	{
		ContratoDTO cv=null;
		try 
		{
			cv = (ContratoDTO) BeanUtils.cloneBean(contrato);
			FechasDTO fechas = generalesDAO.obtenerFechasMaximaMinimaDeContratosPorContratoOriginal(contrato.getIdContratoOriginal());
			cv.setFechaInicio(fechas.getInicio());
			cv.setFechaFin(fechas.getFin());
		} catch (IllegalAccessException | InstantiationException | InvocationTargetException | NoSuchMethodException e) 
		{
			logger.error("Error ",e);
		}
		return cv;
	}
}