package com.mx.dla.dda.reporte.amortizacion.actions;

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.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;

import org.apache.commons.collections.map.HashedMap;
import org.apache.ibatis.executor.result.ResultMapException;
import org.springframework.beans.factory.annotation.Autowired;

import com.mx.dla.dda.admin.catalogos.estudios.dtos.CatalogoContratoDTO;
import com.mx.dla.dda.catalogos.bos.CatalogosBO;
import com.mx.dla.dda.catalogos.dtos.EstudioDTO;
import com.mx.dla.dda.contrato.common.actions.BaseContratoAction;
import com.mx.dla.dda.contrato.generales.bos.PoblarGeneralesBO;
import com.mx.dla.dda.contrato.transaccion.exceptions.dtos.TransaccionException;
import com.mx.dla.dda.reporte.amortizacion.bos.ReporteAmortizacionBO;
import com.mx.dla.dda.reporte.amortizacion.daos.ReporteAmortizacionDAO;
import com.mx.dla.dda.reporte.amortizacion.dtos.RegistroMontoDTO;
import com.mx.dla.dda.reporte.amortizacion.dtos.RegistroRubroDTO;
import com.mx.dla.dda.reporte.amortizacion.dtos.RemanenteDTO;
import com.mx.dla.dda.reporte.amortizacion.dtos.SortByNumeroContrato;
import com.opensymphony.xwork2.Action;

public class ReporteAmortizacionAction extends BaseContratoAction {

	private static final long serialVersionUID = -3317004330758868390L;

	@Autowired
	private ReporteAmortizacionBO reporteAmortizacionBO;

	@Autowired
	private CatalogosBO catalogosBO;

	private Long idEstudio;
	private Long idContrato;
	private String fecha;
	private List<String> fechasRango;
	private List<EstudioDTO> estudios;
	private List<CatalogoContratoDTO> contratos;

	private RegistroRubroDTO totalesMontosEstudio;
	private List<RegistroRubroDTO> totalesMontosContratos;
	private Map<String, List<RegistroRubroDTO>> totalesMontosContratosSAPDLA;
	private List<RegistroRubroDTO> montosTitulos;
	private Map<String, List<RegistroRubroDTO>> totalesMontosTitulosSAPDLA;
	private Integer year;

	@Autowired
	private PoblarGeneralesBO poblarGeneralesBO;

	@Autowired
	private ReporteAmortizacionDAO reporteAmortizacionDAO;

	public String obtenerContratos() throws TransaccionException {
		try {
			contratos = catalogosBO.getContratosByEstudio(idEstudio);
		} catch (ResultMapException e) {
			logger.error("Error. {}", e);
			throw new TransaccionException("Ocurrio un error", e);
		} catch (SQLException e) {
			logger.error("Error. {}", e);
			throw new TransaccionException("Ocurrio un error", e);
		} catch (TransaccionException e) {
			logger.error("Error. {}", e);
			throw new TransaccionException("Ocurrio un error", e);
		}
		return Action.SUCCESS;
	}

	public String obtenerEstudios() throws TransaccionException {
		try {
			estudios = catalogosBO.obtenListaEstudios();
		} catch (ResultMapException e) {
			logger.error("Error en [" + this.getClass() + "]", e);
			throw new TransaccionException("Ocurrio un error", e);
		} catch (SQLException e) {
			logger.error("Error en [" + this.getClass() + "]", e);
			throw new TransaccionException("Ocurrio un error", e);
		} catch (TransaccionException e) {
			logger.error("Error en [" + this.getClass() + "]", e);
			throw new TransaccionException("Ocurrio un error", e);
		}
		return Action.SUCCESS;
	}

