package foodtruck.email;

import java.io.UnsupportedEncodingException;
import java.text.MessageFormat;
import java.util.Map;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

import com.google.common.base.Joiner;
import com.google.common.collect.Iterables;
import com.google.inject.Inject;

import org.joda.time.format.DateTimeFormatter;

import foodtruck.dao.ConfigurationDAO;
import foodtruck.model.Configuration;
import foodtruck.model.FoodTruckRequest;
import foodtruck.model.Location;
import foodtruck.model.Truck;
import foodtruck.model.TweetSummary;
import foodtruck.util.FriendlyDateOnlyFormat;

/**
 * An email notifier that sends the email immediately.
 * @author aviolette
 * @since 4/29/13
 */
public class SimpleEmailNotifier implements EmailNotifier {
  public static Logger log = Logger.getLogger(SimpleEmailNotifier.class.getName());
  private final ConfigurationDAO configDAO;
  private final MessageBuilder messageBuilder;
  private final DateTimeFormatter dateOnlyFormatter;

  @Inject
  public SimpleEmailNotifier(ConfigurationDAO configurationDAO, MessageBuilder messageBuilder,
      @FriendlyDateOnlyFormat DateTimeFormatter dateOnlyFormat) {
    this.configDAO = configurationDAO;
    this.messageBuilder = messageBuilder;
    this.dateOnlyFormatter = dateOnlyFormat;
  }

  @Override public void systemNotifyOffTheRoad(Truck truck, TweetSummary tweet) {
    String msgBody = MessageFormat.format("This tweet might indicate that {0} is off the road:\n" +
        "\n \"{1}\"\n\n" +
        "Click here to take the truck off the road: " +
        "http://www.chicagofoodtruckfinder.com/admin/trucks/{2}/offtheroad", truck.getName(), tweet.getText(),
        truck.getId());
    sendSystemMessage(truck.getName() + " might be off the road", msgBody);
  }

  @Override public void systemNotifyLocationAdded(Location location, TweetSummary tweet, Truck truck) {
    try {
      sendSystemMessage("New Location Added: " + location.getName(),
          messageBuilder.locationAddedMessage(location, tweet, truck));
    } catch (Exception e) {
      log.log(Level.WARNING, e.getMessage(), e);
    }
  }

  @Override public void systemNotifyTrucksAddedByObserver(Map<Truck, TweetSummary> trucksAdded) {
    StringBuilder builder = new StringBuilder("The following trucks were added: \n\n");
    for (Map.Entry<Truck, TweetSummary> entry : trucksAdded.entrySet()) {
      builder.append(entry.getKey().getName()).append(" http://www.chicagofoodtruckfinder.com/admin/trucks/")
          .append(entry.getKey().getId()).append(" => @").append(entry.getValue().getScreenName())
          .append(" '").append(entry.getValue().getText()).append("'\n\n");
    }
    try {
      sendSystemMessage("New stops added by observers", builder.toString());
    } catch (Exception e) {
      log.log(Level.WARNING, e.getMessage(), e);
    }
  }

  @Override public void notifyNewFoodTruckRequest(FoodTruckRequest request) {
    try {
      StringBuilder builder = buildRequest(request);
      builder.append("\n\nClick here to promote: http://www.chicagofoodtruckfinder.com/admin/requests/promote?id=")
          .append(request.getKey()).append("\n\n");
      sendSystemMessage("New food truck request", builder.toString());
    } catch (Exception e) {
      log.log(Level.WARNING, e.getMessage(), e);
    }
  }

  private StringBuilder buildRequest(FoodTruckRequest request) {
    StringBuilder builder = new StringBuilder("The following request was added: \n\n");
    builder.append(request.getEventName()).append("\n\n");
    builder.append(dateOnlyFormatter.print(request.getStartTime())).append(" - ");
    builder.append(dateOnlyFormatter.print(request.getEndTime())).append("\n");
    builder.append("Requested by: ").append(request.getRequester()).append("\n");
    builder.append("Email: ").append(request.getEmail()).append("\n");
    builder.append("Phone: ").append(request.getPhone()).append("\n");
    builder.append("Expected number of guests: ").append(request.getExpectedGuests()).append("\n");
    builder.append("Prepaid: ").append(request.isPrepaid()).append("\n");
    builder.append("\n\n");
    builder.append(request.getDescription());
    return builder;
  }

  @Override public boolean notifyFoodTrucksOfRequest(Iterable<String> addresses, FoodTruckRequest request) {
    if (Iterables.size(addresses) == 0) {
      log.log(Level.INFO, "Message for request: {0} not sent 'cause there are no recipients", request.getKey());
      return false;
    }
    log.log(Level.INFO, "Sending Request {0} to {1}", new Object[] { request.getKey(), Joiner.on(",").join(addresses) });
    return sendMessage("Food Truck Request", addresses, buildRequest(request).toString());
  }

  private boolean sendMessage(String subject, Iterable<String> receivers, String msgBody) {
    Configuration config = configDAO.find();
    String sender = config.getNotificationSender();
    Properties props = new Properties();
    Session session = Session.getDefaultInstance(props, null);
    Message msg = new MimeMessage(session);
    try {
      msg.setFrom(new InternetAddress(sender, "Food Truck Finder"));
      for (String receiver : receivers) {
        msg.addRecipient(Message.RecipientType.TO,
            new InternetAddress(receiver));
      }
      msg.setSubject(subject);
      msg.setText(msgBody);
      Transport.send(msg);
    } catch (MessagingException e) {
      log.log(Level.WARNING, e.getMessage(), e);
      return false;
    } catch (UnsupportedEncodingException e) {
      log.log(Level.WARNING, e.getMessage(), e);
      return false;
    }
    return true;
  }

  private void sendSystemMessage(String subject, String msgBody) {
    sendMessage(subject, configDAO.find().getSystemNotificationList(), msgBody);
  }
}

@@ -457,16 +457,64 @@
 Joiner;%0A
+import com.google.common.collect.ImmutableList;%0A
 import c
@@ -4936,25 +4936,61 @@
 quest%22, 
-addresses
+configDAO.find().getSystemNotificationList() 
 , buildR
@@ -5011,24 +5011,35 @@
 ).toString()
+, addresses
 );%0A  %7D%0A%0A  pr
@@ -5114,32 +5114,55 @@
 , String msgBody
+, Iterable%3CString%3E bccs
 ) %7B%0A    Configur
@@ -5614,24 +5614,153 @@
 ));%0A      %7D%0A
+      for (String receiver : bccs) %7B%0A        msg.addRecipient(Message.RecipientType.BCC, new InternetAddress(receiver));%0A      %7D%0A
       msg.se
@@ -6224,21 +6224,49 @@
 t(), msgBody
+, ImmutableList.%3CString%3Eof()
 );%0A  %7D%0A%7D%0A

Move receipients of Food Truck Requests to BCC list.