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

import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import org.zkoss.util.resource.Labels;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zul.Combobox;
import org.zkoss.zul.Div;
import org.zkoss.zul.Messagebox;
import org.zkoss.zul.Radio;

import com.rjconsultores.ventaboletos.constantes.Constantes;
import com.rjconsultores.ventaboletos.entidad.CasetaPeaje;
import com.rjconsultores.ventaboletos.entidad.Constante;
import com.rjconsultores.ventaboletos.entidad.EmpresaImposto;
import com.rjconsultores.ventaboletos.entidad.OrgaoConcedente;
import com.rjconsultores.ventaboletos.entidad.Ruta;
import com.rjconsultores.ventaboletos.entidad.RutaCaseta;
import com.rjconsultores.ventaboletos.entidad.RutaEmpresa;
import com.rjconsultores.ventaboletos.entidad.RutaSecuencia;
import com.rjconsultores.ventaboletos.service.CalcularPeajeService;
import com.rjconsultores.ventaboletos.service.CasetaPeajeService;
import com.rjconsultores.ventaboletos.service.ConstanteService;
import com.rjconsultores.ventaboletos.service.EmpresaImpostoService;
import com.rjconsultores.ventaboletos.service.OrgaoConcedenteService;
import com.rjconsultores.ventaboletos.service.RutaService;
import com.rjconsultores.ventaboletos.utilerias.UsuarioLogado;
import com.rjconsultores.ventaboletos.web.utilerias.MyGenericForwardComposer;
import com.rjconsultores.ventaboletos.web.utilerias.MyListbox;

@Controller("calcularPeajeController")
@Scope("prototype")
public class CalcularPeajeController extends MyGenericForwardComposer {

	private static final long serialVersionUID = 1L;

	@Autowired
	private OrgaoConcedenteService orgaoConcedenteService;
	@Autowired
	private RutaService rutaService;
	@Autowired
	private CalcularPeajeService calcularPeajeService;
	@Autowired
	private EmpresaImpostoService empresaImpostoService;
	@Autowired
	private CasetaPeajeService casetaPeajeService;
	@Autowired
	private ConstanteService constanteService;

	private Combobox cmbOrgaoConcedente;
	private List<OrgaoConcedente> lsOrgaoConcedente;

	private Radio rdConsiderarICMSNo;
	private Radio rdConsiderarICMSSi;

	private Combobox cmbRuta;
	private List<Ruta> listSelectedRutas;
	private MyListbox selectedRutasList;
	private List<Ruta> lsRutas;
	private Combobox cmbCasetaPeaje;
	private List<CasetaPeaje> listSelectedCasetaPeaje;
	private MyListbox selectedCasetaPeajeList;
	private List<CasetaPeaje> lsCasetaPeaje;
	Set<Integer> lsIdsOrgSemIndice = new HashSet<Integer>();
    private Div casetaPeajeDiv;	
	public static final String FILTRAR_POR_PRACA_DE_PEDAGIO = "FILTRAR_POR_PRACA_DE_PEDAGIO";

	public List<OrgaoConcedente> getLsOrgaoConcedente() {
		return lsOrgaoConcedente;
	}

	public void setLsOrgaoConcedente(List<OrgaoConcedente> lsOrgaoConcedente) {
		this.lsOrgaoConcedente = lsOrgaoConcedente;
	}

	public Combobox getCmbOrgaoConcedente() {
		return cmbOrgaoConcedente;
	}

	public void setCmbOrgaoConcedente(Combobox cmbOrgaoConcedente) {
		this.cmbOrgaoConcedente = cmbOrgaoConcedente;
	}

	@Override
	public void doAfterCompose(Component comp) throws Exception {

		super.doAfterCompose(comp);

		lsOrgaoConcedente = new ArrayList<OrgaoConcedente>();
		for (Integer orgaoConcedenteId : Constantes.ORGAOS_CONCEDENTES_CALCULO_ANTT) {
			adicionaNaListaOrgaoConcedente(orgaoConcedenteId);
		}
		for (Integer orgaoConcedenteId : Constantes.ORGAOS_CONCEDENTES_CALCULO_ARTESP) {
			adicionaNaListaOrgaoConcedente(orgaoConcedenteId);
		}
		for (Integer orgaoConcedenteId : Constantes.ORGAOS_CONCEDENTES_CALCULO_AGER) {
			adicionaNaListaOrgaoConcedente(orgaoConcedenteId);
		}
		lsRutas = rutaService.buscarRutasPorEmpresas(UsuarioLogado.getUsuarioLogado().getEmpresa());
		listSelectedRutas = new ArrayList<Ruta>();
		lsCasetaPeaje = casetaPeajeService.buscarTodosOrdenadoPorDescricao();
		listSelectedCasetaPeaje = new ArrayList<CasetaPeaje>();
		casetaPeajeDiv.setVisible(buscarContantefiltrarPorPracaDePedagio());
	}

