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

import java.io.IOException;
import java.net.SocketTimeoutException;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

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.Component;

import com.mx.dla.dda.contrato.fees.dtos.FeesSuscriptorBD;
import com.mx.dla.dda.contrato.minimoseleccion.daos.MinimoSeleccionDAO;
import com.mx.dla.dda.contrato.minimoseleccion.dtos.AnioInfoDTO;
import com.mx.dla.dda.contrato.minimoseleccion.dtos.AnnioDTO;
import com.mx.dla.dda.contrato.minimoseleccion.dtos.AnnioPeriodoDTO;
import com.mx.dla.dda.contrato.minimoseleccion.dtos.CategoriaInfoDTO;
import com.mx.dla.dda.contrato.minimoseleccion.dtos.CategoriaMinimoDTO;
import com.mx.dla.dda.contrato.minimoseleccion.dtos.ContratoMinimoSeleccionDTO;
import com.mx.dla.dda.contrato.minimoseleccion.dtos.ContratoPagoCategoriaDTO;
import com.mx.dla.dda.contrato.minimoseleccion.dtos.ContratoPagoCostoDTO;
import com.mx.dla.dda.contrato.minimoseleccion.dtos.ContratoPagoDTO;
import com.mx.dla.dda.contrato.minimoseleccion.dtos.ContratoPagoFlatDTO;
import com.mx.dla.dda.contrato.minimoseleccion.dtos.DetalleAnnioPeriodoDTO;
import com.mx.dla.dda.contrato.minimoseleccion.dtos.MontoRealDTO;
import com.mx.dla.dda.contrato.minimoseleccion.dtos.PeriodoDTO;
import com.mx.dla.dda.contrato.minimoseleccion.dtos.PeriodoInfoDTO;
import com.mx.dla.dda.contrato.minimoseleccion.dtos.SuscriptoresPeriodoDTO;
import com.mx.dla.dda.contrato.transaccion.exceptions.dtos.TransaccionException;
import com.mx.dla.dda.contrato.ws.obtenersuscriptores.ParamSuscriptoresContrato;
import com.mx.dla.dda.contrato.ws.obtenersuscriptores.ResponseSuscriptoresContratoDTO;
import com.mx.dla.dda.restClient.bos.DLARestClient;
import com.mx.dla.dda.restClient.bos.DLARestClientFactory;
import com.mx.dla.dda.restClient.constants.DLARestServices;
import com.mx.dla.global.bos.BaseBO;

@Component
public class MinimoSeleccionBO extends BaseBO {

	@Autowired
	private MinimoSeleccionDAO minimoSeleccionDAO;

	@Autowired
	public DLARestClientFactory dlaRestClientFactory;

