package eu.dnetlib.data.emailSender;

import eu.dnetlib.data.claims.migration.entity.Claim;
import eu.dnetlib.data.claims.migration.entity.Project;
import eu.dnetlib.data.claims.migration.handler.FetchClaimHandler;
import eu.dnetlib.data.claims.migration.handler.ProjectHandler;
import eu.dnetlib.data.claimsDemo.ClaimUtils;
import eu.dnetlib.data.claimsDemo.SQLStoreException;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;

import javax.mail.*;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.text.SimpleDateFormat;
import java.util.*;

public class EmailSender implements Runnable {

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

    @Autowired
    private FetchClaimHandler fetchClaimHandler = null;

    @Autowired
    private ProjectHandler projectHandler = null;

    private static String openaireClaimsPage;
    private static String username;
    private static String password;
    private static String host;
    private static String port;
    private static String from;
    private static String specialRecipients;

    private static String dateFrom;
    private static String dateTo;

    @Override
    public void run() {
        logger.info("EmailSender thread is running. " + host);
        logger.info("Special Recipients  " + specialRecipients);


        Project project = null;
        List<Claim> claims = null;
        List<String> types = new ArrayList<String>();

        Map<String, List<String>> managersOfProject = new HashMap<String, List<String>>();

        types.add(ClaimUtils.PROJECT);

        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date = null;

        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.HOUR_OF_DAY, -23);
        calendar.add(Calendar.MINUTE, -59);
        calendar.add(Calendar.SECOND, -59);
        date = calendar.getTime();
        dateFrom=(format.format(date));

        date = new Date();
        dateTo = (format.format(date));

        logger.debug("Sending emails for claims between " + dateFrom + " and "+dateTo);

        try {
            // Get all claims between dateFrom and dateTo which satisfy source_type == "project" or target_type == "project"
            claims = fetchClaimHandler.fetchClaimsByDate(dateFrom, dateTo, null, null, "", "source", true, types, false);
        } catch (SQLStoreException|Exception e) {
            logger.error("Could not fetch claims by date from "+dateFrom+" to "+dateTo, e);
        }

        for (Claim claim: claims) {
            if (claim.getSourceType().equals("project")) {
                project = (Project)claim.getSource();
            } else {
                project = (Project)claim.getTarget();
            }

            if (!managersOfProject.containsKey(project.getOpenaireId())) {

                // specialRecipients are used currently for testing purposes
                List<String> tmpManagers = null;
                if (specialRecipients != null && !specialRecipients.isEmpty()) {
                    tmpManagers = Arrays.asList(specialRecipients.split("\\s*,\\s*"));
                    logger.debug("Special recipients: " + specialRecipients);
                    managersOfProject.put(project.getOpenaireId(), tmpManagers);
                }

                // Send emails to actual project managers instead of special recipients
                //List<String> managers = projectFetcher.getFetchProjectHandler().fetchContactEmailsByProjectId(project.getOpenaireId());
                //logger.debug("Managers of project " + project.getOpenaireId() + ": "+managers);
                //managersOfProject.put(project.getOpenaireId(), managers);

                String token = UUID.randomUUID().toString();
                logger.debug("UUID Token for project " + project.getOpenaireId() + ": " + token);
                try {
                    projectHandler.updateTokenByProjectId(project.getOpenaireId(), token);

                    if (managersOfProject.get(project.getOpenaireId()) != null &&
                            !managersOfProject.get(project.getOpenaireId()).isEmpty()) {
                        send(project, token, managersOfProject.get(project.getOpenaireId()));
                    }
                } catch (SQLStoreException|Exception e) {
                    logger.error("Could update token for project with id "+ project.getOpenaireId(), e);
                }
            }
        }
    }

    public void send(Project project, String token, List<String> managers) {
        final String openaireClaimsPageUrl = openaireClaimsPage + token;

        // Get system properties
        Properties properties = System.getProperties();
        properties.setProperty("mail.smtp.host", host);
        properties.put("mail.smtp.port", port);
        properties.put("mail.smtp.auth", "true"); //enable authentication
        properties.put("mail.smtp.starttls.enable", "true");

        Session session = Session.getInstance(properties,
            new javax.mail.Authenticator() {
                protected PasswordAuthentication getPasswordAuthentication() {
                    return new PasswordAuthentication(username, password);
                }
            });

        try {
            // Create a default MimeMessage object.
            MimeMessage message = new MimeMessage(session);

            // Set From: header field of the header.
            message.setFrom(new InternetAddress(from));

            // Set To: header field of the header.
            for(String to : managers) {
                message.addRecipient(Message.RecipientType.TO, new InternetAddress(to));
            }

            // Set Subject: header field
            message.setSubject("Openaire Claims Notification");

            // For simple text setText() can be used instead of setContent()

            // Send the actual HTML message, as big as you like
            message.setContent("There are new Claims for the project: '" + project.getName() +"' for which you seem to be a contact person." +
                                        "<br>Click <a href=\""+openaireClaimsPageUrl+"\">here</a> to curate these Claims.", "text/html");

            // Send message
            Transport.send(message);
            logger.debug("Sent message successfully....\n");

        } catch (AddressException ae) {
            logger.error("Email could not be send.", ae);

        } catch (MessagingException me) {
            logger.error("Email could not be send.", me);
        }
    }

    public void setFetchClaimHandler(FetchClaimHandler fetchClaimHandler) {
        this.fetchClaimHandler = fetchClaimHandler;
    }

    public void setProjectHandler(ProjectHandler projectHandler) {
        this.projectHandler = projectHandler;
    }

    public static void setOpenaireClaimsPage(String openaireClaimsPage) {
        EmailSender.openaireClaimsPage = openaireClaimsPage;
    }

    public static void setUsername(String username) {
        EmailSender.username = username;
    }

    public static void setPassword(String password) {
        EmailSender.password = password;
    }

    public static void setHost(String host) {
        EmailSender.host = host;
    }

    public static void setPort(String port) {
        EmailSender.port = port;
    }

    public static void setFrom(String from) {
        EmailSender.from = from;
    }

    public static void setSpecialRecipients(String specialRecipients) {
        EmailSender.specialRecipients = specialRecipients;
    }
}
