package nc.noumea.mairie.pdc.dao.impl;

/*
 * #%L
 * Logiciel de Gestion des Permis de Construire de la Ville de Nouméa
 * %%
 * Copyright (C) 2013 - 2016 Mairie de Nouméa, Nouvelle-Calédonie
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public
 * License along with this program.  If not, see
 * <http://www.gnu.org/licenses/gpl-3.0.html>.
 * #L%
 */

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.persistence.Query;

import org.apache.commons.lang.StringUtils;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import nc.noumea.mairie.pdc.core.dao.impl.GenericDaoImpl;
import nc.noumea.mairie.pdc.core.utility.DateUtil;
import nc.noumea.mairie.pdc.core.utility.PdcUtil;
import nc.noumea.mairie.pdc.dao.ConsultationDao;
import nc.noumea.mairie.pdc.entity.Consultation;
import nc.noumea.mairie.pdc.enums.Statut;
import nc.noumea.mairie.pdc.enums.TypeHistorique;
import nc.noumea.mairie.pdc.services.ConfigService;

@Repository("consultationDao")
public class ConsultationDaoImpl extends GenericDaoImpl<Consultation> implements ConsultationDao {

	private static Logger	log	= LoggerFactory.getLogger(ConsultationDaoImpl.class);

	@Autowired
	private ConfigService	configService;

	@Override
	public List<Consultation> findAllARelancerPourExpirationDelai15() {
		Integer nombreJour7 = configService.getNombreJourRelanceCompletudeSecondeRelance(); // exemple : 7 jours
		Integer nombreJour15 = configService.getNombreJourRelanceCompletudePremiereRelance(); // exemple: 15 jours
		return findAllARelancerPourDelaiCompletudeGeneric(nombreJour7, nombreJour15, TypeHistorique.EMAIL_EXPIRATION_DELAI_ORGANISME_PREMIERE_RELANCE);
	}

	@Override
	public List<Consultation> findAllARelancerPourExpirationDelai7() {
		Integer nombreJour0 = 0; // 0 jour
		Integer nombreJour7 = configService.getNombreJourRelanceCompletudeSecondeRelance(); // exemple : 7 jours
		return findAllARelancerPourDelaiCompletudeGeneric(nombreJour0, nombreJour7, TypeHistorique.EMAIL_EXPIRATION_DELAI_ORGANISME_SECONDE_RELANCE);
	}

	@Override
	public List<Consultation> findAllARelancerPourExpirationDelai() {
		Integer noLimit = null; //
		Integer nombreJour0 = 0; // à partir de > 0 jour d'expiration
		return findAllARelancerPourDelaiCompletudeGeneric(noLimit, nombreJour0, TypeHistorique.EMAIL_EXPIRATION_DELAI_ORGANISME);
	}

	@SuppressWarnings("unchecked")
	private List<Consultation> findAllARelancerPourDelaiCompletudeGeneric(Integer nombreJour1, Integer nombreJour2, TypeHistorique typeHistorique) {
		List<String> listeCritere = new ArrayList<>();

		// #7634, on ne relance que sur les projets à partir du 01/06/2014
		listeCritere.add("p.dateDepot >= :dateDepotMinimale");

		// On recherche les consultations liés à des projets en instruction ou attente info org...
		listeCritere.add("p.statut=:statutInstruction OR p.statut=:statutAttenteInfoOrg");

		// ... où les consultations n'ont pas d'avis
		// listeCritere.add("c.dateCompletude IS NULL AND c.avis IS NULL AND c.dateReponse IS NULL");
		listeCritere.add("c.avis IS NULL");

		// ... et qui n'ont pas d'historique (d'un type "mail de relance") lié
		listeCritere.add("NOT EXISTS (select h FROM Historique h WHERE h.consultation = c AND h.type=:typeHistorique)");

		String whereClause = listeCritere.isEmpty() ? "" : "WHERE (" + StringUtils.join(listeCritere, ") AND (") + ")";
		String jpaQuery = "SELECT DISTINCT c, c.projet FROM Projet p, IN(p.listeConsultation) c " + whereClause + " ORDER BY c.dateDebut";

		log.debug("JPA Query = " + jpaQuery);

		Query query = persistentManager.getEntityManager().createQuery(jpaQuery);

		PdcUtil.setParameter(query, "dateDepotMinimale", DateUtil.parseDate("01/06/2014")); // #7634
		PdcUtil.setParameter(query, "statutInstruction", Statut.INSTRUCTION);
		PdcUtil.setParameter(query, "statutAttenteInfoOrg", Statut.ATTENTE_INFO_ORG);
		PdcUtil.setParameter(query, "typeHistorique", typeHistorique);

		List<Consultation> listeConsultationCandidate = PdcUtil.createList(query.getResultList(), 0);

		return filtreListeConsultationCandidatePourRelance(nombreJour1, nombreJour2, listeConsultationCandidate);
	}

	private List<Consultation> filtreListeConsultationCandidatePourRelance(Integer nombreJour1, Integer nombreJour2, List<Consultation> listeConsultation) {

		List<Consultation> result = new ArrayList<>();
		DateTime auj00h00 = DateUtil.debutJournee(new DateTime());

		for (Consultation consultationCandidate : listeConsultation) {
			Date dateFinConsultation = consultationCandidate.getDateFin();
			if (dateFinConsultation == null) {
				continue;
			}
			DateTime dateTimeFinConsultation = new DateTime(dateFinConsultation);
			if (nombreJour2 != null) {
				DateTime date2 = dateTimeFinConsultation.minusDays(nombreJour2);
				if (auj00h00.isBefore(date2) || auj00h00.isEqual(date2)) {
					// consultation non retenue pour ce mail, car la date de fin de consultation est encore trop loin
					continue;
				}
			}
			if (nombreJour1 != null) {
				DateTime date1 = dateTimeFinConsultation.minusDays(nombreJour1);
				if (auj00h00.isAfter(date1)) {
					// consultation non retenue pour ce mail, car la date de fin de consultation est trop proche
					continue;
				}
			}
			result.add(consultationCandidate);
		}
		return result;
	}
}