	public void cambiaMinimoCategoria(List<CategoriaMinimoDTO> campoPeriodos) throws ResultMapException, SQLException, TransaccionException {

		Map<String, String> categoriaMinimo = null;
		String[] idCategoria;

		logger.info("campoPeriodo: " + campoPeriodos);
		try {

			for (CategoriaMinimoDTO categoriaMinimoDTO : campoPeriodos) {
				logger.info("categoriaMinimo " + categoriaMinimoDTO);
				categoriaMinimo = categoriaMinimoDTO.getPareja();
				minimoSeleccionDAO.cambiaMontoPeriodo(categoriaMinimoDTO.getIdMonto(),
						categoriaMinimoDTO.getMontoMinimo());
				for (String llave : categoriaMinimo.keySet()) {
					idCategoria = llave.split("_");
					logger.info(idCategoria[1] + " : " + categoriaMinimo.get(llave));
					minimoSeleccionDAO.cambiaMinimoCategoria(Long.parseLong(idCategoria[1]),
							categoriaMinimo.get(llave));
				}
			}

		} 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 Long obtenerEstatusContrato(Long idContrato) throws ResultMapException, SQLException, TransaccionException {

		Long estatusContrato = null;

		try {
			estatusContrato = minimoSeleccionDAO.obtenerEstatusContrato(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);
		}

		return estatusContrato;
	}

	public String obtenTipoPago(Long idContrato) throws ResultMapException, SQLException, TransaccionException {

		String tipoPago = null;

		try {
			tipoPago = minimoSeleccionDAO.obtenTipoPago(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);
		}

		return tipoPago;

	}

	public List<AnnioDTO> obtenAnnioContrato(Long idContrato) throws ResultMapException, SQLException, TransaccionException {

		List<AnnioDTO> annios = null;

		try {
			annios = minimoSeleccionDAO.obtenAnnioContrato(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);
		}

		return annios;
	}

	public List<PeriodoDTO> obtnePeriodoContrato(Long idContrato) throws ResultMapException, SQLException, TransaccionException {

		List<PeriodoDTO> periodos = null;
		SimpleDateFormat formatoDeFecha = new SimpleDateFormat("MM/dd/yyyy");

		try {
			periodos = minimoSeleccionDAO.obtnePeriodoContrato(idContrato);

			for (PeriodoDTO periodo : periodos) {
				periodo.setStrFechaInicio(formatoDeFecha.format(periodo.getFechaInicio()));
				periodo.setStrFechaFin(formatoDeFecha.format(periodo.getFechaFin()));
			}

		} catch (PersistenceException e) {
			throw new TransaccionException("Error al cargar los datos.", e);
		} catch (DataAccessException e) {
			throw new TransaccionException("Error al cargar los datos", e);
		}

		return periodos;
	}

	public AnnioPeriodoDTO obtenAnnioPeriodo(Long idContratoPago, Integer annio, String tipoPago, Long idContrato)
			throws ResultMapException, SQLException, TransaccionException {

		AnnioPeriodoDTO annioPeriodo = new AnnioPeriodoDTO();
		String monto = null;
		List<DetalleAnnioPeriodoDTO> categorias = null;
		String precioAnualyMinimo = null;
		String[] precioAnualyMinimoArray = null;

		try {

			if (tipoPago.equals("FLAT")) {

				monto = minimoSeleccionDAO.obtenAnnioMinimoMonto(idContratoPago, annio);
				categorias = minimoSeleccionDAO.obtenAnnioCategorias(idContratoPago, annio);

			} else {

				monto = minimoSeleccionDAO.obtenPeriodoMinimoMonto(idContratoPago);
				categorias = minimoSeleccionDAO.obtenPeriodoCategorias(idContratoPago);

			}

			for (DetalleAnnioPeriodoDTO categoria : categorias) {
				precioAnualyMinimo = obtenPrecioAnualAndMinimo(tipoPago, idContratoPago, annio,
						categoria.getIdPagoCategoria(), Integer.parseInt(categoria.getMinimoTitulos()), idContrato);
				precioAnualyMinimoArray = precioAnualyMinimo.split("_");
				categoria.setPrecioAnual(precioAnualyMinimoArray[0]);
				categoria.setMinimo(precioAnualyMinimoArray[1]);
			}

			annioPeriodo.setIdContratoPago(idContratoPago);
			annioPeriodo.setMinimoMonto(monto);
			annioPeriodo.setCategorias(categorias);

		} catch (PersistenceException e) {
			throw new TransaccionException("Error al cargar los datos.", e);
		} catch (DataAccessException e) {
			throw new TransaccionException("Error al cargar los datos", e);
		}

		return annioPeriodo;
	}

	public boolean actualizaCategoriasMonto(Long idContratoPago, String minimoMonto, Map<Long, String> categoriasMod,
			Integer annio, String tipoPago) throws ResultMapException, SQLException, TransaccionException {
		boolean respuesta = false;
		logger.info("idContratoPago : " + idContratoPago + " minimoMonto : " + minimoMonto + " key : "
				+ categoriasMod.keySet());

		try {

			if (tipoPago.equals("FLAT")) {
				minimoSeleccionDAO.actualizaMinimoMontoAnnio(idContratoPago, minimoMonto, annio);
			} else {
				minimoSeleccionDAO.actualizaMinimoMontoPeriodo(idContratoPago, minimoMonto);
			}

			for (Long key : categoriasMod.keySet()) {
				minimoSeleccionDAO.actualizaMinimoTitulos(categoriasMod.get(key), key);
			}

			respuesta = true;

		} catch (PersistenceException e) {
			throw new TransaccionException("Error al cargar los datos.", e);
		} catch (DataAccessException e) {
			throw new TransaccionException("Error al cargar los datos", e);
		}

		return respuesta;
	}

	public String obtenPrecioAnualAndMinimo(String tipoPago, Long idContratoPago, Integer annio, Long idPagoCategoria,
			Integer noTitulos, Long idContrato) throws ResultMapException, SQLException, TransaccionException {

		String respuesta = null;
		String precio = null;
		Integer minimo = null;
		Integer numeroSuscriptores = 0;

		try {

			if (tipoPago.equals("FLAT")) {

				precio = minimoSeleccionDAO.obtenCostoAnnio(idContratoPago, idPagoCategoria, annio);

			} else {

				numeroSuscriptores = obtnerNumeroSuscriptores(idContratoPago, idContrato);
				logger.info("numero de Suscriptores : " + numeroSuscriptores);
				precio = minimoSeleccionDAO.obtenCostoPeriodo(idContratoPago, idPagoCategoria, numeroSuscriptores);

			}

			logger.info("precio : " + precio);

			if (precio == null || precio.equals("")) {
				precio = "0";
			}

			minimo = noTitulos * Integer.parseInt(precio);
			respuesta = precio + "_" + minimo.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);
		}

		return respuesta;
	}

