package com.rjconsultores.ventaboletos.service.impl;

import java.math.BigDecimal;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.zkoss.util.resource.Labels;

import com.rjconsultores.ventaboletos.dao.GP_PricingOcupaAntecipaDAO;
import com.rjconsultores.ventaboletos.entidad.GP_Pricing;
import com.rjconsultores.ventaboletos.entidad.GP_PricingOcupaAntecipa;
import com.rjconsultores.ventaboletos.exception.BusinessException;
import com.rjconsultores.ventaboletos.service.GP_PricingOcupaAntecipaService;
import com.rjconsultores.ventaboletos.utilerias.TraslaparUtil;
import com.rjconsultores.ventaboletos.utilerias.UsuarioLogado;
import com.rjconsultores.ventaboletos.vo.pricing.GP_PricingOcupaAntecipaLegendaVO;
import com.rjconsultores.ventaboletos.vo.pricing.GP_PricingOcupaAntecipaLegendaVO.GP_PricingOcupaAtencipaLegendaItemVO;
import com.rjconsultores.ventaboletos.vo.pricing.GP_PricingOcupaAntecipaPoltronasVO;
import com.rjconsultores.ventaboletos.vo.pricing.GP_PricingOcupaAntecipaVO;

@Service("gp_pricingOcupacionService")
public class GP_PricingOcupaAntecipaServiceImpl implements GP_PricingOcupaAntecipaService {

	private static final Logger log = LogManager.getLogger(GP_PricingOcupaAntecipaServiceImpl.class);

	@Autowired
	private GP_PricingOcupaAntecipaDAO pricingOcupacionDAO;

	@Transactional
	public GP_PricingOcupaAntecipa suscribir(GP_PricingOcupaAntecipa entidad) throws BusinessException {
		traslapa(entidad);
		entidad.setUsuarioId(UsuarioLogado.getUsuarioLogado().getUsuarioId());
		entidad.setFecmodif(Calendar.getInstance().getTime());
		entidad.setActivo(GP_Pricing.ATIVO);

		return pricingOcupacionDAO.suscribir(entidad);
	}

	@Transactional(rollbackFor = BusinessException.class)
	public GP_PricingOcupaAntecipa actualizacion(GP_PricingOcupaAntecipa entidad) throws BusinessException {
		traslapa(entidad);
		entidad.setUsuarioId(UsuarioLogado.getUsuarioLogado().getUsuarioId());
		entidad.setFecmodif(Calendar.getInstance().getTime());
		entidad.setActivo(GP_Pricing.ATIVO);

		return pricingOcupacionDAO.actualizacion(entidad);
	}

	@Transactional
	public void borrar(GP_PricingOcupaAntecipa entidad) {
		entidad.setUsuarioId(UsuarioLogado.getUsuarioLogado().getUsuarioId());
		entidad.setFecmodif(Calendar.getInstance().getTime());
		entidad.setActivo(GP_Pricing.EXCLUIDO);

		pricingOcupacionDAO.actualizacion(entidad);
	}
	
	public List<GP_PricingOcupaAntecipa> updateList(GP_PricingOcupaAntecipa pricingOcupaAntecipa) {
		List<GP_PricingOcupaAntecipa> lsSalvos = pricingOcupacionDAO.buscarOcupaAntecipaPricing(pricingOcupaAntecipa.getPricing().getPricingId());
		return lsSalvos;
	}

