package com.rjconsultores.ventaboletos.web.gui.controladores.tarifas;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import org.apache.log4j.Logger;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import org.zkoss.util.media.Media;
import org.zkoss.util.resource.Labels;
import org.zkoss.zhtml.Messagebox;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Executions;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zul.Filedownload;
import org.zkoss.zul.Radio;

import com.rjconsultores.ventaboletos.entidad.AliasServico;
import com.rjconsultores.ventaboletos.entidad.Parada;
import com.rjconsultores.ventaboletos.entidad.Ruta;
import com.rjconsultores.ventaboletos.exception.BusinessException;
import com.rjconsultores.ventaboletos.service.AliasServicoService;
import com.rjconsultores.ventaboletos.service.CorridaService;
import com.rjconsultores.ventaboletos.service.ParadaService;
import com.rjconsultores.ventaboletos.service.RutaService;
import com.rjconsultores.ventaboletos.utilerias.UsuarioLogado;
import com.rjconsultores.ventaboletos.web.utilerias.MyGenericForwardComposer;

@Controller("modificacionMasivaAliasUploadController")
@Scope("prototype")
public class ModificacionMasivaAliasUploadController extends MyGenericForwardComposer {

	private static final long serialVersionUID = 1L;

	private static final int CELL_ID_ALIAS_ORIGEM = 0;
	private static final int CELL_ID_ALIAS_DESTINO = 1;
	private static final int CELL_ID_ORIGEM = 2;
	private static final int CELL_ID_DESTINO = 3;
	private static final int CELL_ID_LINHA = 4;
	private static final int CELL_ID_CORRIDA = 5;
	private static final int CELL_ID_ALIAS = 6;

	private Media mExcel;
	private Radio rdAtualizarRegistros;

	private static Logger log = Logger.getLogger(ModificacionMasivaAliasUploadController.class);

	@Autowired
	private ParadaService paradaService;
	@Autowired
	private RutaService rutaService;
	@Autowired
	private CorridaService corridaService;
	@Autowired
	private AliasServicoService aliasServicoService;

	@Override
	public void doAfterCompose(Component comp) throws Exception {
		super.doAfterCompose(comp);
		mExcel = (Media) Executions.getCurrent().getArg().get("mExcel");
	}

	public void onClick$btnSalvar(Event ev) throws IOException, InterruptedException {
		atualizarCriarAlias(rdAtualizarRegistros.isChecked());
	}

