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.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.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 ReportePagoBO extends BaseBO{
	
	@Autowired
	private ReportePagoDAO reportePagoDAO;
	
	@Autowired
	private ReportePagoAlternoDAO reportePagoAlterno;
	
	@Autowired
	private ExcelMapperContext excelMapperContext;
	
	@Autowired
	protected ExcelMapperTransform excelMapperTransform;
	
	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) {
		try{
			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());
				}
			}
			
		} catch (PersistenceException e) {
			logger.error("Error. {}", e);
		} catch (DataAccessException e) {
			logger.error("Error. {}", e);
		}
	}
	
	
	
	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.obtenerDetalleContratoPorEstudioSAP(idEstudio);
			
		} catch (PersistenceException e) {
			logger.error("Error. {}", e);
		} catch (DataAccessException e) {
			logger.error("Error. {}", e);
		}
		
		return detalleContratos;
	}
	
	public void pruebaDAO() {
		
		
		Map<String, String> parametros = new HashMap<String, String>();
		
		parametros.put("fechaInicio", "'01-12-2015'");
		parametros.put("fechaFin", "'01-12-2016'");
		parametros.put("M1", "'12-2015'");
		parametros.put("M2", "'01-2016'");
		parametros.put("M3", "'02-2016'");
		parametros.put("M4", "'03-2016'");
		parametros.put("M5", "'04-2016'");
		parametros.put("M6", "'05-2016'");
		parametros.put("M7", "'06-2016'");
		parametros.put("M8", "'07-2016'");
		parametros.put("M9", "'08-2016'");
		parametros.put("M10", "'09-2016'");
		parametros.put("M11", "'10-2016'");
		parametros.put("M12", "'11-2016'");
		parametros.put("M13", "'12-2016'");
		List<ReporteRowDTO> listaReporteRow = null;
		try {
			
			listaReporteRow = reportePagoAlterno.obtenerReporteRows(20L, 108L, parametros);
			
			if(listaReporteRow != null){
				for(ReporteRowDTO detalle:listaReporteRow) {
					logger.info("[{}]", detalle);
				}
			}
		} catch (PersistenceException e) {
			logger.error("Error. {}", e);
		} catch (DataAccessException e) {
			logger.error("Error. {}", e);
		}
	}
	
	/*Metodos que se usan*/
	
	public String[] obtenerLlaves(){
		String[] llaves = {"Concepto", "M1", "M2", "M3", "M4", "M5", "M6", "M7", "M8", "M9", "M10", "M11", "M12", "M13", "Total"};
		return llaves;
	}
	
	public String[] obtenerEncabezado(Date fechaInicio) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(fechaInicio);
		
		int mes = calendar.get(Calendar.MONTH) + 1;
		int annio = calendar.get(Calendar.YEAR);
		
		String[] encabezado = obtenerLlaves(); 
		String[] meses = {"Ene", "Feb", "Mar", "Abr", "May", "Jun", "Jul", "Ago", "Sep", "Oct", "Nov", "Dic"};
		
		for(int i = 1; i < (encabezado.length - 1); i++){
			
			encabezado[i] =  meses[(mes - 1)] + " - " + annio;
			
			if(mes == 12){
				mes = 1;
				annio++;
			}else {
				mes++;
			}
		}
		
		return encabezado;
	}
	
	public Map<String, String> obtenerParametrosQuery(Date fechaInicio) {
		
		Map<String, String> parametros = new HashMap<String, String>();
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(fechaInicio); 
		
		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<ReporteRowDTO> obteneReporte(Date fechaInicio, Long idContrato, Long idEstudio) {
		
		List<ReporteRowDTO> reporte = null;
		Map<String, String> parametros = obtenerParametrosQuery(fechaInicio);
		
		try {
			
			reporte = reportePagoAlterno.obtenerReporteRows(idContrato, idEstudio, parametros);
			logger.info("Regresando reporte");
		} catch (PersistenceException e) {
			logger.error("Error. {}", e);
		} catch (DataAccessException e) {
			logger.error("Error. {}", e);
		}
		return reporte;
	}
	
	public InputStream obtenerReporteEnExcel(Date fechaInicio, Long idContrato, Long idEstudio) {
		
		byte[] info = null;
		InputStream reporte = null;
		ExcelMapper mapper = excelMapperContext.getExcelMapper("reportePago");
		
		logger.info("{}", mapper);
		
		String[] encabezado = obtenerEncabezado(fechaInicio);
		Map<String, String> parametros = null;
		List<ReporteRowDTO> 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);
			}
			
			parametros = obtenerParametrosQuery(fechaInicio);
			reporteInfo = reportePagoAlterno.obtenerReporteRows(idContrato, idEstudio, parametros);
			
			logger.info("{}", mapper);
			
			info = excelMapperTransform.transformObjectToExcel(reporteInfo, mapper, ReporteRowDTO.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;
	}
	
	public void consultaListaMapa(){
		logger.info("Inicia");
		try {
			
			List<Map<String, String>> listaMapas = reportePagoAlterno.obtenerListaMapas();
			logger.info("listaMapas : [{}]", listaMapas);
			
		} catch (PersistenceException e) {
			logger.error("Error. {}", e);
		} catch (DataAccessException e) {
			logger.error("Error. {}", e);
		}
		logger.info("Finaliza");
	}

}