	public void onClick$btnCalcularPeaje(Event ev) throws InterruptedException {
		OrgaoConcedente orgao = null;
		boolean orgaoListaRutasHasIndices = true;			
		if(!validaSeTodasAsRutasPossuiPeloMenosUmaSecuenciaComApracaDePedagio()) {			
			return;
		};		
		if (!listSelectedRutas.isEmpty()) {
			orgao = null;
			for (Ruta r : listSelectedRutas) {	
				if (r.getOrgaoConcedente().getIndicePeaje() == null) {
					orgaoListaRutasHasIndices = false;
					lsIdsOrgSemIndice.add(r.getOrgaoConcedente().getOrgaoConcedenteId());
				}
			}
		} else if(cmbOrgaoConcedente.getSelectedItem()!= null) {
			orgao = ((OrgaoConcedente) cmbOrgaoConcedente.getSelectedItem().getValue());
		}

		if ((orgao != null && orgao.getIndicePeaje() != null) || (!listSelectedRutas.isEmpty() && orgaoListaRutasHasIndices) || (!listSelectedCasetaPeaje.isEmpty() && orgaoListaRutasHasIndices)) {

			List<Ruta> lsRuta;
			if (!listSelectedRutas.isEmpty()) {
				lsRuta = listSelectedRutas;
			} else if (!listSelectedCasetaPeaje.isEmpty()){
				lsRuta=rutaService.buscarPorOrgaoEcasetaPeaje(orgao,converterLiistDeCasetaPeajeEmArrayDeCasetaPeaje(listSelectedCasetaPeaje));				
				orgao = null;
				List<Ruta> lsRutaAux = new ArrayList<Ruta>();
				lsRutaAux.addAll(lsRuta);
				for (Ruta r : lsRutaAux) {	
					if (r.getOrgaoConcedente().getIndicePeaje() == null) {
						lsRuta.remove(r);
					}
				}
				
				if(!lsRutaAux.isEmpty() && lsRuta.isEmpty() ) {
					lsIdsOrgSemIndice.add(lsRutaAux.get(0).getOrgaoConcedente().getOrgaoConcedenteId());
					retornoDoErro(orgao);
					return;
				}
			}
			else {
				lsRuta = rutaService.buscaRutasFromOrgao(orgao);
			}
			boolean usarICMS;
			if (rdConsiderarICMSSi.isChecked()) {
				usarICMS = true;
			} else {
				usarICMS = false;
			}
			if (!validarImpostoICMSEmpresa(lsRuta) && usarICMS) {
				Messagebox.show("Foram encontradas empresas com ICMS nulo, o cálculo não poderá ser realizado.",
						Labels.getLabel("indexController.mniCalculoPeaje.label"), Messagebox.OK, Messagebox.ERROR);

				return;
			}

			try {

				calcularPeajeService.gerarSQLInserirPeajes(lsRuta, orgao, usarICMS,converterLiistDeCasetaPeajeEmArrayDeCasetaPeaje(listSelectedCasetaPeaje));

				Messagebox.show(Labels.getLabel("calcularPeajeController.MSG.suscribirOK"),
						Labels.getLabel("indexController.mniCalculoPeaje.label"), Messagebox.OK, Messagebox.INFORMATION);
			} catch (RuntimeException e) {
				// TODO throw: especific exception should be created

				if (e.getMessage().trim().length() > 0) {

					String error[] = e.getMessage().split(";");
					if (error.length == 2) {
						String type = error[0];
						String ruta = error[1];

						if ("rutaSemQtdEixos".equals(type)) {
							Messagebox.show(
									Labels.getLabel("calcularPeajeController.MSG.rutaSemQtdEixos", new Object[] { ruta }),
									Labels.getLabel("indexController.mniCalculoPeaje.label"), Messagebox.NO, Messagebox.ERROR);
						} else if ("rutaSemQtdAsientos".equals(type)) {
							Messagebox.show(
									Labels.getLabel("calcularPeajeController.MSG.rutaSemQtdAsientos", new Object[] { ruta }),
									Labels.getLabel("indexController.mniCalculoPeaje.label"), Messagebox.NO, Messagebox.ERROR);
						}

					} else {
						Messagebox.show(
								Labels.getLabel("MSG.Error"),
								Labels.getLabel("indexController.mniCalculoPeaje.label"), Messagebox.NO, Messagebox.ERROR);
					}
				} else {
					e.printStackTrace();
				}
				// TODO else: show some generic error for unexpected error
			} catch (Exception e) {
				Messagebox.show(
						"A empresa " + e.getMessage() + " não possui ICMS cadastrado.",
						Labels.getLabel("indexController.mniCalculoPeaje.label"), Messagebox.NO, Messagebox.ERROR);
			}
		} else {
			retornoDoErro(orgao);

		}
	}