	public String cargaInicialReporteAmortizacionSAPDLA() {
		try {

			DateFormat entrada = new SimpleDateFormat("MM/yyyy");
			DateFormat salida = new SimpleDateFormat("MMM yyyy", new Locale("es", "ES"));
			year = Integer.parseInt(fecha.substring(3));
			Integer month = Integer.parseInt(fecha.substring(0, 2));
			fecha = "01/" + year;
			if (idEstudio != null && idEstudio > 0) {
				totalesMontosContratosSAPDLA = reporteAmortizacionBO
						.obtenListaMontosTotalesContratoPorEstudioDLASAP(idEstudio, idContrato, fecha, year, month);
			} else {
				estudios = catalogosBO.obtenListaEstudios();
				totalesMontosContratosSAPDLA = new HashedMap();
				for (EstudioDTO estudio : estudios) {
					totalesMontosContratosSAPDLA
							.putAll(reporteAmortizacionBO.obtenListaMontosTotalesContratoPorEstudioDLASAP(
									estudio.getIdEstudio(), idContrato, fecha, year, month));
				}
			}

			List<String> fechas = reporteAmortizacionBO.getFechasAConsultar(fecha);
			fechasRango = new ArrayList<String>();

			for (String fecha : fechas) {
				Date date = entrada.parse(fecha);
				fecha = salida.format(date).toUpperCase();
				fechasRango.add(fecha);
			}

		} catch (ResultMapException e) {
			logger.error("Error en [" + this.getClass() + "]", e);
			addActionError("Ha ocurrido un error");
		} catch (SQLException e) {
			logger.error("Error en [" + this.getClass() + "]", e);
			addActionError("Ha ocurrido un error");
		} catch (TransaccionException e) {
			logger.error("Error en [" + this.getClass() + "]", e);
			addActionError("Ha ocurrido un error");
		} catch (ParseException e) {
			logger.error("Error en [" + this.getClass() + "]", e);
			addActionError("Ha ocurrido un error");
		}
		return Action.SUCCESS;
	}

	public String cargaInicialReporteAmortizacion() {

		try {

			DateFormat entrada = new SimpleDateFormat("MM/yyyy");
			DateFormat salida = new SimpleDateFormat("MMM yyyy", new Locale("es", "ES"));

			totalesMontosEstudio = reporteAmortizacionBO.obtenMontosTotalesPorEstudio(idEstudio, fecha);
			totalesMontosContratos = reporteAmortizacionBO.obtenListaMontosTotalesContratoPorEstudio(idEstudio, null,
					fecha, 12L);

			List<String> fechas = reporteAmortizacionBO.getFechasAConsultar(fecha);
			fechasRango = new ArrayList<String>();

			for (String fecha : fechas) {
				Date date = entrada.parse(fecha);
				fecha = salida.format(date).toUpperCase();
				fechasRango.add(fecha);
			}

		} catch (ResultMapException e) {
			logger.error("Error en [" + this.getClass() + "]", e);
			addActionError("Ha ocurrido un error");
		} catch (ParseException e) {
			logger.error("Error en [" + this.getClass() + "]", e);
			addActionError("Ha ocurrido un error");
		}

		return Action.SUCCESS;
	}

	public String cargaMontoTitulosPorContrato() {

		logger.debug("ID!!! idContrato: " + idContrato + "::: fecha: " + fecha);

		try {

			montosTitulos = reporteAmortizacionBO.obtenListaMontoTitulosPorContrato(idContrato, fecha);

			logger.debug("montosTitulos !!!!: " + montosTitulos);

		} catch (ResultMapException e) {
			logger.error("Error en [" + this.getClass() + "]", e);
			addActionError("Ha ocurrido un error");
		} catch (ParseException e) {
			logger.error("Error en [" + this.getClass() + "]", e);
			addActionError("Ha ocurrido un error");
		}

		return Action.SUCCESS;
	}

	public String cargaInicialReporteAmortizacionSAP() {

		try {

			DateFormat entrada = new SimpleDateFormat("MM/yyyy");
			DateFormat salida = new SimpleDateFormat("MMM yyyy", new Locale("es", "ES"));

			totalesMontosEstudio = reporteAmortizacionBO.obtenMontosTotalesPorEstudioSAP(idEstudio, fecha);
			totalesMontosContratos = reporteAmortizacionBO.obtenListaMontosTotalesContratoPorEstudioSAP(idEstudio, null,
					fecha, 12L);

			List<String> fechas = reporteAmortizacionBO.getFechasAConsultar(fecha);
			fechasRango = new ArrayList<String>();

			for (String fecha : fechas) {
				Date date = entrada.parse(fecha);
				fecha = salida.format(date).toUpperCase();
				fechasRango.add(fecha);
			}

		} catch (ResultMapException e) {
			logger.error("Error en [" + this.getClass() + "]", e);
			addActionError("Ha ocurrido un error");
		} catch (ParseException e) {
			logger.error("Error en [" + this.getClass() + "]", e);
			addActionError("Ha ocurrido un error");
		}

		return Action.SUCCESS;
	}

