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

import java.sql.SQLException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.ibatis.exceptions.PersistenceException;
import org.apache.ibatis.executor.result.ResultMapException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Service;

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.FeesPagoCostoDTO;
import com.mx.dla.dda.contrato.fees.dtos.FeesPagoRangoDTO;
import com.mx.dla.dda.contrato.fees.dtos.FeesSuscriptorBD;
import com.mx.dla.dda.contrato.minimoseleccion.bos.MinimoSeleccionBO;
import com.mx.dla.dda.contrato.transaccion.exceptions.dtos.TransaccionException;
import com.mx.dla.global.bos.BaseBO;

@Service
public class FeesSuscriptorBO extends BaseBO {

	@Autowired
	private FeesContratoDAO feesContratoDAO;

	@Autowired
	private MinimoSeleccionBO minimoSeleccionBO;

	public FeesContratoPagoDTO crearSuscriptor(FeesContratoPagoBD pagoBD, List<FeesSuscriptorBD> feeBD) {
		FeesContratoPagoDTO fee = null;
		int numRangos = 1;

		if (feeBD == null) {
			List<FeesPagoCostoDTO> pagos = new ArrayList<FeesPagoCostoDTO>();

			FeesPagoCostoDTO pago = new FeesPagoCostoDTO(0L, "", numRangos);
			pagos.add(pago);

			fee = new FeesContratoPagoDTO(0L, 0L, 0L, "", "", "", "", "nuevo", pagos, null);
			fee.setMaxRangos(numRangos);
		} else {
			logger.info(feeBD.toString());
			List<FeesPagoCostoDTO> pagos = new ArrayList<FeesPagoCostoDTO>();
			for (FeesSuscriptorBD itemBD : feeBD) {
				boolean existente = false;
				for (FeesPagoCostoDTO item : pagos) {
					if (item.getIdCategoria().longValue() == itemBD.getIdCategoria().longValue()) {
						item.getRangos().add(new FeesPagoRangoDTO(itemBD.getIdPagoRango(), itemBD.getDesde(),
								itemBD.getHasta(), itemBD.getCosto()));
						existente = true;
					}
				}
				if (!existente) {
					FeesPagoCostoDTO pago = new FeesPagoCostoDTO(itemBD.getIdCategoria(), itemBD.getDesCategoria(), 0);
					pago.getRangos().add(new FeesPagoRangoDTO(itemBD.getIdPagoRango(), itemBD.getDesde(),
							itemBD.getHasta(), itemBD.getCosto()));
					pagos.add(pago);
				}
			}

			numRangos = pagos.get(0).getRangos().size();
			fee = new FeesContratoPagoDTO(pagoBD.getIdContratoPago(), pagoBD.getIdContrato(),
					pagoBD.getIdTipoSuscriptor(), this.getFecha(pagoBD.getFechaInicio()),
					this.getFecha(pagoBD.getFechaFin()), pagoBD.getTipoAnio(), pagoBD.getTipoPago(), "editar", pagos,
					null);
			fee.setAnioContrato(pagoBD.getAnioContrato());
			fee.setMaxRangos(numRangos);
		}
		return fee;
	}

	public void guardarSuscriptor(FeesContratoPagoDTO periodo, Long idContrato)
			throws ParseException, ResultMapException, SQLException, TransaccionException {
		try {
			List<FeesSuscriptorBD> minSelCat = new ArrayList<FeesSuscriptorBD>();
			Integer str = null;
			logger.info("periodo a guardar." + periodo.toString());
			FeesContratoPagoBD contratoPago = new FeesContratoPagoBD(0L, idContrato, periodo.getIdSuscriptor(),
					periodo.getTipoPago(), periodo.getTipoAnio(), this.crearFecha(periodo.getFechaInicio()),
					this.crearFecha(periodo.getFechaFin()));
			contratoPago.setAnioContrato(periodo.getAnioContrato());
			feesContratoDAO.guardarContratoPago(contratoPago);
			minimoSeleccionBO.guardarMinSeleccion(contratoPago.getIdContratoPago(), null, null); // Se guarda el minimo
																									// de seleccion por
																									// periodo
			this.guardarRangoPagoCosto(periodo, contratoPago);

			for (FeesPagoCostoDTO categoria : periodo.getCategorias())
				minSelCat.add(new FeesSuscriptorBD(contratoPago.getIdContratoPago(), str, categoria.getIdCategoria()));

			minimoSeleccionBO.guardarMinSeleccionXCatAnio(minSelCat); // Se guarda el minimo de seleccion por categoria
			logger.info("guardar msle. " + minSelCat.toString());
		} catch (PersistenceException e) {
			throw new TransaccionException("Error al cargar los datos.", e);
		} catch (DataAccessException e) {
			throw new TransaccionException("Error al cargar los datos", e);
		}
	}

	public void guardarRangoPagoCosto(FeesContratoPagoDTO periodo, FeesContratoPagoBD contratoPago)
			throws ResultMapException, SQLException, TransaccionException {

		try {
			List<Long> idRangos = new ArrayList<Long>();
			List<FeesSuscriptorBD> costos = new ArrayList<FeesSuscriptorBD>();

			for (FeesPagoRangoDTO rango : periodo.getCategorias().get(0).getRangos()) // Se guardan los rangos
			{
				feesContratoDAO.guardarPagoRango(rango, contratoPago.getIdContratoPago());
				idRangos.add(rango.getIdRango());
			}

			for (FeesPagoCostoDTO categoria : periodo.getCategorias())
				for (int i = 0; i < categoria.getRangos().size(); i++)
					costos.add(new FeesSuscriptorBD(idRangos.get(i), categoria.getRangos().get(i).getMonto(),
							categoria.getIdCategoria()));

			feesContratoDAO.guardarPagoCostoALL(costos);
			logger.info("Se guarda los costos. " + costos.toString() + "del periodo " + periodo.getIdContratoPago());
		} catch (PersistenceException e) {
			throw new TransaccionException("Error al cargar los datos.", e);
		} catch (DataAccessException e) {
			throw new TransaccionException("Error al cargar los datos", e);
		}
	}