	public Integer obtnerNumeroSuscriptores(Long idContratoPago, Long idContrato) throws ResultMapException, SQLException, TransaccionException {

		Integer nSuscriptores = 0;
		String fechaInicioPeriodo = null;
		ParamSuscriptoresContrato solicitud = new ParamSuscriptoresContrato();
		ResponseSuscriptoresContratoDTO respuesta = null;
		DLARestClient dLARestClient;

		try {

			fechaInicioPeriodo = minimoSeleccionDAO.obtneFechaInicioPeriodo(idContrato, idContratoPago);

			solicitud.setFechaInicioPeriodo(fechaInicioPeriodo);
			solicitud.setIdContrato(idContrato.toString());

			dLARestClient = dlaRestClientFactory.getClient(DLARestServices.OBTENER_SUSCRIPTORES_CONTRATO);

			logger.info("request : " + solicitud);

			respuesta = dLARestClient.get(solicitud, ResponseSuscriptoresContratoDTO.class);

			logger.info("response : " + respuesta);

			nSuscriptores = Integer.parseInt(respuesta.getSuscriptores());

		} catch (PersistenceException e) {
			throw new TransaccionException("Error al cargar los datos.", e);
		} catch (DataAccessException e) {
			throw new TransaccionException("Error al cargar los datos", e);
		} catch (SocketTimeoutException e) {
			throw new TransaccionException("Error al enviar los datos al servicio", e);
		} catch (IOException e) {
			throw new TransaccionException("Error al enviar los datos al servicio", e);
		}

		return nSuscriptores;
	}

	// Se guardan los minimos de seleccion que vienen desde fees
	public void guardarMinSeleccion(Long idCtoPago, Long idCategoria, Long anio) {
		if (idCtoPago != null && idCategoria == null)
			minimoSeleccionDAO.guardarminSeleccionCtoPago(minimoSeleccionDAO.getSecuenciaSeleccion(), idCtoPago, anio);
		else if (idCategoria != null)
			minimoSeleccionDAO.guardarminSeleccionCtoPagoCateg(minimoSeleccionDAO.getSecuenciaSeleccion(), idCtoPago,
					idCategoria, anio);
	}

	public void guardarMinSeleccionXAnio(List<FeesSuscriptorBD> minSelAnio) {
		minimoSeleccionDAO.guardarMinSeleccionXAnio(minSelAnio);
	}

	public void guardarMinSeleccionXCatAnio(List<FeesSuscriptorBD> minSel) {
		minimoSeleccionDAO.guardarMinSeleccionXCatAnio(minSel);
	}

	public void eliminarMinSeleccion(Long idCtoPago, Long idCateg) {
		if (idCtoPago != null && idCateg == null)
			minimoSeleccionDAO.eliminarminSeleccionCtoPago(idCtoPago);
		else if (idCateg != null)
			minimoSeleccionDAO.eliminarminSeleccionCtoPagoCateg(idCtoPago, idCateg);
	}

	public void eliminarMinSeleccionXCto(Long idContrato) {
		minimoSeleccionDAO.eliminarMinSeleccionXCto(idContrato);
	}

	public List<PeriodoInfoDTO> consultaInformacionRender(Long idContrato) {

		List<PeriodoInfoDTO> periodosLista = new ArrayList<PeriodoInfoDTO>();
		List<AnioInfoDTO> anniosLista = new ArrayList<AnioInfoDTO>();
		List<CategoriaInfoDTO> categoriasLista = new ArrayList<CategoriaInfoDTO>();

		List<ContratoPagoDTO> periodos = minimoSeleccionDAO.consultaPeriodosPagoContrato(idContrato);
		List<ContratoPagoCategoriaDTO> categorias = minimoSeleccionDAO.consultaCategoriasPagoContrato(idContrato);
		List<AnnioDTO> annios = minimoSeleccionDAO.obtenAnnioContrato(idContrato);

		for (ContratoPagoDTO periodo : periodos) {
			PeriodoInfoDTO periodoInfo = new PeriodoInfoDTO();
			periodoInfo.setIdContratoPago(periodo.getIdContratoPago());

			Integer annioIndex = 0;
			anniosLista = new ArrayList<AnioInfoDTO>();

			do {
				AnioInfoDTO annioInfo = new AnioInfoDTO();
				AnnioDTO annio = new AnnioDTO();

				if (annios != null && annios.size() != 0) {
					annio = annios.get(annioIndex);
					annioInfo.setAnnio(annio.getAnnio());
					annioIndex++;
				} else {
					annioInfo.setAnnio(null);
					annioIndex = null;
				}
				categoriasLista = new ArrayList<CategoriaInfoDTO>();
				for (ContratoPagoCategoriaDTO categoria : categorias) {
					CategoriaInfoDTO categoriaInfo = new CategoriaInfoDTO();
					categoriaInfo.setIdPagoCateg(categoria.getIdPagoCateg());
					categoriaInfo.setDescCategoria(categoria.getDescCategoria());
					categoriasLista.add(categoriaInfo);

					ContratoMinimoSeleccionDTO params = new ContratoMinimoSeleccionDTO();

					params.setIdContratoPago(periodoInfo.getIdContratoPago());
					params.setIdPagoCategoria(categoriaInfo.getIdPagoCateg());
					params.setAnnio(annioInfo.getAnnio());

				}

				annioInfo.setCategorias(categoriasLista);
				anniosLista.add(annioInfo);

			} while (annioIndex != null && annios != null && annios.size() != 0 && annioIndex < annios.size());

			periodoInfo.setAnnios(anniosLista);
			periodosLista.add(periodoInfo);
		}

		return periodosLista;

	}

