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

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import javax.xml.stream.XMLStreamException;

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

import com.mx.dla.dda.catalogos.dtos.EstudioDTO;
import com.mx.dla.dda.excelMapper.exceptions.ExcelMapperException;
import com.mx.dla.dda.general.constants.MesesAnio;
import com.mx.dla.dda.general.utilerias.FechaUtilerias;
import com.mx.dla.dda.reporte.acumulateBuys.dao.ReporteAcumulateBuysDAO;
import com.mx.dla.dda.reporte.acumulateBuys.dto.acumulateBuysEstudiosDTO;
import com.mx.dla.dda.reporte.cpview.exception.ReportCostPerViewException;
import com.mx.dla.dda.reporte.general.dtos.CeldaBaseDTO;
import com.mx.dla.dda.reporte.general.dtos.ExcelEstilosConfDTO;
import com.mx.dla.dda.reporte.general.dtos.RangoExcelEstiloDTO;
import com.mx.dla.dda.reporte.oyp.daos.ReporteOveragesYPaymentsDAO;
import com.mx.dla.dda.reporte.oyp.dtos.ReporteOveragesYPaymentsVistaDTO;
import com.mx.dla.dda.reporte.reportecfg.daos.ReporteConfiguracionDAO;
import com.mx.dla.dda.reportes.ExcelGeneratorProcess.bos.ExcelGeneratorProcessBO;
import com.mx.dla.dda.reportes.generaxml.ExcelXmlConfiguracionWriter;
import com.mx.dla.global.bos.BaseBO;

@Service
public class ReporteOveragesYPaymentsBO extends BaseBO {

	@Autowired
	private ReporteOveragesYPaymentsDAO	reporteOveragesYPaymentsDAO;

	@Autowired
	private ReporteConfiguracionDAO		reporteConfiguracionDAO;

	@Autowired
	private ReporteAcumulateBuysDAO		reporteAcumulateBuysDAO;

	@Autowired
	private ExcelGeneratorProcessBO		excelGeneratorProcessBO;

	@Autowired
	private ExcelXmlConfiguracionWriter	excelXmlConfiguracionWriter;

	public List<LinkedHashMap<String, Object>> obtenReporteTabla(Long mesInicial, Long anioInicial, Long mesFinal, Long anioFinal, Long idEstudio, String tipoPago, String validaEstatusCarga)
	        throws ParseException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
		logger.info("obtenReporteTabla");

		String sumatorias_mensuales = "";
		String meses_seleccionados = "";
		String meses_pivote = "";
		ArrayList<String> columnas = new ArrayList<String>();

		SimpleDateFormat formater = new SimpleDateFormat("MM/yyyy");

		Calendar beginCalendar = Calendar.getInstance();
		Calendar finishCalendar = Calendar.getInstance();

		beginCalendar.setTime(formater.parse(mesInicial + "/" + anioInicial));
		finishCalendar.setTime(formater.parse(mesFinal + "/" + anioFinal));

		Integer index = 1;
		while (beginCalendar.before(finishCalendar) || beginCalendar.equals(finishCalendar)) {
			String month = StringUtils.leftPad(String.valueOf(beginCalendar.get(Calendar.MONTH) + 1), 2, "0");
			String year = String.valueOf(beginCalendar.get(Calendar.YEAR));

			sumatorias_mensuales = sumatorias_mensuales + "NVL(SUM(MES_" + index + "), 0) as M" + index + ",";
			meses_seleccionados = meses_seleccionados + "NVL( MES_" + index + ", 0 ) as MES_" + index + ",";
			meses_pivote = meses_pivote + "'" + month + year + "' as MES_" + index + ",";
			columnas.add("M" + index);

			beginCalendar.add(Calendar.MONTH, 1);
			index++;
		}