	private void traslapa(GP_PricingOcupaAntecipa pricingOcupaAntecipa) throws BusinessException {
				
		List<GP_PricingOcupaAntecipa> lsSalvos = pricingOcupacionDAO.buscarOcupaAntecipaPricing(pricingOcupaAntecipa.getPricing().getPricingId());

		// removo o pricing que eu estou validando
		lsSalvos.remove(pricingOcupaAntecipa);
		
		BigDecimal cantocupaini = pricingOcupaAntecipa.getOcupacioninicial();
		BigDecimal cantocupafin = pricingOcupaAntecipa.getOcupacionfinal();
		
		boolean validaCantPorcentaje = ((cantocupaini != null) && (cantocupafin != null));

		Integer cantasientosmin = pricingOcupaAntecipa.getCantasientosmin();
		Integer cantasientosmax = pricingOcupaAntecipa.getCantasientosmax();

		boolean validaCantAsientos = ((cantasientosmin != null) && (cantasientosmax != null));

		Integer cantdiasmin = pricingOcupaAntecipa.getCantdiasmin();
		Integer cantdiasmax = pricingOcupaAntecipa.getCantdiasmax();

		boolean validaCantDias = ((cantdiasmin != null) && (cantdiasmax != null));

		for (GP_PricingOcupaAntecipa poa : lsSalvos) {
			boolean traslapaCantPorcentaje = false;
			if (validaCantPorcentaje) {
				if ((poa.getOcupacioninicial() != null) && (poa.getOcupacionfinal() != null)) {
					traslapaCantPorcentaje = TraslaparUtil.intersectNum(poa.getOcupacioninicial(), poa.getOcupacionfinal(), cantocupaini, cantocupafin);
				}
			}
			
			boolean traslapaCantAsiento = false;
			if (validaCantAsientos) {
				if ((poa.getCantasientosmin() != null) && (poa.getCantasientosmax() != null)) {
					traslapaCantAsiento = TraslaparUtil.intersectNum(poa.getCantasientosmin(), poa.getCantasientosmax(), cantasientosmin, cantasientosmax);
				}
			}

			boolean traslapaCantDias = false;
			if (validaCantDias) {
				if ((poa.getCantdiasmin() != null) && (poa.getCantdiasmax() != null)) {
					traslapaCantDias = TraslaparUtil.intersectNum(poa.getCantdiasmin(), poa.getCantdiasmax(), cantdiasmin, cantdiasmax);
				}
			}			

			if ((traslapaCantPorcentaje || traslapaCantAsiento ) && traslapaCantDias  ){
				List<String> args = new ArrayList<String>();
				String dias = poa.getCantdiasmin() + "-" + poa.getCantdiasmax();
				args.add(dias);
				String faixa = null;
				if(traslapaCantPorcentaje) {
					faixa = poa.getOcupacioninicial() + "-" + poa.getOcupacionfinal();
				}
				if(traslapaCantAsiento) {
					faixa = poa.getCantasientosmin() + "-" + poa.getCantasientosmax();
				}
				args.add(faixa);
				log.info("registro que traslapa PricingOcupaAntecipa id =" + poa.getPricingocupaantecipaId());
				throw new BusinessException("pricingOcupaAntecipaServiceImpl.msg.traslapa", args.toArray());
			}
			
		}

	}

	@Override
	public List<GP_PricingOcupaAntecipaVO> carregarPricingOcupaAntecipaVO(Integer pricingId) {
		List<GP_PricingOcupaAntecipa> pricingOcupaAntecipas = carregarPricingOcupaAntecipa(pricingId);
		return carregarPricingOcupaAntecipaVO(pricingOcupaAntecipas);
	}

