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

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.mx.dla.dda.admin.catalogos.estudios.daos.CatalogoEstudiosDAO;
import com.mx.dla.dda.admin.catalogos.estudios.dtos.CatalogoEstudioDTO;
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.global.bos.BaseBO;

@Service
public class ReporteAmortizacionBO extends BaseBO{

	@Autowired
	private ReporteAmortizacionDAO reporteAmortizacionDAO;
	
	@Autowired
	private CatalogoEstudiosDAO catalogoEstudiosDAO;

	public List<RegistroRubroDTO> obtenListaMontosTotalesContratoPorEstudio(
			Long idEstudio, Long idContrato, String fecha, Long mesesSearch) throws ParseException {

		List<RegistroRubroDTO> totalesPorContrato = new ArrayList<RegistroRubroDTO>();
		List<RegistroMontoDTO> montosContrato = reporteAmortizacionDAO
				.obtenMontosTotalesContrato(idEstudio, fecha, mesesSearch);
		Map<Long, List<RegistroMontoDTO>> contratosMonto  = new HashMap<Long,List<RegistroMontoDTO>>();
		
		for(RegistroMontoDTO monto : montosContrato) {
			if(Objects.isNull(contratosMonto.get(monto.getIdContrato()))) {
				contratosMonto.put(monto.getIdContrato(), new ArrayList<RegistroMontoDTO>());
			}
			contratosMonto.get(monto.getIdContrato()).add(monto);
		}
		
		List<String> meses = getFechasAConsultar(fecha);

		for (Entry<Long, List<RegistroMontoDTO>> contrato : contratosMonto.entrySet()) {
			List<RegistroMontoDTO> montos = contrato.getValue();
			
			List<RegistroMontoDTO> list = obtenMontosMesesVacios(meses);
			
			if (montos != null && !montos.isEmpty()) {
				for(RegistroMontoDTO item : montos)
				    buscaRegistroMontoMes(list, item);
				if(idContrato == null || idContrato < 0 || idContrato.equals(montos.get(0).getIdContrato())) {
					RegistroRubroDTO totalContrato = new RegistroRubroDTO();
					totalContrato.setId(contrato.getKey());
					totalContrato.setDescripcion(montos.get(0).getNumContrato());
					totalContrato.setCosto(montos.get(0).getCosto());
					totalContrato.setMontoMes(list);
					totalContrato.setFechaFin(montos.get(0).getFechaFin());
					totalContrato.setFechainicio(montos.get(0).getFechaInicio());
					totalContrato.setCodigoSAP("-");
					totalContrato.setSistema("DDA");
					totalContrato.setIdBroadview("-");
					totalContrato.setRemanente(new Double(0.0));
					totalesPorContrato.add(totalContrato);
				}
			}

		}

		return totalesPorContrato;
	}
	
	public RegistroRubroDTO obtenMontosTotalesPorEstudio(Long idEstudio,
			String fecha) throws ParseException {

		List<RegistroMontoDTO> montosTotalesEstudio = reporteAmortizacionDAO
				.obtenMontosTotalesEstudio(idEstudio, fecha);
		
		CatalogoEstudioDTO nombreEstudio = catalogoEstudiosDAO.catalogoEstudiosPorId(idEstudio.intValue());
		
		List<String> meses = getFechasAConsultar(fecha);

		List<RegistroMontoDTO> list = obtenMontosMesesVacios(meses);
		
		for(RegistroMontoDTO item : montosTotalesEstudio)
		    buscaRegistroMontoMes(list, item);
				
		RegistroRubroDTO totalesEstudio = new RegistroRubroDTO();
		totalesEstudio.setId(idEstudio);
		totalesEstudio.setDescripcion(nombreEstudio.getDescripcionEstudio());
		totalesEstudio.setMontoMes(list);
		totalesEstudio.setRemanente(new Double(0.0));
		return totalesEstudio;
	}
	
	public RegistroRubroDTO obtenMontosTotalesPorEstudioDLASAP(Long idEstudio,
			String fecha) throws ParseException {

		List<RegistroMontoDTO> montosTotalesEstudio = reporteAmortizacionDAO
				.obtenMontosTotalesEstudio(idEstudio, fecha);
		
		CatalogoEstudioDTO nombreEstudio = catalogoEstudiosDAO.catalogoEstudiosPorId(idEstudio.intValue());
		
		List<String> meses = getFechasAConsultar(fecha);

		List<RegistroMontoDTO> list = obtenMontosMesesVacios(meses);
		
		for(RegistroMontoDTO item : montosTotalesEstudio)
		    buscaRegistroMontoMes(list, item);
				
		RegistroRubroDTO totalesEstudio = new RegistroRubroDTO();
		totalesEstudio.setId(idEstudio);
		totalesEstudio.setDescripcion(nombreEstudio.getDescripcionEstudio());
		totalesEstudio.setMontoMes(list);

		return totalesEstudio;
	}
	
