/*
 *  Copyright 2013-2050 Emmanuel BRUN (contact@amapj.fr)
 * 
 *  This file is part of AmapJ.
 *  
 *  AmapJ is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.

 *  AmapJ 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 Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with AmapJ.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * 
 */
 package fr.amapj.service.services.notification.hourly.producteur;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import fr.amapj.common.CollectionUtils;
import fr.amapj.common.DateUtils;
import fr.amapj.common.StringUtils;
import fr.amapj.common.collections.G1D;
import fr.amapj.common.collections.G1D.Cell1;
import fr.amapj.model.engine.rdblink.RdbLink;
import fr.amapj.model.engine.transaction.NewTransaction;
import fr.amapj.model.models.contrat.modele.ModeleContrat;
import fr.amapj.model.models.contrat.reel.Contrat;
import fr.amapj.model.models.contrat.reel.TypInscriptionContrat;
import fr.amapj.model.models.fichierbase.Producteur;
import fr.amapj.model.models.fichierbase.ProducteurNotificationRetardataire;
import fr.amapj.model.models.stats.NotificationDone;
import fr.amapj.model.models.stats.TypNotificationDone;
import fr.amapj.service.engine.deamons.DeamonsContext;
import fr.amapj.service.services.mailer.MailerMessage;
import fr.amapj.service.services.mailer.MailerService;
import fr.amapj.service.services.mescontrats.ContratStatusService;
import fr.amapj.service.services.parametres.ParametresDTO;
import fr.amapj.service.services.parametres.ParametresService;
import fr.amapj.service.services.producteur.ProducteurService;
import fr.amapj.service.services.utilisateur.util.UtilisateurUtil;


public class ProducteurInscriptionRetardataireNotificationService 
{
	private final static Logger logger = LogManager.getLogger();
	

	public void sendInscriptionRetardataire(Producteur producteur, RdbLink em, DeamonsContext deamonsContext)
	{		
		String emails = getAllUsersToNotify(em, producteur);
		if (emails.length()==0)
		{
			return;
		}
		
		
		
		List<Contrat> cs = computeContratRetardataire(em,producteur);
		if (cs.size()==0)
		{
			return;
		}
	
		sendOneMessage(cs,producteur,emails,em,deamonsContext);	
	}

	private String getAllUsersToNotify(RdbLink em, Producteur producteur) 
	{
		List<String> res = new ArrayList<>();		

		// Ajout des reférents si besoin 
		if (producteur.notificationRetardataire==ProducteurNotificationRetardataire.REFERENT || producteur.notificationRetardataire==ProducteurNotificationRetardataire.REFERENT_PRODUCTEUR)
		{
			res.addAll(new ProducteurService().getProducteurReferent(em, producteur).stream().map(e->e.referent.email).collect(Collectors.toList()));
		}
		
		// Ajout des producteurs 
		if (producteur.notificationRetardataire==ProducteurNotificationRetardataire.REFERENT_PRODUCTEUR)
		{
			res.addAll(new ProducteurService().getProducteurUtilisateur(em, producteur).stream().map(e->e.utilisateur.email).collect(Collectors.toList()));
		}
		
		// Filtrage des emails incorrects
		res = CollectionUtils.filter(res, u->UtilisateurUtil.canSendMailTo(u)==true);
		
		// 
		return CollectionUtils.asString(res, ",");
	}

	private List<Contrat> computeContratRetardataire(RdbLink em, Producteur producteur) 
	{
		// On prend en compte uniquement les contrats retardataires conlus il y a moins de 7 jours
		// Les contrats plus vieux et non notifiés ne seront jamais notifiés 
		Date d1 = DateUtils.addDays(DateUtils.getDateWithNoTime(), -7);
		
		em.createQuery( "select c from Contrat c WHERE " +
						"c.modeleContrat.producteur=:p AND " +
						"c.typInscriptionContrat=:typInscriptionContrat AND "+
						"c.dateCreation>:d1 AND "+
						"NOT EXISTS (select d from NotificationDone d where d.typNotificationDone=:typNotif and d.contrat=c) ");
		em.setParameter("p", producteur);
		em.setParameter("d1", d1);
		em.setParameter("typInscriptionContrat", TypInscriptionContrat.RETARDATAIRE);
		em.setParameter("typNotif", TypNotificationDone.INSCRIPTION_RETARDATAIRE);

		
		List<Contrat> cs = em.result().list(Contrat.class);
		
		// On filtre pour garder uniquement ceux qui ne sont plus modifiable depuis au moins 2H 
		// Le mail partira ainsi à 2H du matin en même temps que la feuille de distribution 
		ContratStatusService css = new ContratStatusService();
		Date d2 = DateUtils.addHour(DateUtils.getDate(), -2);
		return cs.stream().filter(e->css.isContratRetardataireModifiable(e, d2)==false).collect(Collectors.toList());
		
	}