	@Override
	public List<GP_PricingOcupaAntecipaVO> carregarPricingOcupaAntecipaVO(List<GP_PricingOcupaAntecipa> pricingOcupaAntecipas) {
		List<GP_PricingOcupaAntecipaVO> aux = new ArrayList<GP_PricingOcupaAntecipaVO>();
		
		for (GP_PricingOcupaAntecipa ocupacaoAntecipa: pricingOcupaAntecipas) {
			Integer cantdiasmax = ocupacaoAntecipa.getCantdiasmax() != null ? ocupacaoAntecipa.getCantdiasmax() : GP_PricingOcupaAntecipaVO.CANTDIASMAXDEFAULT;
			GP_PricingOcupaAntecipaVO ocupacao = new GP_PricingOcupaAntecipaVO();
			
			ocupacao.setPricingocupaantecipaId(ocupacaoAntecipa.getPricingocupaantecipaId());
			ocupacao.setDias(ocupacaoAntecipa.getCantdiasmin() + "-" + cantdiasmax);
			ocupacao.setDiaMin(ocupacaoAntecipa.getCantdiasmin());
			int linhaMax = cantdiasmax.equals(GP_PricingOcupaAntecipaVO.CANTDIASMAXDEFAULT) ? ocupacaoAntecipa.getCantdiasmin() + 10 : cantdiasmax;
			if(linhaMax > GP_PricingOcupaAntecipaVO.CANTDIASMAXDEFAULT) {
				linhaMax = GP_PricingOcupaAntecipaVO.CANTDIASMAXDEFAULT;
			}
			
			ocupacao.setDiaMax(linhaMax);
			
			if(ocupacaoAntecipa.getOcupacioninicial() != null && ocupacaoAntecipa.getOcupacionfinal() != null) {
				ocupacao.setOcupMin(ocupacaoAntecipa.getOcupacioninicial().intValue());
				ocupacao.setOcupMax(ocupacaoAntecipa.getOcupacionfinal().intValue());
			} else if(ocupacaoAntecipa.getCantasientosmin() != null && ocupacaoAntecipa.getCantasientosmax() != null) {
				ocupacao.setOcupMin(ocupacaoAntecipa.getCantasientosmin().intValue());
				ocupacao.setOcupMax(ocupacaoAntecipa.getCantasientosmax().intValue());
			}
			ocupacao.setCor(ocupacaoAntecipa.getCor());
			ocupacao.setPercentual(ocupacaoAntecipa.getPorcentaje());
			
			ocupacao.marcarPoltronas();
			
			aux.add(ocupacao);
		}
		
		Collections.sort(aux, new Comparator<GP_PricingOcupaAntecipaVO>() {

			@Override
			public int compare(GP_PricingOcupaAntecipaVO o1, GP_PricingOcupaAntecipaVO o2) {
				int retorno = o1.getDiaMin().compareTo(o2.getDiaMax());
				return retorno;
			}
		});
		
		
		List<GP_PricingOcupaAntecipaVO> retorno = new ArrayList<GP_PricingOcupaAntecipaVO>();
		for (GP_PricingOcupaAntecipaVO pricingOcupacaoAntecipa : aux) {
			retorno.addAll(gerarDados(pricingOcupacaoAntecipa));
		}

		retorno = agruparMesmoDias(retorno);
		
		if(retorno.size() >= 3) {
			retorno.get(retorno.size() - 2).setAuxDesc("...");
		}
		
		if(retorno.size() >= 2) {
			retorno.get(retorno.size() - 1).setAuxDesc(GP_PricingOcupaAntecipaVO.CANTDIASMAXDEFAULT.toString());
		}
		
		return retorno;
	}

	private List<GP_PricingOcupaAntecipaVO> agruparMesmoDias(List<GP_PricingOcupaAntecipaVO> lsOcupacaoAntecipas) {
		List<GP_PricingOcupaAntecipaVO> retorno = new ArrayList<GP_PricingOcupaAntecipaVO>();
		for (GP_PricingOcupaAntecipaVO pricingOcupacaoAntecipa : lsOcupacaoAntecipas) {
			GP_PricingOcupaAntecipaVO aux = new GP_PricingOcupaAntecipaVO(pricingOcupacaoAntecipa, true);
			if(retorno.isEmpty() || !retorno.contains(aux)) {
				retorno.add(aux);
			} else {
				int index = retorno.indexOf(pricingOcupacaoAntecipa);
				retorno.get(index).getPoltronas().addAll(aux.getPoltronas());
			}
		}
		
		adicionarPoltronasNaoMarcadas(retorno);
		
		return retorno;
	}

	private void adicionarPoltronasNaoMarcadas(List<GP_PricingOcupaAntecipaVO> lsRetorno) {
		for (GP_PricingOcupaAntecipaVO pricingOcupacaoAntecipa : lsRetorno) {
			List<GP_PricingOcupaAntecipaPoltronasVO> poltronasPadrao = GP_PricingOcupaAntecipaPoltronasVO.carregarPoltronasPadrao();
			poltronasPadrao.removeAll(pricingOcupacaoAntecipa.getPoltronas());
			pricingOcupacaoAntecipa.getPoltronas().addAll(poltronasPadrao);
			Collections.sort(pricingOcupacaoAntecipa.getPoltronas(), new Comparator<GP_PricingOcupaAntecipaPoltronasVO>() {
				@Override
				public int compare(GP_PricingOcupaAntecipaPoltronasVO o1, GP_PricingOcupaAntecipaPoltronasVO o2) {
					return o1.getPoltrona().compareTo(o2.getPoltrona());
				}
			});
		}
	}