	public void atualizarCriarAlias(Boolean atualizarExistentes) throws IOException, InterruptedException {

		log.debug("ModificaçãoMassivaAlias: atualizarCriarAlias");
		InputStream isMExcel = null;
		try {
			isMExcel = mExcel.getStreamData();
		} catch (IllegalStateException ex) {
			Messagebox.show(Labels.getLabel("modificacionMasivaAliasTarifasController.msg.formatoInvalido"),
					Labels.getLabel("modificacionMasivaAliasTarifasController.erro.title"),
					Messagebox.OK, Messagebox.ERROR);
			closeWindow();
			return;
		}
		Sheet sheet;
		if (mExcel.getFormat().equals("xls")) {
			HSSFWorkbook wb = new HSSFWorkbook(isMExcel);
			sheet = wb.getSheetAt(0);
		} else if (mExcel.getFormat().equals("xlsx")) {
			XSSFWorkbook wb = new XSSFWorkbook(isMExcel);
			sheet = wb.getSheetAt(0);
		} else {
			closeWindow();
			return;
		}

		int rows = sheet.getPhysicalNumberOfRows();
		List<AliasServico> aliasServicoToSave = new ArrayList<AliasServico>();
		StringBuilder erro = new StringBuilder();
		StringBuilder duplicados = new StringBuilder();
		int registrosAlterados = 0;

		if (!validaSheet(sheet)) {
			Messagebox.show(Labels.getLabel("modificacionMasivaAliasTarifasController.msg.planilhaInvalida"),
					Labels.getLabel("modificacionMasivaAliasTarifasController.erro.title"),
					Messagebox.OK, Messagebox.ERROR);
			closeWindow();
			return;
		}

		for (int r = 1; r < rows; r++) {
			Row row = sheet.getRow(r);

			if (row == null
					|| row.getCell(0) == null
					|| (row.getCell(0).getCellType() == Cell.CELL_TYPE_STRING && (row.getCell(0).getStringCellValue().isEmpty()))
					|| (row.getCell(0).getCellType() == Cell.CELL_TYPE_STRING && row.getCell(0).getStringCellValue().equalsIgnoreCase("id alias origem"))
					|| (row.getCell(0).getCellType() == Cell.CELL_TYPE_BLANK)) {
				continue;
			}

			StringBuilder erroEntidadeNaoExistente = new StringBuilder();
			Parada aliasOrigem = getParadaPorRow(row, CELL_ID_ALIAS_ORIGEM, erroEntidadeNaoExistente);
			Parada aliasDestino = getParadaPorRow(row, CELL_ID_ALIAS_DESTINO, erroEntidadeNaoExistente);
			Parada origem = getParadaPorRow(row, CELL_ID_ORIGEM, erroEntidadeNaoExistente);
			Parada destino = getParadaPorRow(row, CELL_ID_DESTINO, erroEntidadeNaoExistente);
			Ruta linha = getLinhaPorRow(row, erroEntidadeNaoExistente);
			Integer idCorrida = getCorridaPorRow(row);
			Integer idAliasServico = getIdAliasServicoPorRow(row, erroEntidadeNaoExistente);

			if (!erroEntidadeNaoExistente.toString().isEmpty()) {
				String descricaoErro = "Linha " + row.getRowNum() + ": \n";
				log.info("Erro: \n" + descricaoErro);

				erro.append(descricaoErro);
				erro.append(erroEntidadeNaoExistente.toString());
			} else {
				AliasServico aliasServico = criarAliasServico(aliasDestino, aliasOrigem, origem, destino, linha, idCorrida, idAliasServico);
				aliasServicoToSave.add(aliasServico);
			}
		}
		try {
			for (AliasServico aliasServico : aliasServicoToSave) {

				AliasServico existente = aliasServicoService.existe(aliasServico.getOrigen(), aliasServico.getDestino(),
						aliasServico.getRuta(), aliasServico.getCorridaId());
				if (existente != null) {
					if (aliasServico.getAliasServicoId() == null) {
						duplicados.append(Labels.getLabel("modificacionMasivaAliasTarifasController.msg.servicoExisteIdNull") + "\n" + getCampos(existente, Boolean.FALSE));
					} else {
						if (temAlteracao(aliasServico, existente) && atualizarExistentes) {
							salvar(aliasServico, Boolean.TRUE);
							registrosAlterados++;
						} else {
							duplicados.append(Labels.getLabel("modificacionMasivaAliasTarifasController.msg.servicoExiste") + " (" + aliasServico.getAliasServicoId() + ") \n");
						}
					}
					continue;
				}
				if (aliasServico.getAliasServicoId() == null) {
					salvar(aliasServico, Boolean.TRUE);
				}
				else {
					if (atualizarExistentes) {
						salvar(aliasServico, Boolean.FALSE);
					} else {
						log.info("Registro não atualizado: " + aliasServico.getAliasServicoId());
						continue;
					}
				}
				registrosAlterados++;
			}
		} catch (BusinessException e) {
			e.printStackTrace();
		}

		String nomeArquivo = UsuarioLogado.getUsuarioLogado().getNombusuario()
				+ "_" + Calendar.getInstance().getTime().getTime()
				+ "_" + "retorno";
		File fNomeArquivo = File.createTempFile(nomeArquivo, ".tmp");
		FileOutputStream fos = new FileOutputStream(fNomeArquivo);

		StringBuilder textoFinal = new StringBuilder();
		textoFinal.append(registrosAlterados + " ");
		textoFinal.append(Labels.getLabel("modificacionMasivaAliasTarifasController.msg.registroSalvos") + "\n\n");

		if (!erro.toString().isEmpty()) {
			textoFinal.append("--------------- ERRORS ----------------\n");
			textoFinal.append(erro.toString());
			textoFinal.append("\n---------------------------------------\n");
		}

		if (!duplicados.toString().isEmpty()) {
			textoFinal.append("--------------- DUPLICADO ----------------\n");
			textoFinal.append(duplicados.toString());
			textoFinal.append("\n---------------------------------------");
		}

		fos.write(textoFinal.toString().getBytes());
		fos.close();

		InputStream is = null;
		is = new FileInputStream(fNomeArquivo);
		Filedownload.save(is, "application/txt", "RetornoModMasivaAlias.txt");
		fNomeArquivo.delete();
		closeWindow();
	}

