package com.mx.dla.dda.factura.general.bos;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.List;

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

import com.mx.dla.dda.factura.general.daos.FacturacionDAO;
import com.mx.dla.dda.factura.general.dtos.ContratoFacturaDTO;
import com.mx.dla.dda.factura.general.dtos.FacturaGeneralDTO;
import com.mx.dla.dda.factura.general.dtos.MesFacturaDTO;
import com.mx.dla.dda.factura.general.dtos.PagoMesContratoBD;
import com.mx.dla.dda.general.dtos.ResponseDTO;
import com.mx.dla.dda.general.utilerias.ListaUtilerias;
import com.mx.dla.global.bos.BaseBO;

@Component
public class FacturacionBO extends BaseBO {

	@Autowired
	private FacturacionDAO facturacionDAO;

	@Autowired
	private FacturacionWServiceBO wsbo;
	
	public FacturaGeneralDTO cargaFacturaInfoGeneral(Long idFactura) {
		FacturaGeneralDTO facturaGeneral = new FacturaGeneralDTO();
		
		if (idFactura != null) 
		{
			facturaGeneral.setIdFactura(idFactura);
			facturaGeneral = facturacionDAO.consultaFacturaGeneral(facturaGeneral);
		}
		return facturaGeneral;
	}

	public List<ContratoFacturaDTO> cargaFacturaInfoDetalle(Long idEstudio, Long idFactura, Boolean aprovada, String indicadorIva) {
		List<ContratoFacturaDTO> contratosDetalle = new ArrayList<ContratoFacturaDTO>();		
		List<ContratoFacturaDTO> contratos        = facturacionDAO.obtenerContratosEstudio(idEstudio, indicadorIva);				
		
		if(contratos != null && contratos.size() > 0)
		{
			for(ContratoFacturaDTO contrato : contratos)
			{			
				ContratoFacturaDTO contratoFac = 
						           idFactura == null ? this.getContratoMesCostoFacturaNula(contrato, 0L) :this.getContratoMesCosto(contrato, idFactura, aprovada);
				if(contratoFac != null)
				   contratosDetalle.add(contratoFac);
			}
		}									
		return contratosDetalle;
	}

	public ContratoFacturaDTO getContratoMesCostoFacturaNula(ContratoFacturaDTO contrato, Long idFactura){
		double totalCto = 0.0, pgdoCto = 0.0, pendienteCto = 0.0, apagarCto = 0.0;			
		List<MesFacturaDTO> costoCto   = new ArrayList<MesFacturaDTO>();		
		
		List<PagoMesContratoBD> costosMes     = facturacionDAO.obtenerCostoMesContrato(contrato.getIdContratoOri());   //Se obtiene los costos x mes del contrato
		List<PagoMesContratoBD> costosPagado  = facturacionDAO.obtenerPagoMesContrato (contrato.getIdContratoOri(), idFactura);    //Se obtiene los costos pagados x mes del contrato				
		
		for (PagoMesContratoBD costoMes : costosMes) 
		{
			MesFacturaDTO detalle = null;
			
			for (PagoMesContratoBD costoPgd : costosPagado)			
				 if( compareDates(costoMes.getFecha(), costoPgd.getFecha()) )				 					 					 						  
					 detalle = this.getMesPago(costoMes, costoPgd, null);				 	 								 							  				     								  											  				  								  				

			if(detalle == null)
			{
				detalle = this.getMesPago(costoMes, null, null);
				detalle.setNuevo(true);
			}			   				  
			  						
			boolean sumar = false;
			if(detalle.getTotal().doubleValue() - detalle.getPagado().doubleValue() > 0 )
			{
				costoCto.add(detalle);
				sumar = true;
			}			
			
			if(sumar)
			{
				totalCto     += detalle.getTotal().doubleValue();
				pgdoCto      += detalle.getPagado().doubleValue();
				pendienteCto += detalle.getPendiente().doubleValue(); 
				apagarCto    += detalle.getPagar().doubleValue();	
			}			
		}
						
		contrato.setPagado(pgdoCto);
		contrato.setTotal(totalCto);
		contrato.setPagar(apagarCto);
		contrato.setPendiente(pendienteCto);
		contrato.setMeses(costoCto);		
		
		if( contrato.getTotal().doubleValue() - contrato.getPagado().doubleValue() == 0 )			
		    contrato = null;		
		return contrato;
	}