	private void sendOneMessage(List<Contrat> cs, Producteur producteur,String emails, RdbLink em, DeamonsContext deamonsContext)
	{
		// Construction du message
		MailerMessage message  = new MailerMessage();
		SimpleDateFormat df = new SimpleDateFormat("EEEEE dd MMMMM yyyy");
		ParametresDTO param = new ParametresService().getParametres();
	
		message.setTitle(param.nomAmap+" - Notification inscription retardaire ");
		message.setContent(getMessageContent(cs,producteur,param,df));
		message.setEmail(emails);
		sendMessageAndMemorize(message,CollectionUtils.convert(cs, e->e.id));
	}

	/**
	 * On réalise chaque envoi dans une transaction indépendante 
	 * 
	 */
	private void sendMessageAndMemorize(MailerMessage message,List<Long> contratIds)
	{
		NewTransaction.write(em->sendMessageAndMemorize(em,message,contratIds));
	}

	protected void sendMessageAndMemorize(RdbLink em, MailerMessage message, List<Long> contratIds)
	{
		// On mémorise dans la base de données que l'on va envoyer le message pour tous ces contrats
		for (Long contratId : contratIds) 
		{
			NotificationDone notificationDone = new NotificationDone();
			notificationDone.typNotificationDone = TypNotificationDone.INSCRIPTION_RETARDATAIRE;
			notificationDone.contrat = em.find(Contrat.class, contratId);
			notificationDone.dateEnvoi = DateUtils.getDate();
			em.persist(notificationDone);
		}
		
		// On envoie le message
		new MailerService().sendHtmlMail(message);
	}

	private String getMessageContent(List<Contrat> cs, Producteur producteur,ParametresDTO param, SimpleDateFormat df)
	{
		String link = param.getUrl();
		
		StringBuffer buf = new StringBuffer();
		buf.append("<h3>"+param.nomAmap+"-"+param.villeAmap+"</h3><br/>");
		buf.append("Bonjour ,");
		buf.append("<br/>");
		buf.append("<br/>");
		buf.append("Un ou plusieurs adhérents se sont inscrits en mode nouvel arrivant / retardataire");
		buf.append("<br/>");
		buf.append("Nom du producteur : "+producteur.nom);
		buf.append("<br/>");
		buf.append("<br/>");
		
		// On réalise une projection 1D de ces contrats - en ligne les modeles de contrats 
		G1D<ModeleContrat,Contrat> c1 = new G1D<>();
		
		// 
		c1.fill(cs);
		c1.groupBy(e->e.modeleContrat);
		
		// Tri par par nom de modele de contrat  
		c1.sortLig(e->e.nom,true);

		// tri sur les cellules sur le nom du souscripteur du contrat
		c1.sortCell(e->e.utilisateur.nom+" "+e.utilisateur.prenom,true);
		
		// Calcul des données
		c1.compute();
		
		// On en deduit la liste des blocs à afficher
		List<Cell1<ModeleContrat, Contrat>> mcs = c1.getFullCells();
		
		for (Cell1<ModeleContrat, Contrat> cell1 : mcs) 
		{
			buf.append("Nom du modèle de contrat : "+StringUtils.s(cell1.lig.nom));
			buf.append("<br/>");
			int nb = cell1.values.size();
			if (nb==1)
			{
				buf.append("1 adhérent a souscrit un nouveau contrat :");
			}
			else
			{
				buf.append(nb+ " adhérents ont souscrit un nouveau contrat :");
			}
			
			
			buf.append("<br/>");
			
			for (Contrat c : cell1.values) 
			{
				buf.append("- "+StringUtils.s(c.utilisateur.nom+" "+c.utilisateur.prenom));
				buf.append("<br/>");
			}
			buf.append("<br/><br/><br/>");
		}
		
		buf.append("A noter : les feuilles de livraison envoyées par mail contiennent bien ces nouveaux adhérents.");
		buf.append("<br/>");
		buf.append("<br/>");
		
		
		
		buf.append("Si vous souhaitez accéder à l'application : <a href=\""+link+"\">Cliquez ici </a>");
		buf.append("<br/>");
		buf.append("<br/>");
		buf.append("Bonne journée !");
		buf.append("<br/>");
		buf.append("<br/>");
		
		return buf.toString();
	}
}
