package com.ejie.ad74a.util.comun;

import java.io.File;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Properties;

import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.mail.BodyPart;
import javax.mail.Message.RecipientType;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import com.ejie.ad74a.constantes.Constantes;
import com.ejie.ad74a.model.Expedientes;
import com.ejie.ad74a.model.Solicitantes;
import com.ejie.ad74a.util.constantes.PropertiesConstantes;

public class UtilidadesMail {

	private static final Logger logger = LoggerFactory.getLogger(UtilidadesMail.class);

	@Autowired
	private Properties appConfiguration;

	private static UtilidadesMail instance = null;

	private String protocol;
	private String host;
	private String port;
	private String from;

	private static final String NOMBREBENEFICIARIO = "##NOMBREBENEFICIARIO##";
	private static final String TEMPLATE_MAIL_AVISO_SSB_INF_INTERVENCION_PATH = "mail_aviso_ssb_inf_int.html";

	private Session session;

	/**
	 * @return UtilidadesMail
	 * @throws Exception
	 */
	public static UtilidadesMail getInstance() throws Exception {
		if (UtilidadesMail.instance == null) {
			UtilidadesMail.instance = new UtilidadesMail();
		}
		return UtilidadesMail.instance;
	}

	/**
	 * Constructor privado
	 * 
	 * @throws Exception
	 */
	private UtilidadesMail() throws Exception {
		try {

			this.host = PropertiesConstantes.Props.MAIL_HOST.getValue();
			this.protocol = PropertiesConstantes.Props.MAIL_PROTOCOL.getValue();
			this.port = PropertiesConstantes.Props.MAIL_PORT.getValue();
			this.from = PropertiesConstantes.Props.MAIL_FROM.getValue();

			Properties props = new Properties();

			// Protocolo de transporte
			props.put("mail.transport.protocol", this.protocol);
			props.put("mail.smtp.host", this.host);
			props.put("mail.smtp.port", this.port);
			props.put("mail.host", this.host);

			props.put("mail.smtp.auth", "false");

			this.session = Session.getInstance(props, null);

			this.session.setDebug(true);
		} catch (Exception exMMail) {
			System.err.println(exMMail.getMessage());
		}
	}

	public void enviarMailAviso(Expedientes expediente, Solicitantes solicitante, String tipoCorreo,
			ArrayList<String> tecnicosTo) throws Exception {

		// from
		String fromEmail = PropertiesConstantes.Props.MAIL_FROM.getValue();

		// destinatarios
		ArrayList<String> mailsTo = this.recuperarMailTecnico(tecnicosTo);

		// asunto
		String asunto = this.recuperarAsuntoMail(expediente, solicitante, tipoCorreo);

		// cuerpo mail
		String cuerpo = this.recuperarTextoMail(expediente, solicitante, tipoCorreo);

		List<DestinatarioMail> listaDestinatarios = new ArrayList<DestinatarioMail>();
		for (String mail : mailsTo) {
			listaDestinatarios.add(new DestinatarioMail(mail, DestinatarioMail.DEST_TIPO_A));
		}

		sendMessage(listaDestinatarios, asunto, com.ejie.ad74a.util.constantes.Constantes.ENCODING_UTF8, cuerpo,
				fromEmail, null);
	}

	public void enviarMail(String destinatario, String asunto, String cuerpo) throws Exception {

		// from
		String fromEmail = PropertiesConstantes.Props.MAIL_FROM.getValue();

		// destinatarios
		ArrayList<String> mailsTo = new ArrayList<String>();
		mailsTo.add(destinatario);
		mailsTo = this.recuperarMailTecnico(mailsTo);
		List<DestinatarioMail> listaDestinatarios = new ArrayList<DestinatarioMail>();
		for (String mail : mailsTo) {
			listaDestinatarios.add(new DestinatarioMail(mail, DestinatarioMail.DEST_TIPO_A));
		}

		sendMessage(listaDestinatarios, asunto, com.ejie.ad74a.util.constantes.Constantes.ENCODING_UTF8, cuerpo,
				fromEmail, null);

	}

	public void enviarMailDestinatario(List<DestinatarioMail> listaDestinatarios, String asunto, String cuerpo)
			throws Exception {

		// from
		String fromEmail = PropertiesConstantes.Props.MAIL_FROM.getValue();

		// destinatarios
		sendMessage(listaDestinatarios, asunto, com.ejie.ad74a.util.constantes.Constantes.ENCODING_UTF8, cuerpo,
				fromEmail, null);

	}