	public ContratoFacturaDTO getContratoMesCosto(ContratoFacturaDTO contrato, Long idFactura, Boolean aprovada){
		double totalCto = 0.0, pgdoCto = 0.0, pendienteCto = 0.0, apagarCto = 0.0;			
		List<MesFacturaDTO> costoCto   = new ArrayList<MesFacturaDTO>();		
		
		List<PagoMesContratoBD> costosMes     = facturacionDAO.obtenerCostoMesContrato(contrato.getIdContratoOri());                //Se obtiene los costos x mes del contrato 
		List<PagoMesContratoBD> costosPagado  = facturacionDAO.obtenerPagoMesContrato (contrato.getIdContratoOri(),  idFactura);                //Se obtiene los costos pagados x mes del contrato en cualquier factura		
		List<PagoMesContratoBD> costosFactura = facturacionDAO.obtenerPagoMesFacturaCto(contrato.getIdContratoOri(), idFactura);    //Se obtiene los costos pagados x mes en la factura actual
		
		for (PagoMesContratoBD costoMes : costosMes) 
		{
			MesFacturaDTO detalle = null;

			for (PagoMesContratoBD costoFactura : ListaUtilerias.safeList(costosFactura))
			{
				 if( compareDates(costoMes.getFecha(), costoFactura.getFecha()) )
				 {
					 detalle = this.getMesPago(costoMes, getMesXFecha(costoMes.getFecha(), costosPagado), costoFactura);
					 break;
				 }				 					 					 						  					 				 	
			}
									 								 							  				     								  											  				  								  						
			if(detalle == null)
			{
				for (PagoMesContratoBD costoPgd : ListaUtilerias.safeList(costosPagado))
				{
					 if( compareDates(costoMes.getFecha(), costoPgd.getFecha()) )
					 {
						 detalle = this.getMesPago(costoMes, costoPgd, getMesXFecha(costoMes.getFecha(), costosFactura));
						 break;
					 }				 					 					 						  					 				 	
				}
			}
			
			if(detalle == null)
			{
				detalle = this.getMesPago(costoMes, null, null);
				detalle.setNuevo(true);			
			}
			
			totalCto     += detalle.getTotal().doubleValue();
			pgdoCto      += detalle.getPagado().doubleValue();
			pendienteCto += detalle.getPendiente().doubleValue(); 
			apagarCto    += detalle.getPagar().doubleValue();
			costoCto.add(detalle);									
		}
						
		contrato.setPagado(pgdoCto);
		contrato.setTotal(totalCto);
		contrato.setPagar(apagarCto);
		contrato.setPendiente(pendienteCto);
		contrato.setMeses(costoCto);			
				
		if( contrato.getPagar() == 0 && contrato.getTotal() == 0){
			logger.debug(contrato.toString());
			contrato = null;
		}			
			
		return contrato;
	}

	public PagoMesContratoBD getMesXFecha(Date fecha, List<PagoMesContratoBD> costosFactura){
		   PagoMesContratoBD mes = null;		   
		   for (PagoMesContratoBD costoPgd : costosFactura)		   
			   if(compareDates(costoPgd.getFecha(), fecha) )
				   mes = costoPgd;
		   return mes;				 		  
	} 
	