	private List<GP_PricingOcupaAntecipaVO> gerarDados(GP_PricingOcupaAntecipaVO ocupacao) {
		List<GP_PricingOcupaAntecipaVO> retorno = new ArrayList<GP_PricingOcupaAntecipaVO>();
		for (int i = ocupacao.getDiaMin(); i <= ocupacao.getDiaMax(); i++) {
			GP_PricingOcupaAntecipaVO pricingOcupacao = new GP_PricingOcupaAntecipaVO(ocupacao);
			pricingOcupacao.setAntecipacao(i);
			retorno.add(pricingOcupacao);
		}
		return retorno;
	}

	@Override
	public List<GP_PricingOcupaAntecipaLegendaVO> carregarPricingOcupaAntecipaLegenda(Integer pricingId) {
		List<GP_PricingOcupaAntecipa> lsPricingOcupaAntecipa = carregarPricingOcupaAntecipa(pricingId);
		
		return carregarPricingOcupaAntecipaLegenda(lsPricingOcupaAntecipa);
	}

	@Override
	public List<GP_PricingOcupaAntecipaLegendaVO> carregarPricingOcupaAntecipaLegenda(List<GP_PricingOcupaAntecipa> lsPricingOcupaAntecipa) {
		NumberFormat nf = NumberFormat.getPercentInstance();
		nf.setMaximumFractionDigits(2);
		nf.setMinimumFractionDigits(2);
		
		GP_PricingOcupaAntecipaLegendaVO legendaDias = new GP_PricingOcupaAntecipaLegendaVO();
		GP_PricingOcupaAntecipaLegendaVO legendaPercentuais = new GP_PricingOcupaAntecipaLegendaVO();
		legendaDias.setLegenda(Labels.getLabel("editarPricingController.legenda.label"));
		legendaDias.setItens(new ArrayList<GP_PricingOcupaAtencipaLegendaItemVO>());
		legendaPercentuais.setItens(new ArrayList<GP_PricingOcupaAtencipaLegendaItemVO>());
		for (GP_PricingOcupaAntecipa ocupaAntecipa : lsPricingOcupaAntecipa) {
			Integer cantdiasmax = ocupaAntecipa.getCantdiasmax() != null ? ocupaAntecipa.getCantdiasmax() : GP_PricingOcupaAntecipaVO.CANTDIASMAXDEFAULT;
			String dias = ocupaAntecipa.getCantdiasmin() + "-" + cantdiasmax;
			GP_PricingOcupaAtencipaLegendaItemVO auxDias = legendaDias.new GP_PricingOcupaAtencipaLegendaItemVO(dias, nf.format(ocupaAntecipa.getPorcentaje().doubleValue()/100), ocupaAntecipa.getCor(), dias, ocupaAntecipa.getPricingocupaantecipaId());
			GP_PricingOcupaAtencipaLegendaItemVO auxPercentual = legendaDias.new GP_PricingOcupaAtencipaLegendaItemVO(nf.format(ocupaAntecipa.getPorcentaje().doubleValue()/100), nf.format(ocupaAntecipa.getPorcentaje().doubleValue()/100), ocupaAntecipa.getCor(), dias, ocupaAntecipa.getPricingocupaantecipaId());
			if(!legendaDias.getItens().contains(auxDias)) {
				legendaDias.getItens().add(auxDias);
				legendaPercentuais.getItens().add(auxPercentual);
			}
		}
		List<GP_PricingOcupaAntecipaLegendaVO> retorno = new ArrayList<GP_PricingOcupaAntecipaLegendaVO>();
		retorno.add(legendaDias);
		retorno.add(legendaPercentuais);
		return retorno;
	}

	@Override
	public GP_PricingOcupaAntecipa obtenerID(Integer pricingocupaantecipaId) throws BusinessException {
		return pricingOcupacionDAO.obtenerID(pricingocupaantecipaId);
	}
	
	@Override
	public List<GP_PricingOcupaAntecipa> carregarPricingOcupaAntecipa(Integer pricingId) {
		return pricingOcupacionDAO.buscarOcupaAntecipaPricingAtivos(pricingId);
	}

	@Override
	public List<GP_PricingOcupaAntecipa> obtenerTodoPorPricing(GP_Pricing pricing) {
		return pricingOcupacionDAO.obtenerTodoPorPricing(pricing);
	}
	
}