	private boolean temAlteracao(AliasServico aliasServico, AliasServico existente) {

		if ((
				(aliasServico.getAliasDestino() == null && existente.getAliasDestino() == null)
				||
				(aliasServico.getAliasDestino().equals(existente.getAliasDestino()))
				)
				&&
				(
				(aliasServico.getAliasOrigen() == null && existente.getAliasOrigen() == null)
				||
				(aliasServico.getAliasOrigen().equals(existente.getAliasOrigen()))
				)
				&&
				(
				(aliasServico.getOrigen() == null && existente.getOrigen() == null)
				||
				(aliasServico.getOrigen().equals(existente.getOrigen()))
				)
				&&
				(
				(aliasServico.getDestino() == null && existente.getDestino() == null)
				||
				(aliasServico.getDestino().equals(existente.getDestino()))
				)
				&&
				(
				(aliasServico.getRuta() == null && existente.getRuta() == null)
				||
				(aliasServico.getRuta().equals(existente.getRuta()))
				)
				&&
				(
				(aliasServico.getCorridaId() == null && existente.getCorridaId() == null)
				||
				(aliasServico.getCorridaId().equals(existente.getCorridaId()))
				)) {
			return false;
		}
		return true;
	}

	private String getCampos(AliasServico aliasServico, Boolean exibirId) {
		return exibirId ? (Labels.getLabel("modificacionMasivaAliasTarifasController.lblAlias" + " - " + aliasServico.getAliasServicoId()) + "\n") : ""
				+ Labels.getLabel("modificacionMasivaAliasTarifasController.lblAliasOrigem") + "-" + aliasServico.getAliasOrigen().getParadaId() + "\n"
				+ Labels.getLabel("modificacionMasivaAliasTarifasController.lblAliasDestino") + "-" + aliasServico.getAliasDestino().getParadaId() + "\n"
				+ Labels.getLabel("modificacionMasivaAliasTarifasController.lblOrigem") + "-" + aliasServico.getOrigen().getParadaId() + "\n"
				+ Labels.getLabel("modificacionMasivaAliasTarifasController.lblDestino") + "-" + aliasServico.getDestino().getParadaId() + "\n"
				+ Labels.getLabel("modificacionMasivaAliasTarifasController.lblLinha") + "-" + aliasServico.getRuta().getRutaId() + "\n"
				+ Labels.getLabel("modificacionMasivaAliasTarifasController.lblCorrida") + "-" + aliasServico.getCorridaId() + "\n";
	}

	private void salvar(AliasServico aliasServico, Boolean isNew) throws BusinessException {
		aliasServicoService.suscribirActualizar(aliasServico);
		log.info("Registro " + (isNew ? "Novo" : "Atualizado: ") + "\n" + getCampos(aliasServico, Boolean.TRUE));
	}

	private AliasServico criarAliasServico(Parada aliasDestino, Parada aliasOrigem, Parada origem, Parada destino, Ruta linha, Integer idCorrida, Integer idAliasServico) {
		AliasServico aliasServico = new AliasServico();
		if (idAliasServico != null && idAliasServico != 0) {
			aliasServico.setAliasServicoId(idAliasServico);
		}
		aliasServico.setActivo(Boolean.TRUE);
		aliasServico.setAliasDestino(aliasDestino);
		aliasServico.setAliasOrigen(aliasOrigem);
		aliasServico.setCorridaId(idCorrida);
		aliasServico.setDestino(destino);
		aliasServico.setOrigen(origem);
		aliasServico.setFecmodif(new Date());
		aliasServico.setRuta(linha);
		aliasServico.setUsuarioId(UsuarioLogado.getUsuarioLogado().getUsuarioId());
		return aliasServico;
	}

	private Parada getParadaPorRow(Row row, int numeroCell, StringBuilder erro) {
		Cell cell = row.getCell(numeroCell);
		String nome = getNomeCell(numeroCell);

		if (cell == null) {
			erro.append("Coluna '" + nome + "' da linha " + row.getRowNum() + " está vazia.");
			return null;
		}

		BigDecimal bdId = new BigDecimal(cell.getNumericCellValue());
		Integer idParada = bdId.intValue();
		Parada parada = paradaService.obtenerID(idParada);
		if (parada == null) {
			erro.append(nome + " : " + idParada + " não existe.\n");
		}
		return parada;
	}

