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

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;

import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.exceptions.PersistenceException;
import org.apache.ibatis.executor.result.ResultMapException;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFFont;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Service;

import com.mx.dla.dda.contrato.titulo.dtos.Titulo;
import com.mx.dla.dda.contrato.transaccion.exceptions.dtos.TransaccionException;
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.amortizacion.daos.ReporteAmortizacionDAO;
import com.mx.dla.dda.reporte.amortizacion.dtos.MesesAmortizacionDTO;
import com.mx.dla.global.bos.BaseBO;

@Service
public class ReporteExcelAmortizacionBO extends BaseBO {

	@Autowired
	protected ExcelMapperTransform excelMapperTransform;

	@Autowired
	private ExcelMapperContext excelMapperContext;

	@Autowired
	private ReporteAmortizacionDAO reporteAmortizacionDAO;

	private final String[] smeses = { "ENE", "FEB", "MAR", "ABR", "MAY", "JUN", "JUL", "AGO", "SEP", "OCT", "NOV",
			"DIC" };

	public byte[] generaReporteAmortizacion(Long idEstudio, String fecha)
			throws ResultMapException, SQLException, TransaccionException, ExcelMapperException, IOException {
		List<MesesAmortizacionDTO> reporte = null;
		byte[] fileExcel = null;

		try {
			reporte = reporteAmortizacionDAO.obtenerMesesAmortizacion(idEstudio, fecha);
		} catch (PersistenceException e) {
			throw new TransaccionException("Error al cargar los datos.", e);
		} catch (DataAccessException e) {
			throw new TransaccionException("Error al cargar los datos", e);
		}
		if (reporte.isEmpty())
			reporte.add(getVacio());
		logger.info("{}", reporte);

		fileExcel = this.generarExcel(fecha, reporte);
		return fileExcel;
	}

	public byte[] generaReporteAmortizacionSAP(Long idEstudio, String fecha)
			throws ResultMapException, SQLException, TransaccionException, ExcelMapperException, IOException {
		List<MesesAmortizacionDTO> reporte = null;
		byte[] fileExcel = null;

		try {
			reporte = reporteAmortizacionDAO.obtenerMesesAmortizacionSAP(idEstudio, fecha);
			if (reporte.isEmpty())
				reporte.add(getVacio());
			logger.info("{}", reporte);

		} catch (PersistenceException e) {
			throw new TransaccionException("Error al cargar los datos.", e);
		} catch (DataAccessException e) {
			throw new TransaccionException("Error al cargar los datos", e);
		}

		fileExcel = this.generarExcel(fecha, reporte);
		return fileExcel;
	}

