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

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.mx.dla.dda.general.utilerias.ListaUtilerias;
import com.mx.dla.dda.general.utilerias.StringUtilerias;
import com.mx.dla.dda.ncredito.general.daos.NotaCreditoDAO;
import com.mx.dla.dda.ncredito.general.dtos.ContratoNotaCreditoDetalleDTO;
import com.mx.dla.dda.ncredito.general.dtos.ContratoNotaCreditoGeneralDTO;
import com.mx.dla.dda.ncredito.general.dtos.ContratoTitulo;
import com.mx.dla.dda.ncredito.general.dtos.NotaCredito;
import com.mx.dla.dda.ncredito.general.dtos.NotaCreditoDetalle;
import com.mx.dla.dda.ncredito.general.dtos.TituloNotaCreditoDTO;
import com.mx.dla.global.bos.BaseBO;

@Component
public class NotaCreditoBO extends BaseBO {

	@Autowired
	private NotaCreditoDAO        notaCreditoDAO;

	@Autowired
	private NotaCreditoWServiceBO wsbo;

	public ContratoNotaCreditoGeneralDTO cargaNotaCreditoGeneral(Long idEstudio, Long idNota) {

		NotaCredito notaCredito = null;
		LinkedList<NotaCredito> lnotasCredito = null;
		List<Long> estudios = null;
		List<NotaCredito> notasCredito = new ArrayList<NotaCredito>();
		ContratoNotaCreditoGeneralDTO notaGeneral = new ContratoNotaCreditoGeneralDTO();

		if (idEstudio != null)
			estudios = new ArrayList<>(Arrays.asList(idEstudio));

		if (idNota != null && estudios == null || estudios != null && idNota == null)
			notasCredito = ListaUtilerias.safeList(notaCreditoDAO.consultaNotaCreditoGeneral(idNota, estudios, null));

		lnotasCredito = new LinkedList<NotaCredito>(notasCredito);

		if (!lnotasCredito.isEmpty()) {

			notaCredito = lnotasCredito.getFirst();
			notaGeneral.setApproved(notaCredito.getApproved());
			notaGeneral.setComentario(notaCredito.getComentario());
			notaGeneral.setFechaFactura(notaCredito.getFecha());
			notaGeneral.setIdEstudio(notaCredito.getIdEstudio());
			notaGeneral.setIdNota(notaCredito.getIdNota());
			notaGeneral.setIdSapRegistro(notaCredito.getIdSapRegistro());
			notaGeneral.setNumeroFactura(notaCredito.getNoFactura());
		}

		return notaGeneral;
	}