	private Ruta getLinhaPorRow(Row row, StringBuilder erro) {
		Cell cell = row.getCell(CELL_ID_LINHA);
		String nome = getNomeCell(CELL_ID_LINHA);
		if (cell == null) {
			erro.append("Coluna '" + nome + "' da linha " + row.getRowNum() + " está vazia.");
			return null;
		}
		BigDecimal bdId = new BigDecimal(cell.getNumericCellValue());
		Integer idLinha = bdId.intValue();
		Ruta linha = rutaService.obtenerID(idLinha);
		if (linha == null) {
			erro.append(nome + " : " + idLinha + " não existe.\n");
		}
		return linha;
	}

	private Integer getCorridaPorRow(Row row) {
		Cell cell = row.getCell(CELL_ID_CORRIDA);
		if (cell.toString() == null || cell.toString().isEmpty()) {
			return null;
		}
		BigDecimal bdId = new BigDecimal(cell.getStringCellValue());
		return bdId.intValue();
	}

	private Integer getIdAliasServicoPorRow(Row row, StringBuilder erro) {
		Cell cell = row.getCell(CELL_ID_ALIAS);

		if (cell == null || cell.toString() == null || cell.toString().isEmpty()) {
			return null;
		}
		BigDecimal bdId = new BigDecimal(cell.toString());
		Integer idAliasServico = bdId.intValue();
		if (aliasServicoService.obtenerID(idAliasServico) == null) {
			String nome = getNomeCell(CELL_ID_LINHA);
			erro.append(nome + " : " + idAliasServico + " não existe.\n");
			return null;
		}
		return idAliasServico;
	}

	private String getNomeCell(int num) {
		String nome = "";
		switch (num) {
		case 0:
			nome = Labels.getLabel("modificacionMasivaAliasTarifasController.lblAliasOrigem");
			break;
		case 1:
			nome = Labels.getLabel("modificacionMasivaAliasTarifasController.lblAliasDestino");
			break;
		case 2:
			nome = Labels.getLabel("modificacionMasivaAliasTarifasController.lblOrigem");
			break;
		case 3:
			nome = Labels.getLabel("modificacionMasivaAliasTarifasController.lblDestino");
			break;
		case 4:
			nome = Labels.getLabel("modificacionMasivaAliasTarifasController.lblLinha");
			break;
		case 5:
			nome = Labels.getLabel("modificacionMasivaAliasTarifasController.lblCorrida");
			break;
		case 6:
			nome = Labels.getLabel("modificacionMasivaAliasTarifasController.lblAlias");
			break;
		}
		return nome;
	}

	public Media getmExcel() {
		return mExcel;
	}

	public void setmExcel(Media mExcel) {
		this.mExcel = mExcel;
	}

	private Boolean validaSheet(Sheet sheet) {

		Row header = sheet.getRow(0);

		Cell cell0 = header.getCell(CELL_ID_ALIAS_ORIGEM);
		Cell cell1 = header.getCell(CELL_ID_ALIAS_DESTINO);
		Cell cell2 = header.getCell(CELL_ID_ORIGEM);
		Cell cell3 = header.getCell(CELL_ID_DESTINO);
		Cell cell4 = header.getCell(CELL_ID_LINHA);
		Cell cell5 = header.getCell(CELL_ID_CORRIDA);
		Cell cell6 = header.getCell(CELL_ID_ALIAS);

		if (cell0 == null
				|| cell1 == null
				|| cell2 == null
				|| cell3 == null
				|| cell4 == null
				|| cell5 == null
				|| cell6 == null
				|| !cell0.toString().equals(getNomeCell(CELL_ID_ALIAS_ORIGEM))
				|| !cell1.toString().equals(getNomeCell(CELL_ID_ALIAS_DESTINO))
				|| !cell2.toString().equals(getNomeCell(CELL_ID_ORIGEM))
				|| !cell3.toString().equals(getNomeCell(CELL_ID_DESTINO))
				|| !cell4.toString().equals(getNomeCell(CELL_ID_LINHA))
				|| !cell5.toString().equals(getNomeCell(CELL_ID_CORRIDA))
				|| !cell6.toString().equals(getNomeCell(CELL_ID_ALIAS))) {
			return false;
		}

		return true;
	}

}