	public byte[] generaReporteAmortizacionSAPDLA(Long idEstudio, String fecha)
			throws ResultMapException, SQLException, TransaccionException {
		ByteArrayOutputStream baos = null;
		try {
			Integer year = Integer.parseInt(fecha.substring(3));
			Integer month = Integer.parseInt(fecha.substring(0, 2));
			String day = "01/";
			Map<String, List<MesesAmortizacionDTO>> reporte = getResults(idEstudio, day.concat(year.toString()));
			Map<String, List<MesesAmortizacionDTO>> reporteAnt = getResults(idEstudio, day + (year - 1));
			Map<String, List<MesesAmortizacionDTO>> reporteSig = getResults(idEstudio, day + (year + 1));
			Workbook workbook = new XSSFWorkbook();

			Sheet sheet = workbook.createSheet("Conciliacion DDA vs SAP");
			addHeaders(sheet, workbook, year);
			int row = 1;
			for (Entry<String, List<MesesAmortizacionDTO>> rep : reporte.entrySet()) {
				if (rep.getValue().size() < 2) {
					MesesAmortizacionDTO emptyValue = new MesesAmortizacionDTO(0.0);
					emptyValue.setSistema(rep.getValue().get(0).getSistema().equals("DDA") ? "SAP" : "DDA");
					emptyValue.setDescripcion(rep.getValue().get(0).getDescripcion());
					emptyValue.setTemporada(rep.getValue().get(0).getTemporada());
					emptyValue.setIdContrato(rep.getValue().get(0).getIdContrato());
					rep.getValue().add(emptyValue);
				}
				CellStyle headerStyle;
				int i = 0;
				for (MesesAmortizacionDTO line : rep.getValue()) {
					if (Objects.nonNull(reporteAnt.get(rep.getKey())) && reporteAnt.get(rep.getKey()).size() > i) {
						if (Objects.nonNull(reporteAnt.get(rep.getKey()))) {
							line.setAcumuladoAnt(reporteAnt.get(rep.getKey()).get(i).getAcumulado());
						} else {
							line.setAcumuladoAnt(0.0);
						}
						if (Objects.nonNull(reporteSig.get(rep.getKey()))) {
							line.setAcumuladoSig(reporteSig.get(rep.getKey()).get(i).getAcumulado());
						} else {
							line.setAcumuladoSig(0.0);
						}
					} else {
						line.setAcumuladoAnt(0.0);
						line.setAcumuladoSig(0.0);
					}
					line.calculaRemanente(month);
					int cell = 0;
					if (row == 1 || row == 2) {
						headerStyle = getStyle(workbook, IndexedColors.LIGHT_ORANGE.getIndex(),
								CellStyle.SOLID_FOREGROUND, Short.parseShort("10"), false);
					} else {
						if (Objects.nonNull(line.getIdContrato())) {
							headerStyle = getStyle(workbook, IndexedColors.LIGHT_GREEN.getIndex(),
									CellStyle.SOLID_FOREGROUND, Short.parseShort("10"), false);
						} else {
							headerStyle = getStyle(workbook, IndexedColors.LIGHT_YELLOW.getIndex(),
									CellStyle.SOLID_FOREGROUND, Short.parseShort("10"), false);
						}
					}
					Row header = sheet.createRow(row++);
					fillCell(header, header.createCell(cell++), headerStyle, line.getDescripcion());
					fillCell(header, header.createCell(cell++), headerStyle, line.getTemporada());
					fillCell(header, header.createCell(cell++), headerStyle, line.getSistema());
					fillCell(header, header.createCell(cell++), headerStyle, line.getAcumuladoAnt());
					fillCell(header, header.createCell(cell++), headerStyle, line.getMes1());
					fillCell(header, header.createCell(cell++), headerStyle, line.getMes2());
					fillCell(header, header.createCell(cell++), headerStyle, line.getMes3());
					fillCell(header, header.createCell(cell++), headerStyle, line.getMes4());
					fillCell(header, header.createCell(cell++), headerStyle, line.getMes5());
					fillCell(header, header.createCell(cell++), headerStyle, line.getMes6());
					fillCell(header, header.createCell(cell++), headerStyle, line.getMes7());
					fillCell(header, header.createCell(cell++), headerStyle, line.getMes8());
					fillCell(header, header.createCell(cell++), headerStyle, line.getMes9());
					fillCell(header, header.createCell(cell++), headerStyle, line.getMes10());
					fillCell(header, header.createCell(cell++), headerStyle, line.getMes11());
					fillCell(header, header.createCell(cell++), headerStyle, line.getMes12());
					fillCell(header, header.createCell(cell++), headerStyle, line.getAcumulado());
					fillCell(header, header.createCell(cell++), headerStyle, line.getAcumuladoSig());
					fillCell(header, header.createCell(cell++), headerStyle, line.getRemanente());
					i++;
				}
				sheet.addMergedRegion(new CellRangeAddress((row - 2), (row - 1), 0, 0));
			}
			baos = new ByteArrayOutputStream();
			workbook.write(baos);

		} catch (PersistenceException e) {
			throw new TransaccionException("Error al cargar los datos.", e);
		} catch (DataAccessException e) {
			throw new TransaccionException("Error al cargar los datos", e);
		} catch (IOException e) {
			throw new TransaccionException("Error al cargar los datos", e);
		}

		return baos.toByteArray();
	}