	private void addMontoEstudio(RegistroRubroDTO princ, Map<String, List<RegistroRubroDTO>> totalesPorContratoSAPDLA, 
			int place, Long idEstudio, String fecha, String sistema, Integer month) throws ParseException {
		if (Objects.nonNull(princ)) {
			RegistroRubroDTO ant = obtenMontosTotalesPorEstudio(idEstudio, fecha);
			RegistroRubroDTO sig = obtenMontosTotalesPorEstudio(idEstudio, fecha);
			princ.setSistema(sistema);
			princ.setAcumuladoAnterior(0.0);
			princ.setAcumuladoPosterior(0.0);
			princ.setId(-1L);
			if (Objects.nonNull(ant)) {
				princ.setAcumuladoAnterior(ant.getMontoMes().get(12).getMonto());
			}
			if (Objects.nonNull(sig)) {
				princ.setAcumuladoPosterior(sig.getMontoMes().get(12).getMonto());
			}
			princ.setIdBroadview("-");
			princ.setCodigoSAP("-");
			totalesPorContratoSAPDLA.get(idEstudio.toString()).add(place, princ);
		} else {
			RegistroRubroDTO emptyValue = new RegistroRubroDTO();
			List<String> meses = getFechasAConsultar(fecha);
			emptyValue.setMontoMes(obtenMontosMesesVacios(meses));
			emptyValue.setSistema(sistema);
			emptyValue.setCodigoSAP("-");
			emptyValue.setIdBroadview("-");
			emptyValue.setAcumuladoAnterior(0.0);
			emptyValue.setAcumuladoPosterior(0.0);
			emptyValue.setRemanente(0.0);
			totalesPorContratoSAPDLA.get(idEstudio.toString()).add(emptyValue);
		}
	}
	
	private void addMontoEstudioSAP(RegistroRubroDTO princ, Map<String, List<RegistroRubroDTO>> totalesPorContratoSAPDLA, 
			int place, Long idEstudio, String fecha, String sistema, Integer month) throws ParseException {
		if (Objects.nonNull(princ)) {
			RegistroRubroDTO ant = obtenMontosTotalesPorEstudioSAP(idEstudio, fecha);
			RegistroRubroDTO sig = obtenMontosTotalesPorEstudioSAP(idEstudio, fecha);
			princ.setSistema(sistema);
			princ.setAcumuladoAnterior(0.0);
			princ.setAcumuladoPosterior(0.0);
			princ.setId(-1L);
			if (Objects.nonNull(ant)) {
				princ.setAcumuladoAnterior(ant.getMontoMes().get(12).getMonto());
			}
			if (Objects.nonNull(sig)) {
				princ.setAcumuladoPosterior(sig.getMontoMes().get(12).getMonto());
			}
			princ.setIdBroadview("-");
			princ.setCodigoSAP("-");
			totalesPorContratoSAPDLA.get(idEstudio.toString()).add(place, princ);
		} else {
			RegistroRubroDTO emptyValue = new RegistroRubroDTO();
			List<String> meses = getFechasAConsultar(fecha);
			emptyValue.setMontoMes(obtenMontosMesesVacios(meses));
			emptyValue.setSistema(sistema);
			emptyValue.setCodigoSAP("-");
			emptyValue.setIdBroadview("-");
			emptyValue.setAcumuladoAnterior(0.0);
			emptyValue.setAcumuladoPosterior(0.0);
			emptyValue.setRemanente(0.0);
			totalesPorContratoSAPDLA.get(idEstudio.toString()).add(emptyValue);
		}
	}
	
