package com.mx.dla.dda.admin.catalogos.tipoCambio.bos;

import java.sql.SQLException;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
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.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.mx.dla.dda.admin.catalogos.tipoCambio.daos.TipoCambioDAO;
import com.mx.dla.dda.admin.catalogos.tipoCambio.dtos.MesTiposCTDTO;
import com.mx.dla.dda.admin.catalogos.tipoCambio.dtos.TipoCambioDTO;
import com.mx.dla.dda.admin.catalogos.tipoCambio.dtos.TipoCambioPaisDTO;
import com.mx.dla.dda.catalogos.daos.CatalogosDAO;
import com.mx.dla.dda.catalogos.dtos.PaisVentaDTO;
import com.mx.dla.dda.contrato.transaccion.exceptions.dtos.TransaccionException;
import com.mx.dla.dda.general.constants.MesesAnio;
import com.mx.dla.global.bos.BaseBO;

@Service
public class TipoCambioBO extends BaseBO {

	@Autowired
	private CatalogosDAO catalogosDAO;

	@Autowired
	private TipoCambioDAO tipoCambioDAO;

	public List<Integer> obtenerAnnios() {

		List<Integer> annios = new ArrayList<Integer>();
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(new Date());
		int annio = calendar.get(Calendar.YEAR) - 2;

		for (int i = 0; i < 4; i++) {
			annios.add(annio++);
		}

		return annios;
	}

	public List<PaisVentaDTO> obtenerPaises() throws ResultMapException, SQLException, TransaccionException {
		List<PaisVentaDTO> paises = null;

		try {
			paises = catalogosDAO.getPaises();
		} catch (PersistenceException e) {
			throw new TransaccionException("Error al obtener paises." + e);
		} catch (DataAccessException e) {
			throw new TransaccionException("Error al obtener paises." + e);
		}

		return paises;
	}

	public List<TipoCambioDTO> obtenerNombreTipos() throws ResultMapException, SQLException, TransaccionException {

		List<TipoCambioDTO> nombreTipos = new ArrayList<TipoCambioDTO>();
		nombreTipos.add(new TipoCambioDTO());
		try {
			nombreTipos.addAll(tipoCambioDAO.consultaTiposCambio());
		} catch (PersistenceException e) {
			throw new TransaccionException("Error al obtner nombres de tipos." + e);
		} catch (DataAccessException e) {
			throw new TransaccionException("Error al obtner nombres de tipos." + e);
		}

		return nombreTipos;
	}

	public List<MesTiposCTDTO> obtenerMesTipo(Integer annio, PaisVentaDTO pais, List<TipoCambioDTO> nombreTipos)
			throws ResultMapException, SQLException, TransaccionException {

		List<MesTiposCTDTO> mesesTipo = new ArrayList<MesTiposCTDTO>();
		MesTiposCTDTO aux = null;
		MesesAnio ma = null;

		for (int i = 12; i > 0; i--) {
			aux = new MesTiposCTDTO();
			ma = MesesAnio.parse("" + i);
			aux.setNombre(ma.getDesc());
			aux.setTipos(completaMesTipos(i, annio, pais.getIdPais(), nombreTipos));
			mesesTipo.add(aux);
		}

		return mesesTipo;
	}

	public List<TipoCambioPaisDTO> completaMesTipos(Integer mes, Integer annio, Long idPais,
			List<TipoCambioDTO> nombreTipos) throws ResultMapException, SQLException, TransaccionException {

		List<TipoCambioPaisDTO> mesTipos = null;
		Map<Long, TipoCambioPaisDTO> mesTiposM = new HashMap<Long, TipoCambioPaisDTO>();
		TipoCambioPaisDTO tcpDto = null;
		try {

			mesTipos = tipoCambioDAO.obtnerMesTipos("01/" + mes + "/" + annio, idPais);
			Calendar calendar = Calendar.getInstance();
			calendar.set(Calendar.YEAR, annio);
			calendar.set(Calendar.MONTH, mes - 1);
			calendar.set(Calendar.DAY_OF_MONTH, 1);

			if (mesTipos != null) {

				for (TipoCambioPaisDTO mt : mesTipos) {
					mesTiposM.put(mt.getIdTipoCambio(), mt);
				}
			}

			mesTipos = new ArrayList<TipoCambioPaisDTO>();

			for (TipoCambioDTO tc : nombreTipos) {

				if (tc.getDescripcion() != null) {
					if (mesTiposM.get(tc.getIdTipoCambio()) != null) {
						tcpDto = mesTiposM.get(tc.getIdTipoCambio());
						tcpDto.setRecuperado(true);
						tcpDto.setValor(numberFormatter(tcpDto.getValor()));
						mesTipos.add(mesTiposM.get(tc.getIdTipoCambio()));
					} else {
						tcpDto = new TipoCambioPaisDTO();
						tcpDto.setIdPais(idPais);
						tcpDto.setIdTipoCambio(tc.getIdTipoCambio());
						tcpDto.setMes(calendar.getTime());
						tcpDto.setRecuperado(false);
						mesTipos.add(tcpDto);
					}
				}
			}

		} catch (PersistenceException e) {
			throw new TransaccionException("Error al obtener los meses por tipo." + e);
		} catch (DataAccessException e) {
			throw new TransaccionException("Error al obtener los meses por tipo." + e);
		}

		return mesTipos;
	}

	private String numberFormatter(String numberS) {
		NumberFormat formatter = new DecimalFormat("#0.000000");
		String numberD = "";
		try {
			numberD = formatter.format(Double.parseDouble(numberS));
		} catch (NumberFormatException nfe) {
			numberD = numberS;
		}
		return numberD;
	}

	@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
	public boolean guardarCambios(List<MesTiposCTDTO> mesesTipos)
			throws ResultMapException, SQLException, TransaccionException {

		boolean respuesta = false;

		try {

			if (mesesTipos != null) {
				for (MesTiposCTDTO mt : mesesTipos) {

					logger.info("mes : [{}]", mt.getNombre());

					for (TipoCambioPaisDTO tcp : mt.getTipos()) {

						if (tcp.getRecuperado()) {
							tipoCambioDAO.actualizaTipoCambio(tcp);
						} else {
							if (tcp.getValor() != null)
								tipoCambioDAO.creaTipoCambio(tcp);
						}
					}

				}

				respuesta = true;
			}

		} catch (PersistenceException e) {
			throw new TransaccionException("Error al actualizar los valores." + e);
		} catch (DataAccessException e) {
			throw new TransaccionException("Error al actualizar los valores." + e);
		}

		return respuesta;
	}

}