	@Deprecated
	@SuppressWarnings("unchecked")
	public List<ContratoNotaCreditoDetalleDTO> cargaNotaCreditoDetalles(Long idEstudio, Long idNota, Boolean aprovada) {

		List<ContratoTitulo> dbtitulos = null;
		List<ContratoTitulo> udbtitulos = null;

		List<NotaCreditoDetalle> notaCreditoDetalle = null;

		List<ContratoNotaCreditoDetalleDTO> contratos = new ArrayList<ContratoNotaCreditoDetalleDTO>();
		List<TituloNotaCreditoDTO> titulos = new ArrayList<TituloNotaCreditoDTO>();

		LinkedList<ContratoTitulo> lcontratosTitulos = null;
		LinkedList<NotaCreditoDetalle> lnotaCreditoDetalle = null;

		ContratoTitulo primerTitulo = null;

		Long idContrato = null;
		Long idTituloCnt = null;

		Double costoTotal = null;
		Double costoTotalActual = 0.0;

		String noContrato = null;
		String noContratoActual = null;

		String idSap = null;
		String idSapActual = null;

		String claveIva = null;
		String claveIvaActual = null;

		Double montoTotal = 0.0;
		Double montoTotalActual = 0.0;

		Double monto = 0.0;
		Double costo = 0.0;

		Double montoContrato = 0.0;
		Double costoContrato = 0.0;

		dbtitulos = ListaUtilerias.safeList(notaCreditoDAO.consultaTitulosBajaDisponibles(idEstudio));
		udbtitulos = ListaUtilerias.safeList(notaCreditoDAO.consultaTitulosBajaUtilizados(idEstudio, idNota == null ? 0 : idNota));
		dbtitulos = (ArrayList<ContratoTitulo>) CollectionUtils.subtract(dbtitulos, udbtitulos);

		lcontratosTitulos = new LinkedList<ContratoTitulo>(dbtitulos);

		primerTitulo = lcontratosTitulos.getFirst();

		idContrato = primerTitulo.getIdContrato();
		idSap = primerTitulo.getIdSap();
		noContrato = primerTitulo.getNumeroContrato();
		claveIva = primerTitulo.getClaveIva();
		idTituloCnt = primerTitulo.getIdTituloCnt();

		costoTotal = new Double(primerTitulo.getCosto());

		notaCreditoDetalle = ListaUtilerias.safeList(notaCreditoDAO.consultaNotaCreditoDetalle(null, idNota == null ? 0 : idNota, idContrato, idTituloCnt));
		lnotaCreditoDetalle = new LinkedList<NotaCreditoDetalle>(notaCreditoDetalle);

		if (!lnotaCreditoDetalle.isEmpty()) {
			String valorMonto = lnotaCreditoDetalle.getFirst().getMonto();

			if (valorMonto != null && StringUtilerias.isFloat(valorMonto))
				montoTotal = new Double(valorMonto);

		}

		for (ContratoTitulo contratoTitulo : dbtitulos) {

			String descTitulo = contratoTitulo.getDescTitulo();
			Long idTituloCntActual = contratoTitulo.getIdTituloCnt();
			Long idContratoActual = contratoTitulo.getIdContrato();
			Boolean nuevo = true;
			noContratoActual = contratoTitulo.getNumeroContrato();
			idSapActual = contratoTitulo.getIdSap();
			claveIvaActual = contratoTitulo.getClaveIva();
			costo = new Double(contratoTitulo.getCosto());

			notaCreditoDetalle = ListaUtilerias.safeList(notaCreditoDAO.consultaNotaCreditoDetalle(null, idNota == null ? 0 : idNota, idContratoActual, idTituloCntActual));
			lnotaCreditoDetalle = new LinkedList<NotaCreditoDetalle>(notaCreditoDetalle);

			TituloNotaCreditoDTO titulo = new TituloNotaCreditoDTO();
			titulo.setCosto(costo.toString());
			titulo.setDescTitulo(descTitulo);
			titulo.setIdTituloCnt(idTituloCntActual);
			titulo.setTipoTitulo(0);

			if (!lnotaCreditoDetalle.isEmpty()) {
				String valorMonto = lnotaCreditoDetalle.getFirst().getMonto();

				if (valorMonto != null) {
					if (StringUtilerias.isFloat(valorMonto))
						monto = new Double(valorMonto);
					nuevo = false;
				}

			}

			titulo.setNuevo(nuevo);
			titulo.setMonto(monto.toString());

			costoTotal = costoTotalActual;
			costoTotalActual = costoTotalActual + costo;

			montoTotal = montoTotalActual;
			montoTotalActual = montoTotalActual + monto;

			if (idContrato != idContratoActual) {

				ContratoNotaCreditoDetalleDTO contrato = new ContratoNotaCreditoDetalleDTO();
				contrato.setIdContrato(idContrato);
				contrato.setNumeroContrato(noContrato);
				contrato.setClaveIva(claveIva);
				contrato.setIdSap(idSap);
				contratos.add(contrato);

				List<TituloNotaCreditoDTO> dbtitulosdisminucion = titulosNotaCreditoDisminucion(idNota, idContrato);

				for (TituloNotaCreditoDTO dbtitulodisminucion : dbtitulosdisminucion) {
					costoTotal = costoTotal + new Double(dbtitulodisminucion.getCosto());
					montoTotal = montoTotal + new Double(dbtitulodisminucion.getMonto());
				}

				contrato.setCosto(costoTotal.toString());
				contrato.setMonto(montoTotal.toString());

				titulos.addAll(dbtitulosdisminucion);

				contrato.setTitulos(titulos);

				titulos = new ArrayList<TituloNotaCreditoDTO>();

				idContrato = idContratoActual;
				noContrato = noContratoActual;
				claveIva = claveIvaActual;
				idSap = idSapActual;

				costoTotalActual = costo;
				montoTotalActual = monto;

				montoContrato = montoContrato + montoTotal;
				costoContrato = costoContrato + costoTotal;

			}

			titulos.add(titulo);
			monto = 0.0;

		}

		costoTotal = costoTotalActual;
		montoTotal = montoTotalActual;

		montoContrato = montoContrato + montoTotal;
		costoContrato = costoContrato + costoTotal;

		ContratoNotaCreditoDetalleDTO contrato = new ContratoNotaCreditoDetalleDTO();
		contrato.setIdContrato(idContrato);
		contrato.setNumeroContrato(noContrato);
		contrato.setClaveIva(claveIva);
		contrato.setIdSap(idSap);

		List<TituloNotaCreditoDTO> dbtitulosdisminucion = titulosNotaCreditoDisminucion(idNota, idContrato);

		for (TituloNotaCreditoDTO dbtitulodisminucion : dbtitulosdisminucion) {
			costoTotal = costoTotal + new Double(dbtitulodisminucion.getCosto());
			montoTotal = montoTotal + new Double(dbtitulodisminucion.getMonto());
		}

		contrato.setCosto(costoTotal.toString());
		contrato.setMonto(montoTotal.toString());

		titulos.addAll(dbtitulosdisminucion);

		contrato.setTitulos(titulos);

		contratos.add(contrato);

		return contratos;
	}