	public MesFacturaDTO getMesPago(PagoMesContratoBD costo, PagoMesContratoBD pagado,  PagoMesContratoBD pagoFacturaMes){
		 double totalMes = 0.0, pgdoMes = 0.0, pendienteMes = 0.0, apagarMes = 0.0;
		 
		 totalMes  = costo.getMesTotal().doubleValue();		 		 
		 pgdoMes   = pagado         != null && pagado.getMesTotal()         != null ? pagado.getMesTotal().doubleValue() : 0.0 ; //existen otras facturas donde se ha hecho un pago para este mes
		 apagarMes = pagoFacturaMes != null && pagoFacturaMes.getMesTotal() != null ? pagoFacturaMes.getMesTotal() : 0.0 ;  //existe un pago del mes en la factura actual
		 		 																							 							
		 pendienteMes = totalMes - (pgdoMes + apagarMes);
								 		 		 
		 MesFacturaDTO detalle = new MesFacturaDTO(null, pgdoMes, apagarMes, pendienteMes, totalMes);
		 
		 boolean nuevo = (pagoFacturaMes != null && pagoFacturaMes.getMesTotal() != null) ? false : true; 		 
		 
		 detalle.setNuevo(nuevo);		 		 
		 detalle.setMes(this.getFecha(costo.getFecha()));
		 detalle.setIdFactura(costo.getIdFactura());		 
		 return detalle;
	}	
				
	public void guardarFactura(FacturaGeneralDTO factura){
		if (factura.getIdFactura() == null) 
			facturacionDAO.creaFacturaGeneral(factura);
		else 
			facturacionDAO.actualizaFacturaGeneral(factura);
		this.guardarFacturaDetalle(factura.getContratos(), factura.getIdFactura());
		
		logger.debug(factura.toString());				
	}
		
	public void guardarFacturaDetalle(List<ContratoFacturaDTO> contratos, Long idFactura){
		
		for(ContratoFacturaDTO contrato : contratos)
		{
			for(MesFacturaDTO mes : ListaUtilerias.safeList(contrato.getMeses()))
			{
				mes.setMes(getFecha(mes.getMes()));
				if(mes.getNuevo() != null && mes.getNuevo() && mes.getPagar() > 0)
				{
					logger.debug(idFactura +":"+ contrato.getIdContratoOri() +":"+ mes);
					facturacionDAO.guardarFacturaDetalle(idFactura, contrato.getIdContratoOri(), mes);
				}
				else if (mes.getNuevo() != null && !mes.getNuevo())
				{
					logger.debug(idFactura +":"+ contrato.getIdContratoOri() +":"+ mes);
					facturacionDAO.actualizarFacturaDetalle(idFactura, contrato.getIdContratoOri(), mes);
				}	
			}
		}
	}
	
	public void notificarServicioRest(FacturaGeneralDTO factura) {
		logger.debug(factura.toString());

		ResponseDTO respuesta = null;
		if (factura != null)
			respuesta = wsbo.notificaFactura(factura);
		
		//facturacionDAO.actualizaFacturaGeneralNotificada(factura);
		
		logger.debug("Respuesta servicio: {}", respuesta);

	}
	
	public FacturaGeneralDTO consultaFactura(Long idFactura){
		FacturaGeneralDTO factura = new FacturaGeneralDTO();
		factura.setIdFactura(idFactura);
		return facturacionDAO.consultaFacturaGeneral(factura);
	}

	
	public String getFecha(Date fecha){
		SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy");													
		return sdf.format(fecha);
	}
	
	public String getFecha(String fecha){		
		String [] meses = fecha.split("/");								
		return meses[1]+"-"+meses[0]+"-"+meses[2];
	}
	
	public boolean compareDates(Date uno, Date dos)
	{
		Calendar cal1 = Calendar.getInstance();
		cal1.setTime(uno);		
		
		Calendar cal2 = Calendar.getInstance();
		cal2.setTime(dos);		
    	
    	if(cal1.equals(cal2))
    		return true;
    	else 
    		return false;
	}
}