		sumatorias_mensuales = sumatorias_mensuales.substring(0, sumatorias_mensuales.length() - 1);
		meses_seleccionados = meses_seleccionados.substring(0, meses_seleccionados.length() - 1);
		meses_pivote = meses_pivote.substring(0, meses_pivote.length() - 1);

		List<LinkedHashMap<String, Object>> tabla = reporteOveragesYPaymentsDAO.obtenerOveragesYPayments(mesInicial, anioInicial, mesFinal, anioFinal, idEstudio, tipoPago, sumatorias_mensuales,
		        meses_seleccionados, meses_pivote, validaEstatusCarga);

		if (tabla != null && !tabla.isEmpty()) {
			columnas.addAll(Arrays.asList("SPLIT", "MAX", "OVERAGE"));

			LinkedList<LinkedHashMap<String, Object>> tmp = new LinkedList<LinkedHashMap<String, Object>>(tabla);
			LinkedHashMap<String, Object> template = tmp.getFirst();
			LinkedHashMap<String, Object> total = new LinkedHashMap<String, Object>();

			for (Map.Entry<String, Object> item : template.entrySet())
				if (item.getValue() instanceof String)
					total.put(item.getKey(), new String());
				else
					total.put(item.getKey(), null);

			for (String columna : columnas) {
				Double valor = new Double(0);
				for (LinkedHashMap<String, Object> item : tabla)
					if (((BigDecimal) item.get("ORDEN")).intValue() < 2)
						valor = valor + ((BigDecimal) item.get(columna)).doubleValue();
				total.put(columna, new BigDecimal(valor.toString()));
			}

			total.put("ASSET_NAME", "Total general");
			tabla.add(total);
		}