	private void retornoDoErro(OrgaoConcedente orgao) throws InterruptedException {
		if (orgao != null) {
			Messagebox.show(
					Labels.getLabel("calcularPeajeController.MSG.orgaoSemIndice", new Object[] { orgao.getOrgaoConcedenteId() }),
					Labels.getLabel("indexController.mniCalculoPeaje.label"), Messagebox.NO, Messagebox.ERROR);
		} else {
			Messagebox.show(
					Labels.getLabel("calcularPeajeController.MSG.orgaoSemIndice", new Object[] { retornaIdsOrgaoSemIndice(lsIdsOrgSemIndice) }),
					Labels.getLabel("indexController.mniCalculoPeaje.label"), Messagebox.NO, Messagebox.ERROR);
		}
	}

	private Boolean validaSeTodasAsRutasPossuiPeloMenosUmaSecuenciaComApracaDePedagio() throws InterruptedException {
		if (!listSelectedCasetaPeaje.isEmpty() && !listSelectedRutas.isEmpty()) {
			List<Ruta> lsRutaAuxiliar = new ArrayList<Ruta>();	
			retornarApenasRutaQuePossuiSecuenciasComAsPracas(lsRutaAuxiliar);
			for (Ruta ruta : listSelectedRutas) {
				if (!lsRutaAuxiliar.contains(ruta)) {
					Messagebox.show(Labels.getLabel("calcularPeajeController.MSG.linhaSemPracaDePedagio", new Object[] { ruta }),
							Labels.getLabel("indexController.mniCalculoPeaje.label"), Messagebox.OK, Messagebox.ERROR);
					return false;
				}
			}
		}
		return true;
	}

	private void retornarApenasRutaQuePossuiSecuenciasComAsPracas(List<Ruta> lsRutaAuxiliar) {
		List<Ruta> listSelectedRutasAux = recarregarAsRutasComBanco(listSelectedRutas);
		for (CasetaPeaje casetaPeaje : listSelectedCasetaPeaje) {
				for (Ruta r : listSelectedRutasAux) {
					if (!r.getRutaSecuenciaList().isEmpty()) {
						Boolean isRutaSecuencia = false;
						for (RutaSecuencia rutaSecuencia : r.getRutaSecuenciaList()) {
							if (isRutaSecuencia)
								break;
							if (rutaSecuencia.getActivo()) {
								for (RutaCaseta rutaCaseta : rutaSecuencia.getLsRutaCase()) {
									if (rutaCaseta.getActivo() && rutaCaseta.getCasetaPeaje().getCasetaPeajeId().intValue() == casetaPeaje.getCasetaPeajeId().intValue()) {
										lsRutaAuxiliar.add(r);
										isRutaSecuencia = true;
										break;
									}
								}
							}
						}
					}
				}
			}
		}
	
	
	List<Ruta> recarregarAsRutasComBanco(List<Ruta> lsRutasSelecionadas){	
		List<Integer> lsRutaIds=retornarListRutaIds(lsRutasSelecionadas);
		Integer[] arrayDeRutaIds = converteListIdsEmArrayIds(lsRutaIds);
		return rutaService.buscarPorIds(arrayDeRutaIds);		
	}

	private Integer[] converteListIdsEmArrayIds(List<Integer> ids) {		
		Integer[] arrayIds = new Integer[ids.size()]; 
		arrayIds = ids.toArray(arrayIds);
		return arrayIds;
	}
	
		private List<Integer> retornarListRutaIds(List<Ruta> lsRutasSelecionadas) {
		List<Integer> listRutasId = new ArrayList<Integer>();
		for (Ruta r : lsRutasSelecionadas) {
			listRutasId.add(r.getRutaId());
		}
		return listRutasId;
	}
		
	private Integer[] converterLiistDeCasetaPeajeEmArrayDeCasetaPeaje(List<CasetaPeaje> lsCasetaPeaje) {
		if(!lsCasetaPeaje.isEmpty()) {
			return converteListIdsEmArrayIds(retornarListCasetaPeajeIds(lsCasetaPeaje));
		}
		return null;
	}
	
	private List<Integer> retornarListCasetaPeajeIds(List<CasetaPeaje> lsCasetaPeaje) {
		List<Integer> listCasetaPeaje= new ArrayList<Integer>();
		for (CasetaPeaje c : lsCasetaPeaje) {
			listCasetaPeaje.add(c.getCasetaPeajeId());
		}
		return listCasetaPeaje;
	}
	

	private String retornaIdsOrgaoSemIndice(Set<Integer> s) {
		List l = new ArrayList<Integer>(s);
		if (l.size() == 1) {
			return l.get(0).toString();
		} else {
			StringBuilder sb = new StringBuilder();
			sb.append(l.get(0).toString());
			for (int x = 1; x < l.size(); x++) {
				sb.append(", " + l.get(x).toString());
			}
			return sb.toString();
		}
	}