	public String cargaMontoTitulosPorContratoSAP() {
		try {

			montosTitulos = reporteAmortizacionBO.obtenListaMontoTitulosPorContratoSAP(idContrato, fecha);

		} catch (ResultMapException e) {
			logger.error("Error en [" + this.getClass() + "]", e);
			addActionError("Ha ocurrido un error");
		} catch (ParseException e) {
			logger.error("Error en [" + this.getClass() + "]", e);
			addActionError("Ha ocurrido un error");
		}

		return Action.SUCCESS;
	}

	public String cargaMontoTitulosPorContratoSAPDLA() {
		try {
			year = Integer.parseInt(fecha.substring(3));
			Integer month = Integer.parseInt(fecha.substring(0, 2));
			fecha = "01/" + year;
			totalesMontosTitulosSAPDLA = getListByYear(fecha, month + "/" + year);
			Map<String, List<RegistroRubroDTO>> totalesAnioPasado = getListByYear("01/" + (year - 1),
					month + "/" + year);
			Map<String, List<RegistroRubroDTO>> totalesAnioSiguiente = getListByYear("01/" + (year + 1),
					month + "/" + year);
			for (Entry<String, List<RegistroRubroDTO>> total : totalesMontosTitulosSAPDLA.entrySet()) {
				if (total.getValue().size() < 2) {
					RegistroRubroDTO emptyValue = new RegistroRubroDTO();
					List<String> meses = reporteAmortizacionBO.getFechasAConsultar(fecha);
					emptyValue.setMontoMes(reporteAmortizacionBO.obtenMontosMesesVacios(meses));
					emptyValue.setSistema(total.getValue().get(0).getSistema().equals("DDA") ? "SAP" : "DDA");
					emptyValue.setFechainicio(total.getValue().get(0).getFechainicio());
					emptyValue.setFechaFin(total.getValue().get(0).getFechaFin());
					emptyValue.setCodigoSAP(total.getValue().get(0).getCodigoSAP());
					emptyValue.setIdBroadview(total.getValue().get(0).getIdBroadview());
					emptyValue.setRemanente(0.0);
					total.getValue().add(emptyValue);
				}
				for (int i = 0; total.getValue().size() > i; i++) {
					if (Objects.nonNull(totalesAnioPasado.get(total.getKey()))
							&& totalesAnioPasado.get(total.getKey()).size() > i) {
						if (Objects.nonNull(totalesAnioSiguiente.get(total.getKey()))) {
							total.getValue().get(i).setAcumuladoAnterior(
									totalesAnioPasado.get(total.getKey()).get(i).getMontoMes().get(12).getMonto());
						} else {
							total.getValue().get(i).setAcumuladoAnterior(0.0);
						}
						if (Objects.nonNull(totalesAnioSiguiente.get(total.getKey()))) {
							total.getValue().get(i).setAcumuladoPosterior(
									totalesAnioSiguiente.get(total.getKey()).get(i).getMontoMes().get(12).getMonto());
						} else {
							total.getValue().get(i).setAcumuladoPosterior(0.0);
						}
					} else {
						total.getValue().get(i).setAcumuladoAnterior(0.0);
						total.getValue().get(i).setAcumuladoPosterior(0.0);
					}
				}
			}
			for (Entry<String, List<RegistroRubroDTO>> total : totalesMontosTitulosSAPDLA.entrySet()) {
				for (RegistroMontoDTO mesDDA : total.getValue().get(0).getMontoMes()) {
					for (RegistroMontoDTO mesSAP : total.getValue().get(1).getMontoMes()) {
						if (mesDDA.getFecha() != null && mesDDA.getFecha().equals(mesSAP.getFecha())) {
							if (mesDDA.getMonto().equals(mesSAP.getMonto())) {
								mesDDA.setColor("right");
								mesSAP.setColor("right");
							} else {
								mesDDA.setColor("danger");
								mesSAP.setColor("danger");
							}
						}
					}
				}
			}
		} catch (ResultMapException e) {
			logger.error("Error en [" + this.getClass() + "]", e);
			addActionError("Ha ocurrido un error");
		} catch (ParseException e) {
			logger.error("Error en [" + this.getClass() + "]", e);
			addActionError("Ha ocurrido un error");
		}

		return Action.SUCCESS;
	}