		return tabla == null || tabla.isEmpty() ? null : tabla;
	}

	public ReporteOveragesYPaymentsVistaDTO obtenerReporteOveragesYPaymentsVista(String fechaInicial, String fechaFinal, String tipoPago, String claveReporte, Long idEstudio, String validaEstatusCarga)
	        throws ParseException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
		ReporteOveragesYPaymentsVistaDTO reporte = new ReporteOveragesYPaymentsVistaDTO();

		HashMap<String, Long> fechaInicialSplit = FechaUtilerias.getFechaValores(fechaInicial, "MM/yyyy");
		Long mesInicial = fechaInicialSplit.get("Month");
		Long anioInicial = fechaInicialSplit.get("Year");

		HashMap<String, Long> fechaFinalSplit = FechaUtilerias.getFechaValores(fechaFinal, "MM/yyyy");
		Long mesFinal = fechaFinalSplit.get("Month");
		Long anioFinal = fechaFinalSplit.get("Year");

		List<LinkedHashMap<String, Object>> tabla = obtenReporteTabla(mesInicial, anioInicial, mesFinal, anioFinal, idEstudio, tipoPago, validaEstatusCarga);
		logger.info("{}", tabla);

		if (tabla != null)
			reporte.setTabla(transform(tabla));

		List<LinkedHashMap<String, Object>> columnCfg = reporteConfiguracionDAO.obtenerReporteConfiguracion(claveReporte, idEstudio);

		ArrayList<String> output = new ArrayList<String>();
		for (LinkedHashMap<String, Object> item : columnCfg)
			output.add(item.get("COLUMNA").toString());

		reporte.setColumnCfg(output);
		reporte.setHeader(transform(obtenReporteHeaders(mesInicial, anioInicial, mesFinal, anioFinal)));

		logger.info("{}", reporte.getHeader());

		return reporte;
	}

	public List<LinkedHashMap<String, Object>> obtenReporteHeaders(Long mesInicial, Long anioInicial, Long mesFinal, Long anioFinal) throws ParseException {

		List<LinkedHashMap<String, Object>> headers = new ArrayList<LinkedHashMap<String, Object>>();
		LinkedHashMap<String, Object> header = new LinkedHashMap<String, Object>();

		header.put("ORDEN", "Orden");
		header.put("TYPE_PAGO", "Tipo Pago");
		header.put("NUMERO_CONTRATO", "Numero Contrato");
		header.put("ASSET_NAME", "Asset Name");
		header.put("MG", "MG");
		header.put("CLASS", "Class");

		SimpleDateFormat formater = new SimpleDateFormat("MM/yyyy");

		Calendar beginCalendar = Calendar.getInstance();
		Calendar finishCalendar = Calendar.getInstance();

		beginCalendar.setTime(formater.parse(mesInicial + "/" + anioInicial));
		finishCalendar.setTime(formater.parse(mesFinal + "/" + anioFinal));

		Integer index = 0;
		while (beginCalendar.before(finishCalendar) || beginCalendar.equals(finishCalendar)) {
			String month = MesesAnio.parse("" + (beginCalendar.get(Calendar.MONTH) + 1)).getShortDesc();
			String year = String.valueOf(beginCalendar.get(Calendar.YEAR));

			header.put("M" + (index + 1), month + " - " + year);

			beginCalendar.add(Calendar.MONTH, 1);
			index++;
		}

		header.put("SPLIT", "SPLIT");
		header.put("MAX", "MAX");
		header.put("OVERAGE", "OVERAGE");

		logger.info("{}", header);
		headers.add(header);

		return headers;
	}

	public ArrayList<ArrayList<CeldaBaseDTO>> transform(List<LinkedHashMap<String, Object>> input) {
		ArrayList<ArrayList<CeldaBaseDTO>> output = new ArrayList<ArrayList<CeldaBaseDTO>>();
		for (LinkedHashMap<String, Object> item : input)
			output.add(transform(item));
		return output;
	}

	public ArrayList<CeldaBaseDTO> transform(LinkedHashMap<String, Object> input) {
		ArrayList<CeldaBaseDTO> output = new ArrayList<CeldaBaseDTO>();

		for (Map.Entry<String, Object> entry : input.entrySet()) {
			CeldaBaseDTO item = new CeldaBaseDTO(entry.getKey(), null, entry.getValue() == null ? null : entry.getValue().toString());
			output.add(item);
		}
		return output;
	}

	public List<EstudioDTO> obtenerEstudios() {

		List<EstudioDTO> estudios = new ArrayList<EstudioDTO>();
		List<acumulateBuysEstudiosDTO> estudiosOrigen = reporteAcumulateBuysDAO.obtenerEstudios();

		for (acumulateBuysEstudiosDTO item : estudiosOrigen) {
			EstudioDTO estudio = new EstudioDTO();
			estudio.setIdEstudio(item.getId_estudio() == null ? null : new Long(item.getId_estudio()));
			estudio.setDescripcionEstudio(item.getDesc_estudio());
			estudios.add(estudio);
		}

		return estudios;
	}

	public InputStream obtenerStreamReporte(String fechaInicial, String fechaFinal, String tipoPago, String claveReporte, Long idEstudio, String usuario, String validaEstatusCarga)
	        throws IllegalArgumentException, IllegalAccessException, ParseException, ExcelMapperException, IOException, ReportCostPerViewException, InstantiationException, InvocationTargetException,
	        NoSuchMethodException, SecurityException, XMLStreamException {

		HashMap<String, Long> fechaInicialSplit = FechaUtilerias.getFechaValores(fechaInicial, "MM/yyyy");
		Long mesInicial = fechaInicialSplit.get("Month");
		Long anioInicial = fechaInicialSplit.get("Year");

		HashMap<String, Long> fechaFinalSplit = FechaUtilerias.getFechaValores(fechaFinal, "MM/yyyy");
		Long mesFinal = fechaFinalSplit.get("Month");
		Long anioFinal = fechaFinalSplit.get("Year");

		List<LinkedHashMap<String, Object>> header = obtenReporteHeaders(mesInicial, anioInicial, mesFinal, anioFinal);
		List<LinkedHashMap<String, Object>> tabla = obtenReporteTabla(mesInicial, anioInicial, mesFinal, anioFinal, idEstudio, tipoPago, validaEstatusCarga);
		String fileFileName = usuario + "-" + mesInicial + anioInicial + mesFinal + anioFinal + "-reporteCYP";
		logger.info("{}", fileFileName);

		String[] rcolumnasnew = { "ORDEN", "TYPE_PAGO", "NUMERO_CONTRATO" };

		header = remove(header, rcolumnasnew);
		tabla = remove(tabla, rcolumnasnew);

		List<ExcelEstilosConfDTO> estilos = obtenExcelEstilos(header, tabla);

		excelXmlConfiguracionWriter.writeToXml(fileFileName + ".xml", header, tabla, estilos, "Reporte Overages y Payments");

		logger.info("generaXML");

		return excelGeneratorProcessBO.generaExcelProceso(fileFileName + ".xml", fileFileName + ".xlxs");
	}

	public List<LinkedHashMap<String, Object>> remove(List<LinkedHashMap<String, Object>> input, String[] columnsToRemove) {
		for (LinkedHashMap<String, Object> item : input)
			for (String columna : columnsToRemove)
				item.remove(columna);
		return input;
	}

	private List<ExcelEstilosConfDTO> obtenExcelEstilos(List<LinkedHashMap<String, Object>> header, List<LinkedHashMap<String, Object>> tabla) {

		List<RangoExcelEstiloDTO> rheader = new ArrayList<RangoExcelEstiloDTO>();
		rheader.add(new RangoExcelEstiloDTO(Long.valueOf(0L), Long.valueOf(1L), Long.valueOf(0L), new Integer(tabla.get(0).keySet().size() + 1).longValue()));

		List<RangoExcelEstiloDTO> rCifras = new ArrayList<RangoExcelEstiloDTO>();
		rCifras.add(new RangoExcelEstiloDTO(Long.valueOf(1L), new Integer(tabla.size() + 1).longValue(), Long.valueOf(3L), new Integer(tabla.get(0).keySet().size() + 1).longValue()));
		rCifras.add(new RangoExcelEstiloDTO(Long.valueOf(1L), new Integer(tabla.size() + 1).longValue(), Long.valueOf(1L), Long.valueOf(2L)));

		List<RangoExcelEstiloDTO> rTextos = new ArrayList<RangoExcelEstiloDTO>();
		rTextos.add(new RangoExcelEstiloDTO(Long.valueOf(1L), new Integer(tabla.size() + 1).longValue(), Long.valueOf(0L), Long.valueOf(1L)));

		List<RangoExcelEstiloDTO> rNormal = new ArrayList<RangoExcelEstiloDTO>();
		rNormal.add(new RangoExcelEstiloDTO(Long.valueOf(1L), new Integer(tabla.size() + 1).longValue(), Long.valueOf(2L), Long.valueOf(3L)));

		List<ExcelEstilosConfDTO> estilos = new ArrayList<ExcelEstilosConfDTO>();
		estilos.add(new ExcelEstilosConfDTO(String.valueOf(0), String.valueOf(0), String.valueOf(1), String.valueOf(1), "left", null, "celda_encabezado_general", null, null, "string", rheader));
		estilos.add(new ExcelEstilosConfDTO(String.valueOf(0), String.valueOf(0), String.valueOf(1), String.valueOf(1), "right", null, "celda_normal", null, null, "decimal2", rCifras));
		estilos.add(new ExcelEstilosConfDTO(String.valueOf(150), String.valueOf(0), String.valueOf(1), String.valueOf(1), "left", null, "celda_normal", null, null, "string", rTextos));
		estilos.add(new ExcelEstilosConfDTO(String.valueOf(0), String.valueOf(0), String.valueOf(1), String.valueOf(1), "left", null, "celda_normal", null, null, "string", rNormal));

		return estilos;
	}

}