	public List<ContratoPagoDTO> consultaInformacionPeriodos(Long idContrato) {
		return minimoSeleccionDAO.consultaPeriodosPagoContrato(idContrato);
	}

	public List<ContratoPagoCategoriaDTO> consultaInformacionCategorias(Long idContrato) {
		return minimoSeleccionDAO.consultaCategoriasPagoContrato(idContrato);
	}

	public List<AnnioDTO> consultaInformacionAnnios(Long idContrato) {
		return minimoSeleccionDAO.obtenAnnioContrato(idContrato);
	}

	public List<ContratoPagoFlatDTO> consultaInformacionCostoFlat(Long idContrato) {
		return minimoSeleccionDAO.consultaContratoPagoFlat(idContrato);
	}

	public List<AnnioDTO> consultaInformacionAnniosPorPeriodo(Long idContrato) {
		return minimoSeleccionDAO.obtenAnniosPeriodoPorContrato(idContrato);
	}

	public List<ContratoPagoCostoDTO> consultaInformacionCostoSubscriptores(Long idContrato) {

		List<ContratoPagoCostoDTO> contratoPagoCosto = new ArrayList<ContratoPagoCostoDTO>();

		List<ContratoPagoDTO> periodos = minimoSeleccionDAO.consultaPeriodosPagoContrato(idContrato);
		List<ContratoPagoCategoriaDTO> categorias = minimoSeleccionDAO.consultaCategoriasPagoContrato(idContrato);
		HashMap<Long, Integer> noSuscriptoresPorPeriodo = new HashMap<Long, Integer>();

		// nuevo
		List<SuscriptoresPeriodoDTO> suscriptoresPeriodo = minimoSeleccionDAO.obtnerSuscriptoresPeriodo(idContrato);

		for (SuscriptoresPeriodoDTO peroido : suscriptoresPeriodo) {
			noSuscriptoresPorPeriodo.put(peroido.getIdContratoPago(), peroido.getSuscriptores());
		}

		for (ContratoPagoDTO periodo : periodos)
			for (ContratoPagoCategoriaDTO categoria : categorias) {

				Long idContratoPago = periodo.getIdContratoPago();
				Long idPagoCategoria = categoria.getIdPagoCateg();

				ContratoPagoCostoDTO item = new ContratoPagoCostoDTO();
				item.setIdPagoCateg(idPagoCategoria);
				item.setIdContratoPago(idContratoPago);

				Integer noSuscriptores = noSuscriptoresPorPeriodo.get(idContratoPago);
				String costo = minimoSeleccionDAO.obtenCostoPeriodo(idContratoPago, idPagoCategoria,
						noSuscriptores == null ? 0 : noSuscriptores);

				item.setCosto(costo);

				contratoPagoCosto.add(item);
			}

		return contratoPagoCosto;
	}

	public List<ContratoMinimoSeleccionDTO> consultaInformacionMinimos(Long idContrato) {
		return minimoSeleccionDAO.consultaMinimosSeleccionContrato(idContrato);
	}

	public void actualizaMinimoMonto(Long idContratoPago, Long idPagoCategoria, Integer annio, String minimoMonto) {
		logger.info("idContratoPago: " + idContratoPago + " idPagoCategoria: " + idPagoCategoria + " annio: " + annio
				+ " minimoMonto: " + minimoMonto);
		minimoSeleccionDAO.actualizaMinimoMonto(idContratoPago, idPagoCategoria, annio, minimoMonto);
	}

	public List<MontoRealDTO> consultaInformacionMontosReales(Long idContrato) {
		List<MontoRealDTO> montosReales = minimoSeleccionDAO.obtenInformacionMontoReal(idContrato);
		return montosReales;
	}

}
