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

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
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.admin.catalogos.addons.dtos.EstudioAddonDTO;
import com.mx.dla.dda.admin.catalogos.addons.dtos.ReporteAddonDTO;
import com.mx.dla.dda.admin.catalogos.estudios.daos.CatalogoEstudiosDAO;
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.dtos.ReporteAddOnRowDTO;
import com.mx.dla.dda.reporte.pago.dtos.ReporteCRowDTO;
import com.mx.dla.global.bos.BaseBO;

@Component
public class ReporteSuscriptoresBO extends BaseBO {

	@Autowired
	private ReportePagoAlternoDAO reportePagoAlterno;

	@Autowired
	private ExcelMapperContext excelMapperContext;

	@Autowired
	protected ExcelMapperTransform excelMapperTransform;

	@Autowired
	private CatalogoEstudiosDAO estudiosDao;

	public String[] obtenerLlaves() {
		String[] llaves = { "m1", "m2", "m3", "m4", "m5", "m6", "m7", "m8", "m9", "m10", "m11", "m12", "m13", "m14",
				"m15", "m16", "m17", "m18", "m19" };
		return llaves;
	}

	public String[] obtenerEncabezado() {

		String[] encabezado = obtenerLlaves();

		return encabezado;
	}

	public String[] obtenerEncabezadoCA() {

		String[] encabezado = { "M1", "M2", "M3", "M4", "M5", "M6", "M7", "M8", "M9", "M10", "M11", "M12", "M13", "M14",
				"M15", "M16", "M17", "M18", "M19", "Total" };

		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<ReporteCRowDTO> obteneReporteS(Date fechaInicio) {

		List<ReporteCRowDTO> reporte = null;

		try {
			logger.info("antes de reporte");
			reporte = reportePagoAlterno.obtenerReporteRowsS(fechaInicio);

			logger.info("Regresando reporte");
		} catch (PersistenceException e) {
			logger.error("Error. {}", e);
		} catch (DataAccessException e) {
			logger.error("Error. {}", e);
		}
		return reporte;
	}
	
	public void agrupaEnHistorico(String agrupado, Calendar fecha, Long idEstudio) {
		if (agrupado.equals("SI")) {
			estudiosDao.guardarHistorico(idEstudio, fecha.get(Calendar.YEAR), fecha.get(Calendar.MONTH) + 1, 1);
			estudiosDao.guardarHistorico(idEstudio, fecha.get(Calendar.YEAR), fecha.get(Calendar.MONTH) + 1, 2);
		}else {
			estudiosDao.guardarHistorico(idEstudio, fecha.get(Calendar.YEAR), fecha.get(Calendar.MONTH) + 1, 0);
		}
	}

	public List<ReporteAddOnRowDTO> obteneReporteCA(Date fechaInicio, Long idEstudio) {

		List<ReporteAddOnRowDTO> reporte = null;
		Calendar fecha = Calendar.getInstance();
		fecha.setTime(fechaInicio);

		try {
			EstudioAddonDTO estudio = estudiosDao.catalogoEstudiosAddOnById(idEstudio);
			logger.info("Estudio Recuperado: " + estudio.getNombre());
			ReporteAddonDTO report = estudiosDao.getTiposReporteById(estudio.getIdReporte());
			logger.info("Reporte Recuperado de BD : " + report.getDescFormula());
			switch(report.getFormula()) {
			case "A": 
				agrupaEnHistorico(estudio.getAgrupado(), fecha, idEstudio);
				reporte = reportePagoAlterno.obtenerReporteGeneral(fechaInicio, idEstudio, "'MEXICO'");
				reporte.addAll(reportePagoAlterno.obtenerReporteGeneralMexico(fechaInicio, idEstudio));
				agregarTotales(reporte);
				break;
			case "B":
			case "C": 
				agrupaEnHistorico(estudio.getAgrupado(), fecha, idEstudio);
				reporte = reportePagoAlterno.obtenerReporteGeneral(fechaInicio, idEstudio, "'TODOS'");
				agregarTotales(reporte);
				break;
			case "D": 
				estudiosDao.guardarHistorico(idEstudio, fecha.get(Calendar.YEAR), fecha.get(Calendar.MONTH) + 1, 3);
				reporte = reportePagoAlterno.obtenerReporteFoxGeneral(fechaInicio, idEstudio);
				agregarTotales(reporte);
				break;
			case "E": 
				agrupaEnHistorico(estudio.getAgrupado(), fecha, idEstudio);
				reporte = reportePagoAlterno.obtenerReporteKaraokeQello(fechaInicio, idEstudio,"'TODOS'");
				agregarTotales(reporte);
				break;
			default: logger.error("Reporte no reconocido: " + report.getDescFormula());
			}
			logger.info("Regresando reporte numero de filas" + reporte.size());

		} catch (PersistenceException e) {
			logger.error("Error. {}", e);
		} catch (DataAccessException e) {
			logger.error("Error. {}", e);
		}
		return reporte;
	}
	
	public void agregarTotales(List<ReporteAddOnRowDTO> reporte) {
		ReporteAddOnRowDTO totales = new ReporteAddOnRowDTO();
		Double f2 = 0.0;
		Double fd1 = 0.0;
		Double m19 = 0.0;
		logger.info("Antes de for");
		for (ReporteAddOnRowDTO r : reporte) {
			logger.info("Agregando f2 " + r.getF2());
			f2 = f2 + Double.parseDouble(r.getF2());
			logger.info("Agregando fd1 " + r.getFd1());
			if(r.getFd1() == null) {
				fd1 = fd1 + Double.parseDouble("0");
			}
			else {
				fd1 = fd1 + Double.parseDouble(r.getFd1());
			}
			
			logger.info("Agregando m19 " + r.getM19());
			m19 = m19 + Double.parseDouble(r.getM19());
		}
		logger.info("totales listos");
		totales.setF2(BigDecimal.valueOf(f2).setScale(2, RoundingMode.HALF_UP).toString());
		totales.setFd1(BigDecimal.valueOf(fd1).setScale(2, RoundingMode.HALF_UP).toString());
		totales.setM19(BigDecimal.valueOf(m19).setScale(2, RoundingMode.HALF_UP).toString());
		totales.setM5("Totales: ");
		logger.info("totales listos: " + reporte.size());
		reporte.add(totales);
		logger.info("totales listos: " + reporte.size());
	}

	public InputStream obtenerReporteEnExcel(Date fechaInicio, Long idEstudio) {

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

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

		String[] encabezado = obtenerEncabezado();
		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.obtenerReporteRowsS(fechaInicio);

			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;
	}

	public void cerrarHistorico(Date dateFormat, Long idEstudio) {
		Calendar fecha = Calendar.getInstance();
		fecha.setTime(dateFormat);
		estudiosDao.cerrarHistorico(idEstudio, fecha.get(Calendar.YEAR), fecha.get(Calendar.MONTH) + 1);
	}

}
