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

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

import javax.xml.stream.XMLStreamException;

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.contrato.generales.daos.PoblarGeneralesDAO;
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.dtos.ReporteOveragesYPaymentsVistaDTO;
import com.mx.dla.dda.reporte.reportecfg.daos.ReporteConfiguracionDAO;
import com.mx.dla.dda.reporte.rys.daos.ReporteRevenueYSplitsDAO;
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 ReporteRevenueYSplitsBO extends BaseBO {

	@Autowired
	private ReporteRevenueYSplitsDAO	reporteRevenueYSplitsDAO;

	@Autowired
	private ReporteConfiguracionDAO		reporteConfiguracionDAO;

	@Autowired
	private ExcelGeneratorProcessBO		excelGeneratorProcessBO;

	@Autowired
	private ExcelXmlConfiguracionWriter	excelXmlConfiguracionWriter;

	@Autowired
	private ReporteAcumulateBuysDAO		reporteAcumulateBuysDAO;

	public List<LinkedHashMap<String, Object>> obtenReporteTabla(Long mes, Long anio, Long idEstudio, String tipoAbono, String validaEstatusCarga)
	        throws ParseException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {

		logger.info("obtenReporteTabla");

		List<LinkedHashMap<String, Object>> tabla = reporteRevenueYSplitsDAO.obtenerRevenueYSplits(mes, anio, idEstudio, tipoAbono, validaEstatusCarga);

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

	public ReporteOveragesYPaymentsVistaDTO obtenerReporteRevenueYSplitsVista(String fecha, String tipoAbono, String claveReporte, Long idEstudio, String validaEstatusCarga)
	        throws ParseException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
		ReporteOveragesYPaymentsVistaDTO reporte = new ReporteOveragesYPaymentsVistaDTO();

		HashMap<String, Long> fechaSplit = FechaUtilerias.getFechaValores(fecha, "MM/yyyy");
		Long mes = fechaSplit.get("Month");
		Long anio = fechaSplit.get("Year");

		List<LinkedHashMap<String, Object>> tabla = obtenReporteTabla(mes, anio, idEstudio, tipoAbono, validaEstatusCarga);

		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(mes, anio)));

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

		return reporte;
	}

	public List<LinkedHashMap<String, Object>> obtenReporteHeaders(Long mes, Long anio) throws ParseException {

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

		String month = MesesAnio.parse("" + mes).getShortDesc();

		header.put("REGION", "Region");
		header.put("ASSET_NAME", "Asset Name");
		header.put("COUNTRY", "Country");
		header.put("REVENUE", "Revenue Share");
		header.put("VAT", "Client Retail (VAT)");
		header.put("MES", "Reporting Date" + System.lineSeparator() + month + " - " + anio + System.lineSeparator() + " Buys");
		header.put("TOTAL", "Value" + System.lineSeparator() + "Total Revenue");

		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 fecha, String tipoAbono, 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(fecha, "MM/yyyy");
		Long mes = fechaInicialSplit.get("Month");
		Long anio = fechaInicialSplit.get("Year");

		List<LinkedHashMap<String, Object>> header = obtenReporteHeaders(mes, anio);
		List<LinkedHashMap<String, Object>> tabla = obtenReporteTabla(mes, anio, idEstudio, tipoAbono,  validaEstatusCarga);
		String fileFileName = usuario + "-" + mes + anio + "-reporteRYS";

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

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

		logger.info("generaXML");

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

	public List<List<Long>> findRanges(List<Long> list) {
		List<List<Long>> lList = new ArrayList<List<Long>>(); // list of list of integer
		int i = 0;
		int start = 0;
		List<Long> sList = new ArrayList<Long>(2);
		for (i = 1; i < list.size(); i++) {

			if (list.get(i - 1) + 1 != list.get(i)) {
				sList.add(list.get(start));
				sList.add(list.get(i - 1));
				lList.add(sList);
				sList = new ArrayList<Long>(2);
				start = i;
			}

		}
		sList.add(list.get(start));
		sList.add(list.get(list.size() - 1));
		lList.add(sList);
		return lList;
	}

	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> rNormalc = new ArrayList<RangoExcelEstiloDTO>();
		rNormalc.add(new RangoExcelEstiloDTO(1L, new Integer(tabla.size() + 1).longValue(), Long.valueOf(0L), Long.valueOf(1L)));
		rNormalc.add(new RangoExcelEstiloDTO(1L, new Integer(tabla.size() + 1).longValue(), Long.valueOf(2L), Long.valueOf(3L)));

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

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

		List<RangoExcelEstiloDTO> rCifrasTotales = new ArrayList<RangoExcelEstiloDTO>();
		List<RangoExcelEstiloDTO> rNormal = new ArrayList<RangoExcelEstiloDTO>();
		List<RangoExcelEstiloDTO> rTextoTotales = new ArrayList<RangoExcelEstiloDTO>();

		long i = 0;

		logger.info("T {}", tabla);

		List<Long> totalesFilas = new ArrayList<Long>();
		List<Long> normalesFilas = new ArrayList<Long>();

		for (LinkedHashMap<String, Object> item : tabla) {

			logger.info("I {}", item);
			logger.info("R :{}:", item.get("REGION"));
			logger.info("RS :{}:", item.get("REGION").toString().trim());

			if (item.get("REGION") != null && !item.get("REGION").toString().trim().equals("")) {
				logger.info("NX {}", i);
				normalesFilas.add(i++);
			}
			else {
				logger.info("TX {}", i);

				totalesFilas.add(i++);
			}
		}

		logger.info("{}", normalesFilas);
		logger.info("{}", totalesFilas);

		List<List<Long>> rangosNormales = findRanges(normalesFilas);
		logger.info("{}", rangosNormales);

		List<List<Long>> rangosTotales = findRanges(totalesFilas);
		logger.info("{}", rangosTotales);

		for (List<Long> rango : rangosNormales) {
			rCifras.add(new RangoExcelEstiloDTO(rango.get(0) + 1, rango.get(1) + 2, Long.valueOf(5L), new Integer(tabla.get(0).keySet().size() + 1).longValue()));
			rNormal.add(new RangoExcelEstiloDTO(rango.get(0) + 1, rango.get(1) + 2, Long.valueOf(1L), Long.valueOf(2L)));

		}
		for (List<Long> rango : rangosTotales) {
			rCifrasTotales.add(new RangoExcelEstiloDTO(rango.get(0) + 1, rango.get(1) + 2, Long.valueOf(5L), new Integer(tabla.get(0).keySet().size() + 1).longValue()));
			rTextoTotales.add(new RangoExcelEstiloDTO(rango.get(0) + 1, rango.get(1) + 2, Long.valueOf(1L), Long.valueOf(2L)));
		}

		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", rNormal));
		estilos.add(new ExcelEstilosConfDTO(String.valueOf(150), String.valueOf(0), String.valueOf(1), String.valueOf(1), "center", null, "celda_normal", null, null, "string", rNormalc));
		estilos.add(new ExcelEstilosConfDTO(String.valueOf(150), String.valueOf(0), String.valueOf(1), String.valueOf(1), "right", null, "celda_negrita", null, null, "string", rTextoTotales));
		estilos.add(new ExcelEstilosConfDTO(String.valueOf(0), String.valueOf(0), String.valueOf(1), String.valueOf(1), "right", null, "celda_negrita", null, null, "decimal2", rCifrasTotales));
		estilos.add(new ExcelEstilosConfDTO(String.valueOf(0), String.valueOf(0), String.valueOf(1), String.valueOf(1), "center", null, "celda_normal", null, null, "percentage", rPercentages));

		return estilos;
	}

}