	public Map<String, List<RegistroRubroDTO>> obtenListaMontosTotalesContratoPorEstudioDLASAP(
			Long idEstudio,Long idContrato, String fecha, Integer year, Integer month) throws ParseException {
		RegistroRubroDTO totalesMontosEstudio = obtenMontosTotalesPorEstudio(idEstudio, fecha);
		RegistroRubroDTO totalesMontosEstudioSAP = obtenMontosTotalesPorEstudioSAP(idEstudio, fecha);
		List<RemanenteDTO> remanentes = reporteAmortizacionDAO.obtenerRemanente(null, null, month + "/" + year);
		List<RemanenteDTO> remanentesSAP = reporteAmortizacionDAO.obtenerRemanenteSAP(null,null, month + "/" + year);
		//for(RegistroRubroDTO total :totalesPorContrato) {
			for(RemanenteDTO remanente : remanentesSAP) {
				if(remanente != null && totalesMontosEstudioSAP.getId().toString().equals(remanente.getDiferenciador())) {
					totalesMontosEstudioSAP.setRemanente(Double.parseDouble(remanente.getRemanente()));
				}
			}
			for(RemanenteDTO remanente : remanentes) {
				if(remanente != null && totalesMontosEstudio.getId().toString().equals(remanente.getDiferenciador())) {
					totalesMontosEstudio.setRemanente(Double.parseDouble(remanente.getRemanente()));
				}
			}
		//}
		Map<String, List<RegistroRubroDTO>> totalesPorContratoSAPDLA = new LinkedHashMap<>();
		totalesPorContratoSAPDLA.put(idEstudio.toString(), new ArrayList<RegistroRubroDTO>());
		addMontoEstudio(totalesMontosEstudio, totalesPorContratoSAPDLA, 0, idEstudio, "01/" + (year - 1), "DDA", month);
		addMontoEstudioSAP(totalesMontosEstudioSAP, totalesPorContratoSAPDLA, 0, idEstudio, "01/" + (year + 1), "SAP", month);
		Map<String, List<RegistroRubroDTO>> totalesPorContratoAnioAnterior = null;
		Map<String, List<RegistroRubroDTO>> totalesPorContratoAnioSiguiente = null;
		totalesPorContratoSAPDLA.putAll(getListResult(idEstudio,idContrato, fecha,month + "/" + year));
		totalesPorContratoAnioAnterior = getListResult(idEstudio,idContrato, "01/" + (year - 1),month + "/" + year);
		totalesPorContratoAnioSiguiente = getListResult(idEstudio,idContrato, "01/" + (year + 1),month + "/" + year);
		for(Entry<String, List<RegistroRubroDTO>> total :totalesPorContratoSAPDLA.entrySet()) {
			if(total.getValue().size() < 2) {
				RegistroRubroDTO emptyValue = new RegistroRubroDTO();
				List<String> meses = getFechasAConsultar(fecha);
				emptyValue.setMontoMes(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());
				total.getValue().add(emptyValue);
			}
			
			for (int i = 0; total.getValue().size() > i; i++) {
				if(!total.getKey().equals(idEstudio.toString())) {
					if(Objects.nonNull(totalesPorContratoAnioAnterior.get(total.getKey())) && totalesPorContratoAnioAnterior.get(total.getKey()).size() > i) {
						if(Objects.nonNull(totalesPorContratoAnioAnterior.get(total.getKey()))) {
							total.getValue().get(i)
							.setAcumuladoAnterior(totalesPorContratoAnioAnterior
									.get(total.getKey()).get(i).getMontoMes().get(12).getMonto());
						} else {
							total.getValue().get(i).setAcumuladoAnterior(0.0);
						}
						if(Objects.nonNull(totalesPorContratoAnioSiguiente.get(total.getKey()))) {
							total.getValue().get(i)
							.setAcumuladoPosterior(totalesPorContratoAnioSiguiente
									.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 :totalesPorContratoSAPDLA.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");
						}
					}
				}
			}
		}
		return totalesPorContratoSAPDLA;
	}
	
	public Map<String, List<RegistroRubroDTO>> getListResult(Long idEstudio,Long idContrato, String fecha, String fechaRem) throws ParseException {
		List<RegistroRubroDTO> totalesPorContrato = obtenListaMontosTotalesContratoPorEstudio(idEstudio,idContrato, fecha, 11L);
		List<RegistroRubroDTO> totalesPorContratoSAP = obtenListaMontosTotalesContratoPorEstudioSAP(idEstudio,idContrato, fecha, 11L);
		List<RemanenteDTO> remanentes = reporteAmortizacionDAO.obtenerRemanente(idEstudio, null, fechaRem);
		List<RemanenteDTO> remanentesSAP = reporteAmortizacionDAO.obtenerRemanenteSAP(idEstudio,null, fechaRem);
		Map<String, List<RegistroRubroDTO>> totalesPorContratoSAPDLA = new LinkedHashMap<>();
		totalesPorContrato.addAll(totalesPorContratoSAP);
		for(RegistroRubroDTO total :totalesPorContrato) {
			if(!totalesPorContratoSAPDLA.containsKey(total.getDescripcion())) {
				totalesPorContratoSAPDLA.put(total.getDescripcion(), new ArrayList<RegistroRubroDTO>());
			}
			if(total.getSistema().equals("SAP")) {
				for(RemanenteDTO remanente : remanentesSAP) {
					if(remanente != null && total.getDescripcion().equals(remanente.getDiferenciador())) {
						total.setRemanente(Double.parseDouble(remanente.getRemanente()));
					}
				}
			} else {
				for(RemanenteDTO remanente : remanentes) {
					if(remanente != null && total.getDescripcion().equals(remanente.getDiferenciador())) {
						total.setRemanente(Double.parseDouble(remanente.getRemanente()));
					}
				}
			}
			totalesPorContratoSAPDLA.get(total.getDescripcion()).add(total);
		}
		
		return totalesPorContratoSAPDLA;
	}
	
	public List<String> getFechasAConsultar(String fechaIni)
			throws ParseException {

		List<String> fechas = new ArrayList<String>();
		DateFormat formato = new SimpleDateFormat("MM/yyyy");

		Date date = formato.parse(fechaIni);
		Calendar cal = Calendar.getInstance();
		cal.setTime(date);

		String fecha = formato.format(cal.getTime());

		fechas.add(fecha);

		for (int i = 1; i < 12; i++) {

			cal.add(Calendar.MONTH, 1);

			fecha = formato.format(cal.getTime());
			fechas.add(fecha);
		}

		return fechas;
	}
	
	public List<RegistroMontoDTO> obtenMontosMesesVacios(List<String> meses)
			throws ParseException {

		List<RegistroMontoDTO> response = new ArrayList<RegistroMontoDTO>();
		DateFormat formato = new SimpleDateFormat("MM/yyyy");

		for (String mes : meses) {

			RegistroMontoDTO newItem = new RegistroMontoDTO();
			Date fecha = formato.parse(mes);

			newItem.setFecha(fecha);
			newItem.setMonto(0.0);
			response.add(newItem);

		}
		
		RegistroMontoDTO newItem = new RegistroMontoDTO();
		newItem.setFecha(null);
		newItem.setMonto(0.0);
		response.add(newItem);

		return response;
	}
	
	private void buscaRegistroMontoMes(List<RegistroMontoDTO> montos,
			RegistroMontoDTO actualizaMonto) throws ParseException {

		Double parcial = 0.0;
		RegistroMontoDTO total = null;

		for (RegistroMontoDTO monto : montos)
		{				
			if (monto != null)
				if (monto.getFecha() != null) {
					if (monto.getFecha().equals(actualizaMonto.getFecha())) {
						parcial = actualizaMonto.getMonto();
						monto.setMonto(parcial);
					}
				} else {
					total = monto;
				}
		}

		if (total != null)
			total.setMonto(truncateTo(total.getMonto() + parcial, 2));

	}
	
	static double truncateTo( double unroundedNumber, int decimalPlaces ){
	    int truncatedNumberInt = (int)( unroundedNumber * Math.pow( 10, decimalPlaces ) );
	    double truncatedNumber = (double)( truncatedNumberInt / Math.pow( 10, decimalPlaces ) );
	    return truncatedNumber;
	}

	public List<RegistroRubroDTO> obtenListaMontoTitulosPorContrato(
			Long idContrato, String fecha) throws ParseException {

		List<RegistroMontoDTO> montosTitulosContrato = reporteAmortizacionDAO
				.obtenMontosTitulosContrato(idContrato, fecha);

		List<RegistroRubroDTO> montosTitulos = new ArrayList<RegistroRubroDTO>();
		montosTitulos = separaMensualmente(montosTitulosContrato, fecha);

		return montosTitulos;

	}	
	
	private List<RegistroRubroDTO> separaMensualmente(
			List<RegistroMontoDTO> titulosMontos, String fecha)
			throws ParseException {

		List<RegistroRubroDTO> montoTitulos = new ArrayList<>();
		Map<String, List<RegistroMontoDTO>> map = new HashMap<>();
		List<String> meses = getFechasAConsultar(fecha);

		for (RegistroMontoDTO item : titulosMontos) 
		{
			String season = Objects.isNull(item.getTemporada()) ? "" : " Season " + 
					StringUtils.leftPad(item.getTemporada(), 2, "0") ;
			List<RegistroMontoDTO> list = map.get(item.getDescripcion() + season);
			if (list == null) {
				
				list = obtenMontosMesesVacios(meses);
				map.put(item.getDescripcion() + season, list);

				RegistroRubroDTO montoTituloRegistro = new RegistroRubroDTO();
				montoTituloRegistro.setTemporada(item.getTemporada());
				montoTituloRegistro.setDescripcion(item.getDescripcion() + season);
				montoTituloRegistro.setNombreUnico(item.getDescripcion());
				montoTituloRegistro.setCosto(item.getCosto());
				montoTituloRegistro.setMontoMes(list);
				montoTituloRegistro.setId(item.getIdContrato());
				montoTituloRegistro.setSistema(item.getSistema());
				montoTituloRegistro.setCodigoSAP(item.getIdSap());
				montoTituloRegistro.setIdBroadview(item.getIdBroadView());
				
				montoTitulos.add(montoTituloRegistro);
				logger.debug("id cto:" + item.getId() + " no tit:" + montoTitulos.size());
			}

			buscaRegistroMontoMes(list, item);			
		}

		return montoTitulos;
	}
	
	//Amortizacion
	public List<RegistroRubroDTO> obtenListaMontosTotalesContratoPorEstudioSAP(Long idEstudio, Long idContrato, String fecha, Long mesesSearch) throws ParseException {

		List<RegistroRubroDTO> totalesPorContrato = new ArrayList<RegistroRubroDTO>();
		List<RegistroMontoDTO> montosContrato = reporteAmortizacionDAO.obtenMontosTotalesContratoSAP(idEstudio, fecha, mesesSearch);
		
		Map<Long, List<RegistroMontoDTO>> contratosMonto  = new HashMap<Long,List<RegistroMontoDTO>>();
		
		for(RegistroMontoDTO monto : montosContrato) {
			if(Objects.isNull(contratosMonto.get(monto.getIdContrato()))) {
				contratosMonto.put(monto.getIdContrato(), new ArrayList<RegistroMontoDTO>());
			}
			contratosMonto.get(monto.getIdContrato()).add(monto);
		}
		
		List<String> meses = getFechasAConsultar(fecha);

		for (Entry<Long, List<RegistroMontoDTO>> contrato : contratosMonto.entrySet()) {

			List<RegistroMontoDTO> montos = contrato.getValue();
			
			List<RegistroMontoDTO> list = obtenMontosMesesVacios(meses);

			if (montos != null && !montos.isEmpty()) {
				
				for(RegistroMontoDTO item : montos)
				    buscaRegistroMontoMes(list, item);
				if(idContrato == null || idContrato < 0 || idContrato.equals(montos.get(0).getIdContrato())) {
					RegistroRubroDTO totalContrato = new RegistroRubroDTO();
					totalContrato.setId(montos.get(0).getIdContrato());
					totalContrato.setDescripcion(montos.get(0).getNumContrato());
					totalContrato.setCosto(montos.get(0).getCosto());
					totalContrato.setMontoMes(list);
					totalContrato.setFechaFin(montos.get(0).getFechaFin());
					totalContrato.setFechainicio(montos.get(0).getFechaInicio());
					totalContrato.setCodigoSAP("-");
					totalContrato.setSistema("SAP");
					totalContrato.setIdBroadview("-");
					totalContrato.setRemanente(new Double(0.0));
					totalesPorContrato.add(totalContrato);
				}
			}

		}

		return totalesPorContrato;
	}
	
	public RegistroRubroDTO obtenMontosTotalesPorEstudioSAP(Long idEstudio, String fecha) throws ParseException {

		List<RegistroMontoDTO> montosTotalesEstudio = reporteAmortizacionDAO.obtenMontosTotalesEstudioSAP(idEstudio, fecha);
		
		CatalogoEstudioDTO nombreEstudio = catalogoEstudiosDAO.catalogoEstudiosPorId(idEstudio.intValue());
		
		List<String> meses = getFechasAConsultar(fecha);

		List<RegistroMontoDTO> list = obtenMontosMesesVacios(meses);
		
		for(RegistroMontoDTO item : montosTotalesEstudio)
		    buscaRegistroMontoMes(list, item);
				
		RegistroRubroDTO totalesEstudio = new RegistroRubroDTO();
		totalesEstudio.setId(idEstudio);
		totalesEstudio.setDescripcion(nombreEstudio.getDescripcionEstudio());
		totalesEstudio.setMontoMes(list);
		totalesEstudio.setRemanente(new Double(0.0));
		return totalesEstudio;
	}

	public List<RegistroRubroDTO> obtenListaMontoTitulosPorContratoSAP(Long idContrato, String fecha) throws ParseException {

		List<RegistroMontoDTO> montosTitulosContrato = reporteAmortizacionDAO.obtenMontosTitulosContratoSAP(idContrato, fecha);

		List<RegistroRubroDTO> montosTitulos = new ArrayList<RegistroRubroDTO>();
		montosTitulos = separaMensualmente(montosTitulosContrato, fecha);

		return montosTitulos;

	}	

}