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

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
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.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Component;

import com.mx.dla.dda.contrato.generales.daos.GeneralesDAO;
import com.mx.dla.dda.contrato.generales.dtos.ContratoDTO;
import com.mx.dla.dda.excelMapper.bos.ExcelMapperTransform;
import com.mx.dla.dda.excelMapper.context.ExcelMapperContext;
import com.mx.dla.dda.excelMapper.dtos.ExcelMapper;
import com.mx.dla.dda.excelMapper.exceptions.ExcelMapperException;
import com.mx.dla.dda.reporte.pago.daos.ReportePagoAlternoDAO;
import com.mx.dla.dda.reporte.pago.daos.ReportePagoDAO;
import com.mx.dla.dda.reporte.pago.dtos.DetalleContratoDTO;
import com.mx.dla.dda.reporte.pago.dtos.DetalleViewDTO;
import com.mx.dla.dda.reporte.pago.dtos.ReporteCRowDTO;
import com.mx.dla.dda.reporte.pago.dtos.ReporteInterfazContingenciaDTO;
import com.mx.dla.dda.reporte.pago.dtos.ReportePagoBaseDTO;
import com.mx.dla.dda.reporte.pago.dtos.ReportePagoDTO;
import com.mx.dla.dda.reporte.pago.dtos.ReportePagoViewDTO;
import com.mx.dla.global.bos.BaseBO;

@Component
public class ReporteContingenciaBO extends BaseBO {

	@Autowired
	private ReportePagoDAO reportePagoDAO;

	@Autowired
	private ReportePagoAlternoDAO reportePagoAlterno;

	@Autowired
	private ExcelMapperContext excelMapperContext;

	@Autowired
	protected ExcelMapperTransform excelMapperTransform;

	@Autowired
	private GeneralesDAO generalesDAO;

	public void obtenInfoReporte() {
		try {
			List<ReportePagoBaseDTO> infos = reportePagoDAO.obtenerReportePagoTitulos(24L, new Date(), new Date());

			for (ReportePagoBaseDTO info : infos) {
				logger.info("[{}]", info);
			}

		} catch (PersistenceException e) {
			logger.error("Error. {}", e);
		} catch (DataAccessException e) {
			logger.error("Error. {}", e);
		}
	}

	public void obtenInfoReporteMapeo(Long idContratro, Date fI, Date fF, Long idEstudio) {
		String[] llaves = obtenLlaves(fI, fF);
		List<ReportePagoDTO> infos = obtenInfoReportePago(idContratro, fI, fF, llaves, idEstudio);

		logger.info("-----------------------------------------------------------------");

		for (ReportePagoDTO info : infos) {
			logger.info("[{}] -- [{}] -- total: " + info.getTotal(), info.getIdContrato(), info.getNumeroContrato());

			for (ReportePagoViewDTO rp : info.getDetalleTitulos()) {
				logger.info("[{}]  -- [{}]", rp.getIdTituloCntorig(), rp.getNombreEstandar());
				logger.info("[{}]", rp.getDetalleCompleto());
			}
		}
	}

	public String[] obtenLlaves(Date fechaInicio, Date fechaFin) {

		Calendar cI = Calendar.getInstance();
		Calendar cF = Calendar.getInstance();

		cI.setTime(new Date());
		cF.setTime(new Date());

		cI.set(Calendar.MONTH, cI.get(Calendar.MONTH) - 6);
		cF.set(Calendar.MONTH, cF.get(Calendar.MONTH) + 2);

		fechaInicio = cI.getTime();
		fechaFin = cF.getTime();

		long diferenciaTiempo = fechaFin.getTime() - fechaInicio.getTime();
		long diferenciaDias = diferenciaTiempo / (1000 * 60 * 60 * 24);
		Double meses = Math.floor(diferenciaDias / 30);

		String[] llaves = new String[meses.intValue()];

		Calendar cal = Calendar.getInstance();
		cal.setTime(fechaInicio);

		int mesInicio = cal.get(Calendar.MONTH) + 1, annioInicio = cal.get(Calendar.YEAR);

		logger.info("meses : [{}]", meses);

		for (int i = 0; i < llaves.length; i++) {
			llaves[i] = (mesInicio++) + " - " + annioInicio;
			logger.info("llave : [{}]", llaves[i]);
			if (mesInicio > 12) {
				mesInicio = 1;
				annioInicio++;
			}
		}

		return llaves;
	}