	public void editarSuscriptor(FeesContratoPagoDTO periodo)
			throws ParseException, ResultMapException, SQLException, TransaccionException {

		try {
			logger.info("periodo a actualizar." + periodo.toString());
			FeesContratoPagoBD contratoPago = new FeesContratoPagoBD(periodo.getIdContratoPago(),
					periodo.getIdContrato(), periodo.getIdSuscriptor(), periodo.getTipoPago(), periodo.getTipoAnio(),
					this.crearFecha(periodo.getFechaInicio()), this.crearFecha(periodo.getFechaFin()));
			contratoPago.setAnioContrato(periodo.getAnioContrato());
			feesContratoDAO.actualizarContratoPago(contratoPago);
			this.guardarRangoPagoCosto(periodo, contratoPago);
			logger.info("Se ha terminado de editar el periodo. id[" + periodo.getIdContratoPago() + "]");
		} catch (PersistenceException e) {
			throw new TransaccionException("Error al cargar los datos.", e);
		} catch (DataAccessException e) {
			throw new TransaccionException("Error al cargar los datos", e);
		}
	}

	public void eliminarSuscriptores(Long idContrato)
			throws ParseException, ResultMapException, SQLException, TransaccionException {

		try {
			minimoSeleccionBO.eliminarMinSeleccionXCto(idContrato);
			this.eliminarRangosCostoSuscriptor(idContrato);
			feesContratoDAO.eliminarContratoPagoXCto(idContrato);
		} catch (PersistenceException e) {
			throw new TransaccionException("Error al cargar los datos.", e);
		} catch (DataAccessException e) {
			throw new TransaccionException("Error al cargar los datos", e);
		}
	}

	public void eliminarSuscriptor(FeesContratoPagoDTO periodo)
			throws ResultMapException, SQLException, TransaccionException {

		try {
			minimoSeleccionBO.eliminarMinSeleccion(periodo.getIdContratoPago(), null); // Se elimina minimum seleccion
			for (FeesPagoCostoDTO categoria : periodo.getCategorias()) // Se elimina los costos asociados rangos-categ
				for (FeesPagoRangoDTO rango : categoria.getRangos())
					feesContratoDAO.eliminarPagoCosto(categoria.getIdCategoria(), rango.getIdRango());
			feesContratoDAO.eliminarPagoRango(periodo.getIdContratoPago()); // Se eliminan los rangos
			feesContratoDAO.eliminarContratoPago(periodo.getIdContratoPago());
		} catch (PersistenceException e) {
			throw new TransaccionException("Error al cargar los datos.", e);
		} catch (DataAccessException e) {
			throw new TransaccionException("Error al cargar los datos", e);
		}
	}

	public void eliminarRangosCostoSuscriptor(Long idContrato)
			throws ParseException, ResultMapException, SQLException, TransaccionException {

		try {
			feesContratoDAO.eliminarPagoCostoXCto(idContrato); // Se elimina los costos asociados rangos-categ
			feesContratoDAO.eliminarPagoRangoXCto(idContrato); // Se eliminan los rangos
			logger.info("Se han eliminado los rangos y valores de los rangos");
		} catch (PersistenceException e) {
			throw new TransaccionException("Error al cargar los datos.", e);
		} catch (DataAccessException e) {
			throw new TransaccionException("Error al cargar los datos", e);
		}
	}

	public List<FeesContratoPagoDTO> eliminarCategoriaSuscriptor(Long idCategoria, List<FeesContratoPagoDTO> periodos)
			throws ResultMapException, SQLException, TransaccionException {

		try {
			// se eliminan los valores por rango y categoria
			feesContratoDAO.eliminarPagoCostoXCategoria(idCategoria);

			for (FeesContratoPagoDTO periodo : periodos) {
				// se elimina la categoria insertada para el minimo de seleccion
				minimoSeleccionBO.eliminarMinSeleccion(periodo.getIdContratoPago(), idCategoria);
				int index = -1;
				for (int i = 0; i < periodo.getCategorias().size(); i++)
					if (periodo.getCategorias().get(i).getIdCategoria().longValue() == idCategoria.longValue())
						index = i;

				if (index != -1)
					periodo.getCategorias().remove(index);
			}
			feesContratoDAO.actualizarTitulosTCateg(idCategoria); // Se elimina la relacion de la categoria con los
																	// titulos
			feesContratoDAO.actualizarTitulosMCateg(idCategoria);
			feesContratoDAO.eliminarPagoCategoria(idCategoria); // Se elimina la categoria
			return periodos;
		} catch (PersistenceException e) {
			throw new TransaccionException("Error al cargar los datos.", e);
		} catch (DataAccessException e) {
			throw new TransaccionException("Error al cargar los datos", e);
		}
	}

	public Date crearFecha(String valor) throws ParseException {
		DateFormat formatter1 = new SimpleDateFormat("MM/dd/yyyy");
		Date fecha = formatter1.parse(valor);
		return fecha;

	}

	public String getFecha(Date fecha) {
		SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy");
		return sdf.format(fecha);
	}
}