	public Map<String, List<RegistroRubroDTO>> getListByYear(String date, String dateRM) throws ParseException {
		montosTitulos = reporteAmortizacionBO.obtenListaMontoTitulosPorContrato(idContrato, date);

		montosTitulos.addAll(reporteAmortizacionBO.obtenListaMontoTitulosPorContratoSAP(idContrato, date));
		List<RemanenteDTO> remanentes = reporteAmortizacionDAO.obtenerRemanente(idEstudio, idContrato.toString(),
				dateRM);
		List<RemanenteDTO> remanentesSAP = reporteAmortizacionDAO.obtenerRemanenteSAP(idEstudio, idContrato.toString(),
				dateRM);
		montosTitulos.sort(new SortByNumeroContrato());
		Map<String, List<RegistroRubroDTO>> totalesMontosTitulos = new LinkedHashMap<String, List<RegistroRubroDTO>>();
		for (RegistroRubroDTO total : montosTitulos) {
			if (!totalesMontosTitulos.containsKey(total.getDescripcion())) {
				totalesMontosTitulos.put(total.getDescripcion(), new ArrayList<RegistroRubroDTO>());
			}
			if (total.getSistema().equals("SAP")) {
				for (RemanenteDTO remanente : remanentesSAP) {
					if (remanente != null && total.getId().toString().equals(remanente.getDiferenciador())) {
						total.setRemanente(Double.parseDouble(remanente.getRemanente()));
					}
				}
			} else {
				for (RemanenteDTO remanente : remanentes) {
					if (remanente != null && total.getId().toString().equals(remanente.getDiferenciador())) {
						total.setRemanente(Double.parseDouble(remanente.getRemanente()));
					}
				}
			}
			totalesMontosTitulos.get(total.getDescripcion()).add(total);
		}

		return totalesMontosTitulos;
	}

	public Long getIdEstudio() {
		return idEstudio;
	}

	public void setIdEstudio(Long idEstudio) {
		this.idEstudio = idEstudio;
	}

	public Integer getYear() {
		return year;
	}

	public void setYear(Integer year) {
		this.year = year;
	}

	public Long getIdContrato() {
		return idContrato;
	}

	public void setIdContrato(Long idContrato) {
		this.idContrato = idContrato;
	}

	public RegistroRubroDTO getTotalesMontosEstudio() {
		return totalesMontosEstudio;
	}

	public void setTotalesMontosEstudio(RegistroRubroDTO totalesMontosEstudio) {
		this.totalesMontosEstudio = totalesMontosEstudio;
	}

	public void setTotalesMontosContratosSAPDLA(Map<String, List<RegistroRubroDTO>> totalesMontosContratosSAPDLA) {
		this.totalesMontosContratosSAPDLA = totalesMontosContratosSAPDLA;
	}

	public Map<String, List<RegistroRubroDTO>> getTotalesMontosContratosSAPDLA() {
		return totalesMontosContratosSAPDLA;
	}

	public void setTotalesMontosTitulosSAPDLA(Map<String, List<RegistroRubroDTO>> totalesMontosTitulosSAPDLA) {
		this.totalesMontosTitulosSAPDLA = totalesMontosTitulosSAPDLA;
	}

	public Map<String, List<RegistroRubroDTO>> getTotalesMontosTitulosSAPDLA() {
		return totalesMontosTitulosSAPDLA;
	}

	public List<RegistroRubroDTO> getTotalesMontosContratos() {
		return totalesMontosContratos;
	}

	public void setTotalesMontosContratos(List<RegistroRubroDTO> totalesMontosContratos) {
		this.totalesMontosContratos = totalesMontosContratos;
	}

	public List<RegistroRubroDTO> getMontosTitulos() {
		return montosTitulos;
	}

	public void setMontosTitulos(List<RegistroRubroDTO> montosTitulos) {
		this.montosTitulos = montosTitulos;
	}

	public String getFecha() {
		return fecha;
	}

	public void setFecha(String fecha) {
		this.fecha = fecha;
	}

	public List<EstudioDTO> getListaEstudios() {
		try {
			return poblarGeneralesBO.obtenListaEstudios();
		} catch (ResultMapException e) {
			logger.error("Error. {}", e);
			return null;
		} catch (SQLException e) {
			logger.error("Error. {}", e);
			return null;
		} catch (TransaccionException e) {
			logger.error("Error. {}", e);
			return null;
		}
	}

	public List<String> getFechasRango() {
		return fechasRango;
	}

	public void setFechasRango(List<String> fechasRango) {
		this.fechasRango = fechasRango;
	}

	public List<EstudioDTO> getEstudios() {
		return estudios;
	}

	public void setEstudios(List<EstudioDTO> estudios) {
		this.estudios = estudios;
	}

	public List<CatalogoContratoDTO> getContratos() {
		return contratos;
	}

	public void setContratos(List<CatalogoContratoDTO> contratos) {
		this.contratos = contratos;
	}

}