	public List<ReportePagoDTO> obtenInfoReportePago(Long idContrato, Date fechaInicio, Date fechaFin, String[] llaves,
			Long idEstudio) {

		Calendar cI = Calendar.getInstance();
		Calendar cF = Calendar.getInstance();

		cI.setTime(new Date());
		cF.setTime(new Date());

		cI.set(Calendar.MONTH, cI.get(Calendar.MONTH) - 6);
		cF.set(Calendar.MONTH, cF.get(Calendar.MONTH) + 2);

		fechaInicio = cI.getTime();
		fechaFin = cF.getTime();

		List<ReportePagoDTO> infoCompleta = new ArrayList<ReportePagoDTO>();

		try {

			List<ReportePagoDTO> infoReporte = reportePagoDAO.obtenerMapeoReportePagoTitulos(idContrato, fechaInicio,
					fechaFin, idEstudio);

			boolean esPrimero = true;
			Double total = 0.0;

			for (ReportePagoDTO info : infoReporte) {
				logger.info("[{}] -- [{}]", info.getIdContrato(), info.getNumeroContrato());

				if (esPrimero) {
					total = info.getDetalleTitulos().get(0).getDetalle().get(0).getMonto();
					esPrimero = false;
				} else {
					info.setTotal(total);

					for (ReportePagoViewDTO rpv : info.getDetalleTitulos()) {
						logger.info("[{}] -- [{}]", rpv.getIdTituloCntorig(), rpv.getNombreEstandar());
						rpv.setDetalleCompleto(obtenDetalleCompleto(rpv.getDetalle(), llaves));
						rpv.setDetalle(null);
					}

					infoCompleta.add(info);
					esPrimero = true;
				}

			}

		} catch (PersistenceException e) {
			logger.error("Error. {}", e);
		} catch (DataAccessException e) {
			logger.error("Error. {}", e);
		}

		return infoCompleta;

	}

	public Map<String, Double> obtenDetalleCompleto(List<DetalleViewDTO> detalles, String[] llaves) {
		Map<String, Double> detalleCompleto = contruyeRenglonMeses(llaves);

		logger.info("[{}] -- [{}]", llaves, detalleCompleto);

		for (DetalleViewDTO detalle : detalles) {
			Calendar cal = Calendar.getInstance();
			cal.setTime(detalle.getMesPago());
			detalleCompleto.put((cal.get(Calendar.MONTH) + 1) + " - " + cal.get(Calendar.YEAR), detalle.getMonto());
		}

		return detalleCompleto;
	}

	public Map<String, Double> contruyeRenglonMeses(String[] llaves) {

		Map<String, Double> renglon = new HashMap<String, Double>();

		for (String llave : llaves) {
			renglon.put(llave, 0.0);
		}

		return renglon;
	}

	public List<DetalleContratoDTO> obtenerDetalleContratoPorEstudio(Long idEstudio) {

		List<DetalleContratoDTO> detalleContratos = null;

		try {

			detalleContratos = reportePagoDAO.obtenerDetalleContratoPorEstudio(idEstudio);

		} catch (PersistenceException e) {
			logger.error("Error. {}", e);
		} catch (DataAccessException e) {
			logger.error("Error. {}", e);
		}

		return detalleContratos;
	}

	/* Metodos que se usan */

	public String[] obtenerLlaves() {
		String[] llaves = { "Contrato", "Titulo", "id Broadview", "Inicio", "Fin", "Costo", "VU AA", "VU MM" };
		return llaves;
	}