	@Deprecated
	@SuppressWarnings("unchecked")
	List<TituloNotaCreditoDTO> titulosNotaCreditoDisminucion(Long idNota, Long idContrato) {

		List<ContratoTitulo> dbtitulos = ListaUtilerias.safeList(notaCreditoDAO.consultaTitulosDisminucionDisponibles(idContrato));
		List<ContratoTitulo> udbtitulos = ListaUtilerias.safeList(notaCreditoDAO.consultaTitulosDisminucionUtilizados(idContrato, idNota == null ? 0 : idNota));
		dbtitulos = (ArrayList<ContratoTitulo>) CollectionUtils.subtract(dbtitulos, udbtitulos);

		List<TituloNotaCreditoDTO> titulos = new ArrayList<TituloNotaCreditoDTO>();
		Double monto = 0.0;
		Boolean nuevo = true;

		for (ContratoTitulo dbtitulo : dbtitulos) {

			TituloNotaCreditoDTO titulo = new TituloNotaCreditoDTO();
			titulo.setCosto(dbtitulo.getCosto().toString());
			titulo.setDescTitulo(dbtitulo.getDescTitulo());
			titulo.setIdTituloCnt(dbtitulo.getIdTituloCnt());
			titulo.setTipoTitulo(1);

			List<NotaCreditoDetalle> notaCreditoDetalle = ListaUtilerias.safeList(notaCreditoDAO.consultaNotaCreditoDetalle(null, idNota == null ? 0 : idNota, idContrato, dbtitulo.getIdTituloCnt()));
			LinkedList<NotaCreditoDetalle> lnotaCreditoDetalle = new LinkedList<NotaCreditoDetalle>(notaCreditoDetalle);

			if (!lnotaCreditoDetalle.isEmpty()) {
				String valorMonto = lnotaCreditoDetalle.getFirst().getMonto();

				if (valorMonto != null) {
					if (StringUtilerias.isFloat(valorMonto))
						monto = new Double(valorMonto);
					nuevo = false;
				}

			}

			titulo.setMonto(monto.toString());
			titulo.setNuevo(nuevo);
			titulos.add(titulo);

			monto = 0.0;
		}

		return titulos;

	}