	public void addHeaders(Sheet sheet, Workbook workbook, Integer year) {
		CellStyle headerStyle = getStyle(workbook, IndexedColors.RED.getIndex(), CellStyle.SOLID_FOREGROUND,
				Short.parseShort("12"), true);
		Row header = sheet.createRow(0);
		fillCell(header, header.createCell(0), headerStyle, "Descripción");
		fillCell(header, header.createCell(1), headerStyle, "Temporada");
		fillCell(header, header.createCell(2), headerStyle, "Sistema");
		fillCell(header, header.createCell(3), headerStyle, "Acumulado " + (year - 1));
		fillCell(header, header.createCell(4), headerStyle, "ENE");
		fillCell(header, header.createCell(5), headerStyle, "FEB");
		fillCell(header, header.createCell(6), headerStyle, "MAR");
		fillCell(header, header.createCell(7), headerStyle, "ABR");
		fillCell(header, header.createCell(8), headerStyle, "MAY");
		fillCell(header, header.createCell(9), headerStyle, "JUN");
		fillCell(header, header.createCell(10), headerStyle, "JUL");
		fillCell(header, header.createCell(11), headerStyle, "AGO");
		fillCell(header, header.createCell(12), headerStyle, "SEP");
		fillCell(header, header.createCell(13), headerStyle, "OCT");
		fillCell(header, header.createCell(14), headerStyle, "NOV");
		fillCell(header, header.createCell(15), headerStyle, "DIC");
		fillCell(header, header.createCell(16), headerStyle, "Acumulado");
		fillCell(header, header.createCell(17), headerStyle, "Acumulado " + (year + 1));
		fillCell(header, header.createCell(18), headerStyle, "Remanente");
	}

	public Map<String, List<MesesAmortizacionDTO>> getResults(Long idEstudio, String fecha) {
		Map<String, List<MesesAmortizacionDTO>> reporte = new LinkedHashMap<>();
		List<MesesAmortizacionDTO> registros = new LinkedList<>();
		registros.addAll(reporteAmortizacionDAO.obtenerMesesAmortizacion(idEstudio, fecha));
		registros.addAll(reporteAmortizacionDAO.obtenerMesesAmortizacionSAP(idEstudio, fecha));
		for (MesesAmortizacionDTO registro : registros) {
			String temporada = Objects.nonNull(registro.getTemporada()) ? registro.getTemporada() : StringUtils.EMPTY;
			String numContrato = Objects.nonNull(registro.getNumContrato()) ? registro.getNumContrato()
					: StringUtils.EMPTY;
			if (!reporte.containsKey(registro.getDescripcion() + temporada + numContrato)) {
				reporte.put(registro.getDescripcion() + temporada + numContrato, new ArrayList<MesesAmortizacionDTO>());
			}
			reporte.get(registro.getDescripcion() + temporada + numContrato).add(registro);
		}

		return reporte;
	}

	private void fillCell(Row header, Cell headerCell, CellStyle headerStyle, Double data) {
		headerCell.setCellValue(data);
		headerCell.setCellStyle(headerStyle);
	}

	private void fillCell(Row header, Cell headerCell, CellStyle headerStyle, String data) {
		headerCell.setCellValue(data);
		headerCell.setCellStyle(headerStyle);
	}

	private CellStyle getStyle(Workbook workbook, short color, short pattern, short size, boolean isBold) {
		CellStyle headerStyle = workbook.createCellStyle();
		headerStyle.setFillForegroundColor(color);
		headerStyle.setFillPattern(pattern);

		XSSFFont font = ((XSSFWorkbook) workbook).createFont();
		font.setFontName("Arial");
		font.setFontHeightInPoints(size);
		font.setBold(isBold);
		headerStyle.setFont(font);
		return headerStyle;
	}

