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

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

import com.mx.dla.dda.catalogos.daos.CatalogosDAO;
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.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.dda.reporte.pago.dtos.ReporteRowDTO;
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.debug("[{}]",info);
			}
			
		}catch(Exception ex) {
			logger.error("Error [{}] : ", ex);
			logger.debug("Error [{}] : ", ex);
		}
	}
	
	
	public void obtenInfoReporteMapeo(Long idContratro, Date fI, Date fF, Long idEstudio) {
		try{
			String[] llaves = obtenLlaves(fI, fF);
			List<ReportePagoDTO> infos = obtenInfoReportePago(idContratro, fI, fF, llaves, idEstudio);//reportePagoDAO.obtenerMapeoReportePagoTitulos(null, new Date(), new Date());
			
			logger.debug("-----------------------------------------------------------------");
			
			for(ReportePagoDTO info : infos) {
				logger.debug("[{}] -- [{}] -- total: " + info.getTotal() ,info.getIdContrato(), info.getNumeroContrato());
				
				for(ReportePagoViewDTO rp: info.getDetalleTitulos()){
					logger.debug("[{}]  -- [{}]", rp.getIdTituloCntorig(), rp.getNombreEstandar());
					logger.debug("[{}]", rp.getDetalleCompleto());
					
//					for(DetalleViewDTO wi : rp.getDetalle()){
//						logger.debug("[{}]", wi);
//					}
				}
			}
			
		}catch(Exception ex) {
			logger.error("Error [{}] : ", ex);
			logger.debug("Error [{}] : ", ex);
		}
	}
	
	
	
	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.debug("meses : [{}]", meses);
		
		for(int i = 0; i < llaves.length; i++) {
			llaves[i] = (mesInicio++) + " - " + annioInicio ;
			logger.debug("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.debug("[{}] -- [{}]", 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.debug("[{}] -- [{}]", rpv.getIdTituloCntorig(), rpv.getNombreEstandar());
						rpv.setDetalleCompleto( obtenDetalleCompleto(rpv.getDetalle(), llaves ));
						rpv.setDetalle(null);
					}
					
					infoCompleta.add(info);
					esPrimero = true;
				}
				
			}
			
			
			
		}catch(Exception ex) {
			logger.error("Error [{}] : ", ex);
			logger.debug("Error [{}] : ", ex);
		}
		
		return infoCompleta;
		
	}
	
	
	public Map<String, Double> obtenDetalleCompleto(List<DetalleViewDTO> detalles, String[] llaves) {
		Map<String, Double> detalleCompleto = contruyeRenglonMeses(llaves);
		
		logger.debug("[{}] -- [{}]", 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(Exception ex) {
			logger.error("[{}]", ex);
		}
		
		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.debug("parametros : [{}]", parametros);
		
	
		return parametros;
	}
	
	public List<ReporteInterfazContingenciaDTO> obteneReporte( List<String> contratos, Long idEstudio) {
		
		List<ReporteInterfazContingenciaDTO> reporte = new ArrayList<>();
		
		try {
			logger.debug("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.debug("Regresando reporte");
			}
		}catch(Exception ex){
			logger.error("[{}]", ex);
			logger.debug("No regresa reporte reporte");
		}
		return reporte;
	}
	
	public InputStream obtenerReporteEnExcel( String idContrato, Long idEstudio) {
		//System.out.print("Action Excel ...obtenerReporteEnExcel");
		
		byte[] info = null;
		InputStream reporte = null;
		ExcelMapper mapper = excelMapperContext.getExcelMapper("reporteContingencia");
		
		logger.info("{}", mapper);
		
		String[] encabezado = obtenerLlavesReporteExcel();
		List<ReporteCRowDTO> reporteInfo = null;
		//System.out.print("Action Excel ...obtenerEncabezado");
		
		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);
			}
			
			//parametros = obtenerParametrosQuery();
			reporteInfo = reportePagoAlterno.obtenerReporteRowsCExcel( idContrato,  idEstudio);
			//System.out.print("Action Excel ...obtenerReporteRowsC");
			
			logger.info("{}", mapper);
			
			info = excelMapperTransform.transformObjectToExcel(reporteInfo, mapper, ReporteCRowDTO.class);
			reporte = new ByteArrayInputStream(info);
		
		}catch(Exception e){
			logger.error("Error : " + e);
		}
		
		
		return reporte;
	}
	
	

}