	public List<ContratoNotaCreditoDetalleDTO> cargaNotaCreditoDetalle(Long idEstudio, Long idNotaCredito, Boolean aprovada) {

		List<ContratoTitulo> bcontratos = null;
		List<ContratoTitulo> dcontratos = null;
		List<ContratoTitulo> bctitulos = null;
		List<ContratoTitulo> dctitulos = null;
		List<ContratoTitulo> bntitulos = null;
		List<ContratoTitulo> dntitulos = null;
		List<ContratoTitulo> bnntitulos = null;
		List<ContratoTitulo> dnntitulos = null;

		Long idNota = 0L;

		if (idNotaCredito != null)
			idNota = new Long(idNotaCredito);

		List<ContratoNotaCreditoDetalleDTO> contratoNotaDetalle = new ArrayList<ContratoNotaCreditoDetalleDTO>();

		bcontratos = notaCreditoDAO.obtenContratosConBaja(idEstudio);
		dcontratos = notaCreditoDAO.obtenContratosConDisminucion(idEstudio);

		List<ContratoTitulo> contratos = new ArrayList<ContratoTitulo>();
		contratos = mergeList(bcontratos, dcontratos);

		for (ContratoTitulo contrato : ListaUtilerias.safeList(contratos)) {

			Long idContrato = contrato.getIdContrato();

			bctitulos = ListaUtilerias.safeList(notaCreditoDAO.obtenTitulosBajaPorContrato(idEstudio, idContrato));
			dctitulos = ListaUtilerias.safeList(notaCreditoDAO.obtenTitulosDisminucionPorContrato(idEstudio, idContrato));
			bntitulos = ListaUtilerias.safeList(notaCreditoDAO.obtenTitulosBajaPorContratoEnNota(idEstudio, idContrato, idNota));
			dntitulos = ListaUtilerias.safeList(notaCreditoDAO.obtenTitulosDisminucionPorContratoEnNota(idEstudio, idContrato, idNota));
			bnntitulos = ListaUtilerias.safeList(notaCreditoDAO.obtenTitulosBajaPorContratoNoEnNota(idEstudio, idContrato, idNota));
			dnntitulos = ListaUtilerias.safeList(notaCreditoDAO.obtenTitulosDisminucionPorContratoNoEnNota(idEstudio, idContrato, idNota));

			List<ContratoTitulo> mbtitulos = ListaUtilerias.safeList(mergeList(bntitulos, bctitulos));
			List<ContratoTitulo> mdtitulos = ListaUtilerias.safeList(mergeList(dntitulos, dctitulos));

			List<ContratoTitulo> btitulos = (List<ContratoTitulo>) CollectionUtils.subtract(mbtitulos, bnntitulos);
			List<ContratoTitulo> dtitulos = (List<ContratoTitulo>) CollectionUtils.subtract(mdtitulos, dnntitulos);

			Double costo = 0.0;
			Double monto = 0.0;
			List<TituloNotaCreditoDTO> titulos = new ArrayList<TituloNotaCreditoDTO>();
			List<TituloNotaCreditoDTO> vbtitulos = transformTitulo(btitulos);
			List<TituloNotaCreditoDTO> vdtitulos = transformTitulo(dtitulos);

			titulos.addAll(vbtitulos);
			titulos.addAll(vdtitulos);

			for (TituloNotaCreditoDTO titulo : ListaUtilerias.safeList(titulos)) {

				String scosto = titulo.getCosto();
				Double tcosto = 0.0;
				String smonto = titulo.getMonto();
				Double tmonto = 0.0;

				if (scosto != null)
					tcosto = new Double(scosto);

				if (smonto != null)
					tmonto = new Double(smonto);

				costo = costo + tcosto;
				monto = monto + tmonto;

			}

			ContratoNotaCreditoDetalleDTO fcontrato = new ContratoNotaCreditoDetalleDTO();
			fcontrato.setIdContrato(idContrato);
			fcontrato.setNumeroContrato(contrato.getNumeroContrato());
			fcontrato.setClaveIva(contrato.getClaveIva());
			fcontrato.setIdSap(contrato.getIdSap());
			fcontrato.setCosto(costo.toString());
			fcontrato.setMonto(monto.toString());
			fcontrato.setTitulos(titulos);

			if (titulos != null && titulos.size() > 0)
				contratoNotaDetalle.add(fcontrato);

		}

		return contratoNotaDetalle;
	}