	private boolean validarImpostoICMSEmpresa(List<Ruta> lsRuta) {
		Set<Integer> lsEmpresaId = new LinkedHashSet<Integer>();

		for (Ruta ruta : lsRuta) {
			for (RutaEmpresa rutaEmpresa : ruta.getLsRutaEmpresa()) {
				if (lsEmpresaId.contains(rutaEmpresa.getEmpresa().getEmpresaId())) {
					continue;
				}

				lsEmpresaId.add(rutaEmpresa.getEmpresa().getEmpresaId());
			}
		}

		for (Integer empresaId : lsEmpresaId) {
			for (EmpresaImposto empresaImposto : empresaImpostoService.buscarEmpresaImposto(empresaId)) {
				if (empresaImposto.getIcms() == null) {
					return false;
				}
			}
		}

		return true;
	}

	public void onClick$btnAddRuta(Event ev) throws InterruptedException {
		if (cmbRuta.getSelectedItem() != null) {
			listSelectedRutas.add((Ruta) cmbRuta.getSelectedItem().getValue());
			selectedRutasList.setData(listSelectedRutas);
			cmbRuta.setSelectedItem(null);
		}
	}
	
	public void onClick$btnAddCasetaPeaje(Event ev) throws InterruptedException {
		if (cmbCasetaPeaje.getSelectedItem() != null) {
			listSelectedCasetaPeaje.add((CasetaPeaje) cmbCasetaPeaje.getSelectedItem().getValue());
			selectedCasetaPeajeList.setData(listSelectedCasetaPeaje);
			cmbCasetaPeaje.setSelectedItem(null);
		}
	}
	
	public void onClick$btnRemoveCasetaPeaje(Event ev) throws InterruptedException {
		CasetaPeaje  casetaPeaje= (CasetaPeaje) selectedCasetaPeajeList.getSelected();
		listSelectedCasetaPeaje.remove(casetaPeaje);
		selectedCasetaPeajeList.setData(listSelectedCasetaPeaje);
	}

	public void onClick$btnRemoveRuta(Event ev) throws InterruptedException {
		Ruta ruta = (Ruta) selectedRutasList.getSelected();
		listSelectedRutas.remove(ruta);
		selectedRutasList.setData(listSelectedRutas);
	}
	
	private void adicionaNaListaOrgaoConcedente(Integer orgaoConcedenteId) {
		OrgaoConcedente concedente = orgaoConcedenteService.obtenerID(orgaoConcedenteId);
		// Mantis 16425 - NullPointerException
		if (concedente != null && concedente.getActivo()) {
			lsOrgaoConcedente.add(concedente);
		}
	}

	public Combobox getCmbRuta() {
		return cmbRuta;
	}

	public void setCmbRuta(Combobox cmbRuta) {
		this.cmbRuta = cmbRuta;
	}

	public List<Ruta> getListSelectedRutas() {
		return listSelectedRutas;
	}

	public void setListSelectedRutas(List<Ruta> listSelectedRutas) {
		this.listSelectedRutas = listSelectedRutas;
	}

	public MyListbox getSelectedRutasList() {
		return selectedRutasList;
	}

	public void setSelectedRutasList(MyListbox selectedRutasList) {
		this.selectedRutasList = selectedRutasList;
	}

	public List<Ruta> getLsRutas() {
		return lsRutas;
	}

	public void setLsRutas(List<Ruta> lsRutas) {
		this.lsRutas = lsRutas;
	}

	public Combobox getCmbCasetaPeaje() {
		return cmbCasetaPeaje;
	}

	public void setCmbCasetaPeaje(Combobox cmbCasetaPeaje) {
		this.cmbCasetaPeaje = cmbCasetaPeaje;
	}

	public List<CasetaPeaje> getListSelectedCasetaPeaje() {
		return listSelectedCasetaPeaje;
	}

	public void setListSelectedCasetaPeaje(List<CasetaPeaje> listSelectedCasetaPeaje) {
		this.listSelectedCasetaPeaje = listSelectedCasetaPeaje;
	}

	public List<CasetaPeaje> getLsCasetaPeaje() {
		return lsCasetaPeaje;
	}

	public void setLsCasetaPeaje(List<CasetaPeaje> lsCasetaPeaje) {
		this.lsCasetaPeaje = lsCasetaPeaje;
	}
	
	

	private Boolean buscarContantefiltrarPorPracaDePedagio() {
		Constante constante = constanteService.buscarPorNomeConstante(FILTRAR_POR_PRACA_DE_PEDAGIO);
		if (constante != null) {
			if(constante.getValorconstante().equalsIgnoreCase("true")) {
				return true;
			}
		}
		return false;
		
	}
	

}