	private MesesAmortizacionDTO getVacio() {
		MesesAmortizacionDTO v = new MesesAmortizacionDTO();
		v.setDescripcion("");
		v.setMes1(0.0);
		v.setMes2(0.0);
		v.setMes3(0.0);
		v.setMes4(0.0);
		v.setMes5(0.0);
		v.setMes6(0.0);
		v.setMes7(0.0);
		v.setMes8(0.0);
		v.setMes9(0.0);
		v.setMes10(0.0);
		v.setMes11(0.0);
		v.setMes12(0.0);
		v.setAcumulado(0.0);
		return v;
	}

	public byte[] generarExcel(String fecha, List<MesesAmortizacionDTO> reporte)
			throws ExcelMapperException, IOException {
		byte[] fileExcel = null;
		String[] mesAnnio = fecha.split("/");
		int mes = Integer.parseInt(mesAnnio[0]);
		int annio = Integer.parseInt(mesAnnio[1]);

		ExcelMapper mapper = excelMapperContext.getExcelMapper("mesesAmortizacion");

		for (int i = 1; i <= 12; i++) {
			String headerFormated = String.format(mapper.getRules().get(i).getHeader(), smeses[mes - 1], annio);
			mapper.getRules().get(i).setHeader(headerFormated);
			mes++;
			if (mes > 12) {
				annio++;
				mes = 1;
			}
		}

		fileExcel = excelMapperTransform.transformObjectToExcel(reporte, mapper, MesesAmortizacionDTO.class);
		return fileExcel;
	}

	// ---metodos de prueba
	public byte[] generaReporteAmortizacion_old() throws ExcelMapperException, IOException {

		List<Titulo> reporte = new ArrayList<Titulo>();
		Titulo titulo = new Titulo();
		byte[] fileExcel = null;

		titulo.setTipoTitulo("tipo");
		titulo.setNombreUnico("Nombre Unico");
		titulo.setEpisodio("Episodio");
		reporte.add(titulo);

		fileExcel = excelMapperTransform.transformObjectToExcel(reporte, "titulo", Titulo.class);
		logger.info("" + fileExcel.length);

		return fileExcel;
	}

	public byte[] generaReporteAmortizacionOK() throws ExcelMapperException, IOException {
		byte[] fileExcel = null;

		List<MesesAmortizacionDTO> reporte = new ArrayList<MesesAmortizacionDTO>();
		MesesAmortizacionDTO meses = new MesesAmortizacionDTO();
		meses.setAcumulado(100.0);
		meses.setDescripcion("Descripcion");
		meses.setIdContrato(1L);
		meses.setMes1(1.0);
		meses.setMes2(2.0);
		meses.setMes3(3.0);
		meses.setMes4(4.0);
		meses.setMes5(5.0);

		reporte.add(meses);
		fileExcel = excelMapperTransform.transformObjectToExcel(reporte, "mesesAmortizacion",
				MesesAmortizacionDTO.class);
		logger.info("" + fileExcel.length);

		return fileExcel;
	}

	public byte[] generaReporteAmortizacionOK2(Integer anio) throws ExcelMapperException, IOException {

		byte[] fileExcel = null;
		List<MesesAmortizacionDTO> reporte = new ArrayList<MesesAmortizacionDTO>();
		MesesAmortizacionDTO meses = new MesesAmortizacionDTO();
		meses.setAcumulado(100.0);
		meses.setDescripcion("Descripcion");
		meses.setIdContrato(1L);
		meses.setMes1(1.0);
		meses.setMes2(2.0);
		meses.setMes3(3.0);
		meses.setMes4(4.0);
		meses.setMes5(5.0);
		reporte.add(meses);

		ExcelMapper mapper = excelMapperContext.getExcelMapper("mesesAmortizacion");

		for (int i = 1; i <= 12; i++) {
			String s = String.format(mapper.getRules().get(i).getHeader(), anio + i - 1);
			mapper.getRules().get(i).setHeader(s);
		}

		fileExcel = excelMapperTransform.transformObjectToExcel(reporte, mapper, MesesAmortizacionDTO.class);
		logger.info("" + fileExcel.length);
		return fileExcel;
	}

}