	/**
	 * @param listaDestinatarios List<DestinatarioMail>
	 * @param subject            String
	 * @param subjectCharset     String
	 * @param messageBody        String
	 * @param fromEmail          String
	 * @param path
	 * 
	 * @throws UnsupportedEncodingException excepción por codificación inválida
	 * @throws MessagingException           exceción al enviar mail
	 * @throws Exception                    excepción genérica
	 */
	private void sendMessage(List<DestinatarioMail> listaDestinatarios, String subject, String subjectCharset,
			String messageBody, String fromEmail, String path)
			throws UnsupportedEncodingException, MessagingException, Exception {

		MimeMessage message = new MimeMessage(this.session);

		// Quien envia el correo
		if (fromEmail != null) {
			message.setFrom(new InternetAddress(fromEmail));
		} else {
			message.setFrom(new InternetAddress(this.from));
		}

		// A quien va dirigido
		for (DestinatarioMail destinatario : listaDestinatarios) {
			message.addRecipient(this.obtenerRecipientType(destinatario.getTipo()),
					new InternetAddress(destinatario.getEmail()));
		}

		// Asunto
		message.setSubject(subject, subjectCharset);

		// Contenido del mensaje (puede llevar adjuntos)
		MimeMultipart multipart = new MimeMultipart();
		BodyPart texto = new MimeBodyPart();
		texto.setContent(messageBody, "text/html");
		multipart.addBodyPart(texto);

		if (path != null) {
			BodyPart adjunto = new MimeBodyPart();
			adjunto.setDataHandler(new DataHandler(new FileDataSource(path)));
			adjunto.setFileName(path.substring(this.appConfiguration.getProperty("ruta.datos.temporal").length()));

			multipart.addBodyPart(adjunto);
		}

		message.setContent(multipart);

		UtilidadesMail.logger.info("UtilidadesMail - Protocolo: " + this.protocol);
		UtilidadesMail.logger.info("UtilidadesMail - Puerto: " + this.port);
		UtilidadesMail.logger.info("UtilidadesMail - Host: " + this.host);
		UtilidadesMail.logger.info("UtilidadesMail - From: " + fromEmail);
		UtilidadesMail.logger.info("UtilidadesMail - A: " + listaDestinatarios.get(0).getEmail());

		// Envio del email
		Transport t = session.getTransport();
		t.connect();
		t.sendMessage(message, message.getAllRecipients());
		t.close();
	}

	/**
	 * @param tipoDestinatarioMail String
	 * @return RecipientType
	 */
	private RecipientType obtenerRecipientType(String tipoDestinatarioMail) {
		RecipientType recipientType = RecipientType.TO;

		if (tipoDestinatarioMail != null) {
			if (tipoDestinatarioMail.equals(DestinatarioMail.DEST_TIPO_CON_COPIA)) {
				recipientType = RecipientType.CC;
			} else if (tipoDestinatarioMail.equals(DestinatarioMail.DEST_TIPO_CON_COPIA_OCULTA)) {
				recipientType = RecipientType.BCC;
			}
		}

		return recipientType;
	}

	public String recuperarTextoMail(Expedientes expediente, Solicitantes solicitante, String tipoCorreo)
			throws Exception {
		String cuerpo = "";
		String plantilla = "";

		if (tipoCorreo
				.equalsIgnoreCase(com.ejie.ad74a.util.constantes.Constantes.TiposCorreo.AVISO_SSB_INF_INTERVENCION)) {
			plantilla = PropertiesConstantes.Props.MAIL_PLANTILLA_PATH.getValue() + "/"
					+ UtilidadesMail.TEMPLATE_MAIL_AVISO_SSB_INF_INTERVENCION_PATH;
		}

		File plantillaADescargar = new File(plantilla);
		InputStream is = FileUtils.openInputStream(plantillaADescargar);

		if (is != null) {
			cuerpo = IOUtils.toString(is, com.ejie.ad74a.util.constantes.Constantes.ENCODING_UTF8);

			if (tipoCorreo.equalsIgnoreCase(
					com.ejie.ad74a.util.constantes.Constantes.TiposCorreo.AVISO_SSB_INF_INTERVENCION)) {
				String nombreSolicitante = solicitante.getIdentificador01() + " - " + solicitante.getNombreCompleto();
				cuerpo = cuerpo.replaceAll(UtilidadesMail.NOMBREBENEFICIARIO, nombreSolicitante);
			}
		}
		return cuerpo;
	}

	private ArrayList<String> recuperarTodosMailTo() throws Exception {
		return UtilTokenXlnets.getMailListByGroup();
	}

	private ArrayList<String> recuperarMailTecnico(ArrayList<String> tecnicosTo) throws Exception {
		ArrayList<String> listaMails = UtilTokenXlnets.getMailByTecnico(tecnicosTo);
		// se incorporta el mail de grupo siempre
		// miramos el entorno para meter el mail de test o el de grupo de verdad
		String entorno = PropertiesConstantes.Props.ENTORNO.getValue();
		String mailGrupo = "";
		if (!Utilidades.esBlancoNulo(entorno) && entorno.equalsIgnoreCase(Constantes.ENTORNO_DESARROLLO_HOST)) {
			mailGrupo = PropertiesConstantes.Props.MAIL_TEST_ADDRESS.getValue();
		} else {
			mailGrupo = PropertiesConstantes.Props.MAIL_GRUPO.getValue();
		}

		listaMails.add(mailGrupo);
		return listaMails;
	}

	private String recuperarAsuntoMail(Expedientes expediente, Solicitantes solicitante, String tipoCorreo) {
		String asunto = "";
		StringBuilder subject = new StringBuilder();
		if (tipoCorreo
				.equalsIgnoreCase(com.ejie.ad74a.util.constantes.Constantes.TiposCorreo.AVISO_SSB_INF_INTERVENCION)) {
			asunto = "mail.avisoSSBInfIntervencion";
			String nombreSolicitante = solicitante.getIdentificador01() + " - " + solicitante.getNombreCompleto();

			subject = new StringBuilder(
					MessageFormat.format(
							Utilidades.getLabelFromResource(
									com.ejie.ad74a.util.constantes.Constantes.BASENAME_RESOURCE_AD74A_I18N, asunto,
									new Locale(com.ejie.ad74a.constantes.Constantes.ES)),
							new Object[] { nombreSolicitante }));

			subject.append(" / ");
			subject.append(
					MessageFormat.format(
							Utilidades.getLabelFromResource(
									com.ejie.ad74a.util.constantes.Constantes.BASENAME_RESOURCE_AD74A_I18N, asunto,
									new Locale(com.ejie.ad74a.constantes.Constantes.EU)),
							new Object[] { nombreSolicitante }));
		}

		return subject.toString();
	}

}