	public TituloNotaCreditoDTO transformTitulo(ContratoTitulo titulo) {

		Double costo = 0.0;
		Double monto = 0.0;

		if (titulo.getCosto() != null)
			costo = new Double(titulo.getCosto());

		if (titulo.getMonto() != null)
			monto = new Double(titulo.getMonto());

		TituloNotaCreditoDTO vtitulo = new TituloNotaCreditoDTO();
		vtitulo.setCosto(costo.toString());
		vtitulo.setDescTitulo(titulo.getDescTitulo());
		vtitulo.setIdTituloCnt(titulo.getIdTituloCnt());
		vtitulo.setMonto(monto.toString());
		vtitulo.setTipoTitulo(titulo.getTipoTitulo());
		return vtitulo;
	}

	public List<TituloNotaCreditoDTO> transformTitulo(List<ContratoTitulo> titulos) {
		List<TituloNotaCreditoDTO> vtitulos = new ArrayList<TituloNotaCreditoDTO>();
		for (ContratoTitulo titulo : titulos) {
			TituloNotaCreditoDTO vbtitulo = transformTitulo(titulo);
			vtitulos.add(vbtitulo);
		}
		return vtitulos;
	}

	public <T> List<T> mergeList(List<T> target, List<T> other) {

		Set<T> scontratos = new HashSet<T>(target);
		scontratos.addAll(other);
		List<T> result = new ArrayList<T>(scontratos);

		return result;

	}

	public Long guardarFactura(ContratoNotaCreditoGeneralDTO factura) {

		Long idNota = factura.getIdNota();

		NotaCredito notaCredito = new NotaCredito();

		notaCredito.setApproved(factura.getApproved());
		notaCredito.setComentario(factura.getComentario());
		notaCredito.setFecha(factura.getFechaFactura());
		notaCredito.setIdEstudio(factura.getIdEstudio());
		notaCredito.setIdNota(factura.getIdNota());
		notaCredito.setIdSapRegistro(factura.getIdSapRegistro());
		notaCredito.setNoFactura(factura.getNumeroFactura());

		if (idNota == null) {
			idNota = notaCreditoDAO.guardarNotaCredito(notaCredito);
			idNota = notaCredito.getIdNota();
		}
		else
			notaCreditoDAO.actualizarNotaCredito(notaCredito);

		guardarFacturaDetalle(factura.getContratos(), notaCredito.getIdNota());

		return idNota;

	}

	public void guardarFacturaDetalle(List<ContratoNotaCreditoDetalleDTO> contratos, Long idNota) {

		NotaCreditoDetalle detalle = null;

		for (ContratoNotaCreditoDetalleDTO contrato : ListaUtilerias.safeList(contratos)) {
			for (TituloNotaCreditoDTO titulo : ListaUtilerias.safeList(contrato.getTitulos())) {

				Long idContrato = contrato.getIdContrato();
				Long idTitulo = titulo.getIdTituloCnt();
				String monto = titulo.getMonto();

				List<NotaCreditoDetalle> detalles = notaCreditoDAO.consultaNotaCreditoDetalle(null, idNota, idContrato, idTitulo);

				if (detalles.isEmpty()) {
					detalle = new NotaCreditoDetalle();
					detalle.setIdContrato(idContrato);
					detalle.setIdNota(idNota);
					detalle.setIdTituloCnt(idTitulo);
					detalle.setMonto(monto);
					notaCreditoDAO.guardarNotaCreditoDetalle(detalle);
				}
				else {
					LinkedList<NotaCreditoDetalle> ldetalles = new LinkedList<NotaCreditoDetalle>(detalles);
					detalle = ldetalles.getFirst();
					detalle.setMonto(monto);
					notaCreditoDAO.actualizarNotaCreditoDetalle(detalle);
				}

			}
		}
	}
	
	public void notificarServicioRest(ContratoNotaCreditoGeneralDTO factura) {

		if (factura != null && factura.getApproved().intValue() == 1) {
			wsbo.notificaFacturaInterfaz(factura);

			logger.debug("Actualiza a factura notificada");
		}
	}

	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;
	}
}