	public String[] obtenerLlavesReporteExcel() {
		String[] llaves = { "CODIGO_SAP", "ordenCompra", "proveedor", "descripción", "codigoDDA", "centroCosto",
				"ContratoDDA", "programID", "valor", "fechainicio", "fechacontabilizacion", "VU AA", "VU MM", " ",
				" " };
		return llaves;
	}

	public String[] obtenerEncabezado() {

		String[] encabezado = obtenerLlaves();

		return encabezado;
	}

	public Map<String, String> obtenerParametrosQuery() {

		Map<String, String> parametros = new HashMap<String, String>();
		Calendar calendar = Calendar.getInstance();

		String cad = "";

		int mes = calendar.get(Calendar.MONTH) + 1;
		int annio = calendar.get(Calendar.YEAR);

		cad = mes < 10 ? "0" : "";

		String fI = "'01-" + cad + mes + "-" + annio + "'";
		String fF = "'01-" + cad + mes + "-" + (annio + 1) + "'";
		String[] llaves = { "M1", "M2", "M3", "M4", "M5", "M6", "M7", "M8", "M9", "M10", "M11", "M12", "M13" };
		String[] valores = new String[llaves.length];

		parametros.put("fechaInicio", fI);
		parametros.put("fechaFin", fF);

		for (int i = 0; i < llaves.length; i++) {

			cad = mes < 10 ? "0" : "";

			valores[i] = "'" + cad + mes + "-" + annio + "'";

			parametros.put(llaves[i], "'" + cad + mes + "-" + annio + "'");

			if (mes == 12) {
				mes = 1;
				annio++;
			} else {
				mes++;
			}
		}

		logger.info("parametros : [{}]", parametros);

		return parametros;
	}

	public List<ReporteInterfazContingenciaDTO> obteneReporte(List<String> contratos, Long idEstudio) {

		List<ReporteInterfazContingenciaDTO> reporte = new ArrayList<>();

		try {
			logger.info("antes de reporte");
			for (String idContrato : contratos) {
				ContratoDTO contrato = generalesDAO.obtenerContrato(Long.parseLong(idContrato));
				if (contrato.getNumeroContrato().endsWith("E") || contrato.getNumeroContrato().endsWith("C")) {
					reporte.addAll(reportePagoAlterno.obtenerReporteRowsEnmienda(idContrato));
				} else {
					reporte.addAll(reportePagoAlterno.obtenerReporteRowsC(idContrato, idEstudio));
				}
				logger.info("Regresando reporte");
			}
		} catch (PersistenceException e) {
			logger.error("Error. {}", e);
		} catch (DataAccessException e) {
			logger.error("Error. {}", e);
		}
		return reporte;
	}

	public InputStream obtenerReporteEnExcel(String idContrato, Long idEstudio) {

		byte[] info = null;
		InputStream reporte = null;
		ExcelMapper mapper = excelMapperContext.getExcelMapper("reporteContingencia");

		logger.info("{}", mapper);

		String[] encabezado = obtenerLlavesReporteExcel();
		List<ReporteCRowDTO> reporteInfo = null;

		try {

			for (int i = 0; i < encabezado.length; i++) {
				String s = String.format(mapper.getRules().get(i).getHeader(), encabezado[i]);
				mapper.getRules().get(i).setHeader(s);
			}
			reporteInfo = reportePagoAlterno.obtenerReporteRowsCExcel(idContrato, idEstudio);

			logger.info("{}", mapper);

			info = excelMapperTransform.transformObjectToExcel(reporteInfo, mapper, ReporteCRowDTO.class);
			reporte = new ByteArrayInputStream(info);

		} catch (PersistenceException e) {
			logger.error("Error. {}", e);
		} catch (DataAccessException e) {
			logger.error("Error. {}", e);
		} catch (ExcelMapperException e) {
			logger.error("Error. {}", e);
		} catch (IOException e) {
			logger.error("Error. {}", e);
		}

		return reporte;
	}

}
