package com.rafali.flickruploader;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.jdo.PersistenceManager;
import javax.mail.BodyPart;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.Session;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.rafali.common.STR;
import com.rafali.common.ToolString;

public class MailHandlerServlet extends HttpServlet {

	private static final long serialVersionUID = 1L;
	private static final Logger logger = LoggerFactory.getLogger(MailHandlerServlet.class.getPackage().getName());

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		doPost(req, resp);
	}

	static final String premiumSkuCoupon50 = "premium.2.5";
	static final String premiumSkuCoupon75 = "premium.1.25";
	static final String premiumSku = "premium.5";

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		logger.debug(req.toString());
		try {
			Properties props = new Properties();
			Session session = Session.getDefaultInstance(props, null);
			MimeMessage message = new MimeMessage(session, req.getInputStream());
			print(message);
			Multipart mp = (Multipart) message.getContent();
			logger.debug("############## count:" + mp.getCount());
			String email = "not_found_email";
			String content = null;
			if (FlickrRemoteApi.adminEmail.equals(message.getSender().toString())) {
				List<BodyPart> bodyparts = new ArrayList<BodyPart>();
				for (int i = 0; i < mp.getCount(); i++) {
					MimeBodyPart bodyPart = (MimeBodyPart) mp.getBodyPart(i);
					bodyparts.add(bodyPart);
					if (bodyPart.getContent() instanceof MimeMultipart) {
						MimeMultipart mimeMultipart = (MimeMultipart) bodyPart.getContent();
						for (int j = 0; j < mimeMultipart.getCount(); j++) {
							bodyparts.add(mimeMultipart.getBodyPart(j));
						}
					}
				}
				logger.debug("bodyparts : " + bodyparts.size() + " : " + bodyparts);
				for (BodyPart bodyPart : bodyparts) {
					if (bodyPart.getContentType().contains("text/plain") && bodyPart.getContent() instanceof CharSequence) {
						Pattern fromPattern = Pattern.compile(".*From:.*<(" + ToolString.REGEX_EMAIL_INSIDE + ")>.*");
						Matcher matcher = fromPattern.matcher((CharSequence) bodyPart.getContent());
						boolean matchFound = matcher.find();
						if (matchFound) {
							email = matcher.group(1).toLowerCase();
							logger.debug("processing : " + email);
							logger.debug("content : " + content);
							String recipient = message.getAllRecipients()[0].toString();
							if (recipient.contains("coupon100@")) {
								setPremium(email, true, false);
								content = "Awesome! I've just upgraded your account (" + email + ") to a PRO account.\n";
							} else if (recipient.contains("coupon50@")) {
								setDiscount(email, premiumSkuCoupon50);
								content = "Awesome! I've just applied a 50% discount to your account (" + email + ").\n";
							} else if (recipient.contains("coupon75@")) {
								setDiscount(email, premiumSkuCoupon75);
								content = "Awesome! I've just applied a 75% discount to your account (" + email + ").\n";
							}

							if (content != null) {
								content += "To refresh your status go to Preferences > Advanced Preferences and click on ‘Check PRO Status’.";
								content += "\n\nMaxime\n\n";
								content += bodyPart.getContent();
							}
							break;
						}
					}
				}
			} else {
				content = message.getSender() + " is not allowed";
			}

			if (content != null) {
				ToolMail.sendEmailNow(email, message.getSubject().replaceFirst("Fwd:", "Re:"), content.replaceAll("\n", "<br/>\n"), STR.supportEmail, STR.supportEmail);
			} else {
				ToolMail.sendEmailNow(STR.supportEmail, "[failed] - " + message.getSubject(), content, STR.supportEmail);
			}
		} catch (Exception e) {
			logger.error(ToolString.stack2string(e));
			ToolMail.sendEmailNow(STR.supportEmail, "[error] exception while processing mail", req.toString(), STR.supportEmail);
		}
	}

	static void setPremium(String email, boolean premium, boolean purchased) {
		logger.debug("email:" + email + ", premium:" + premium);
		PersistenceManager pm = PMF.get().getPersistenceManager();
		try {
			javax.jdo.Query query = pm.newQuery(Coupon.class);
			query.setFilter("email == :param");
			@SuppressWarnings("unchecked")
			List<Coupon> results = (List<Coupon>) query.execute(email);
			if (results.isEmpty()) {
				logger.debug("no coupon with email = " + email + ", creating one");
				Coupon coupon = new Coupon(email);
				coupon.setPremium(premium);
				coupon.setPurchased(purchased);
				pm.makePersistent(coupon);
			} else {
				for (Coupon coupon : results) {
					coupon.setPremium(premium);
					coupon.setPurchased(purchased);
					coupon.setDateUpdated(new Date());
					logger.debug("updated : " + coupon);
				}
			}
		} finally {
			pm.close();
		}
		updateUser(email, premium);
	}

	static void updateUser(String email, boolean premium) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		try {
			javax.jdo.Query query = pm.newQuery(AppInstall.class);
			query.setFilter("emails == :param");
			@SuppressWarnings("unchecked")
			List<AppInstall> results = (List<AppInstall>) query.execute(email);
			if (results.isEmpty()) {
				logger.debug("no device with email = " + email);
			} else {
				for (AppInstall appInstall : results) {
					appInstall.setPremium(premium);
					logger.debug("updated : " + appInstall);
				}
			}
		} finally {
			pm.close();
		}
	}

	static void setDiscount(String email, String sku) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		try {
			javax.jdo.Query query = pm.newQuery(Coupon.class);
			query.setFilter("email == :param");
			@SuppressWarnings("unchecked")
			List<Coupon> results = (List<Coupon>) query.execute(email);
			if (results.isEmpty()) {
				logger.debug("no coupon with email = " + email + ", creating one");
				Coupon coupon = new Coupon(email);
				coupon.setSku(sku);
				pm.makePersistent(coupon);
			} else {
				for (Coupon coupon : results) {
					coupon.setSku(sku);
					coupon.setPremium(false);
					coupon.setPurchased(false);
					coupon.setDateUpdated(new Date());
					logger.debug("updated : " + coupon);
				}
			}
		} finally {
			pm.close();
		}
		updateUserCoupon(email, sku);
	}

	static void updateUserCoupon(String email, String customSku) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		try {
			javax.jdo.Query query = pm.newQuery(AppInstall.class);
			query.setFilter("emails == :param");
			@SuppressWarnings("unchecked")
			List<AppInstall> results = (List<AppInstall>) query.execute(email);
			if (results.isEmpty()) {
				logger.debug("no device with email = " + email);
			} else {
				for (AppInstall appInstall : results) {
					appInstall.setCustomSku(customSku);
					logger.debug("updated : " + appInstall);
				}
			}
		} finally {
			pm.close();
		}
	}

	private void print(MimeMessage message) throws MessagingException, IOException {
		logger.debug("subject:" + message.getSubject());
		logger.debug("description:" + message.getDescription());
		logger.debug("contentType:" + message.getContentType());
		logger.debug("sender:" + message.getSender());
		logger.debug("from:" + Arrays.toString(message.getFrom()));
		logger.debug("recipient:" + Arrays.toString(message.getAllRecipients()));
		// logger.debug("description:"+message.);
		// Enumeration allHeaderLines = message.getAllHeaderLines();
		// while (allHeaderLines.hasMoreElements()) {
		// logger.debug("allHeaderLines:"+allHeaderLines.nextElement());
		// }
		logger.debug("content:" + message.getContent());
		logger.debug("content:" + message.getContent().getClass());
		Multipart mp = (Multipart) message.getContent();
		logger.debug("count:" + mp.getCount());
		for (int i = 0; i < mp.getCount(); i++) {
			MimeBodyPart bodyPart = (MimeBodyPart) mp.getBodyPart(i);
			logger.debug("bodyPart content type:" + bodyPart.getContentType());
			logger.debug("bodyPart content:" + bodyPart.getContent().getClass());
			logger.debug("bodyPart content:" + bodyPart.getContent());
			if (bodyPart.getContent() instanceof MimeMultipart) {
				MimeMultipart mimeMultipart = (MimeMultipart) bodyPart.getContent();
				for (int j = 0; j < mimeMultipart.getCount(); j++) {
					BodyPart part = mimeMultipart.getBodyPart(j);
					logger.debug(i + " - bodyPart content type:" + part.getContentType());
					logger.debug(i + " - bodyPart content:" + part.getContent().getClass());
					logger.debug(i + " - bodyPart content:" + part.getContent());
				}
			}
		}
	}
}