package eu.dnetlib.repo.manager.service;

import eu.dnetlib.domain.data.PiwikInfo;
import eu.dnetlib.domain.data.Repository;
import eu.dnetlib.domain.functionality.validator.JobForValidation;
import eu.dnetlib.repo.manager.config.CascadingPropertyLoader;
import eu.dnetlib.utils.MailLibrary;
import org.apache.log4j.Logger;
import org.mitre.openid.connect.model.OIDCAuthenticationToken;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;


@Component("emailUtils")
public class EmailUtilsImpl implements EmailUtils {

    private static Logger LOGGER = Logger.getLogger(EmailUtilsImpl.class);

    private List<String> specialRecipients = new ArrayList<String>();
    private boolean override = false, logonly = false;
    private String overrideEmail = null, from = null;

    @Autowired
    private MailLibrary mailLibrary;

    @Autowired
    private CascadingPropertyLoader pLoader;

    @Value("${services.repo-manager.baseUrl}")
    private String baseUrl;

    @Value("${services.repo-manager.adminEmail}")
    private String adminEmail;

    @Value("${services.repomanager.usagestats.adminEmail}")
    private String usageStatsAdminEmail;

    @Value("${services.provide.adminEmail}")
    private String provideAdminEmail;


    @PostConstruct
    public void init(){
        System.out.println("url -> " + this.baseUrl);
    }


    @Override
    public void reportException(Exception exception) {
        Writer writer = new StringWriter();
        PrintWriter printWriter = new PrintWriter(writer);
        exception.printStackTrace(printWriter);

        List<String> recipients = new ArrayList<String>();

        try {
            recipients.add(this.adminEmail);
            String message = "An exception has occurred:\n"+writer.toString();
            String subject = "Automatic Bug Report";
            this.sendMail(recipients, subject, message, false, null);
        } catch (Exception e) {
            LOGGER.error("Error sending error report", e);
        }
    }

    @Override
    public void sendAdministratorRequestToEnableMetrics(PiwikInfo piwikInfo) throws Exception {

        try {
            String subject = "[OpenAIRE-Usage Statistics] New request to enable usage statistics";

            String message = "Dear administrator,\n" +
                    "\n" +
                    "we have received a request to enable the OpenAIRE usage statistics for the following repository \n" +
                    "\n" +
                    "Repository - " + piwikInfo.getRepositoryName() + ", " + piwikInfo.getCountry() + " (" + piwikInfo.getRepositoryId() + ")\n" +
                    "Requestor - " + piwikInfo.getRequestorName() + ", " + piwikInfo.getRequestorEmail() + "\n" +
                    "Piwik ID - " + piwikInfo.getSiteId() + "\n" +
                    "Authentication token - " + piwikInfo.getAuthenticationToken() + "\n" +
                    "\n" +
                    "For more information about this request, go here: \n" +
                    this.baseUrl + "/admin/metrics\n" +
                    "\n" +
                    "Best,\n" +
                    "The OpenAIRE team";

            this.sendMail(this.usageStatsAdminEmail, subject, message, false, null);

        } catch (Exception e) {
            LOGGER.error("Error while sending request to enable metrics email to administrator: " + this.usageStatsAdminEmail, e);
            throw e;
        }
    }

    @Override
    public void sendUserRequestToEnableMetrics(PiwikInfo piwikInfo) throws Exception {

        try {
            String subject = "[OpenAIRE-Usage Statistics] Your request to enable usage statistics";

            String message = "Dear " + piwikInfo.getRequestorName() + ",\n" +
                    "\n" +
                    "we have received your request to enable the OpenAIRE usage statistics for your repository\n" +
                    "\n" +
                    "Repository - " + piwikInfo.getRepositoryName() + ", " + piwikInfo.getCountry() + " (" + piwikInfo.getRepositoryId() + ")\n" +
                    "Piwik ID - " + piwikInfo.getSiteId() + "\n" +
                    "Authentication token - " + piwikInfo.getAuthenticationToken() + "\n" +
                    "\n" +
                    "In order to enable the usage statistics, you must install the OpenAIRE's tracking code in your repository software. " +
                    "OpenAIRE's usage statistics service tracking code is maintained on Github as a patch for various versions of DSpace " +
                    "(https://github.com/openaire/OpenAIRE-Piwik-DSpace) and as an Eprints plugin for version 3 " +
                    "(https://github.com/openaire/EPrints-OAPiwik). In case the platform is different from DSpace or EPrints please contact " +
                    "the OpenAIRE team in repositoryusagestats@openaire.eu in order to find a solution.\n" +
                    "\n" +
                    "For more information about your request and configuration details, go here: \n" +
                    this.baseUrl + "/getImpact/instructions/" + piwikInfo.getRepositoryId() + "\n" +
                    "\n" +
                    "Once you have finished configuring your repository or if you have any questions, please notify the OpenAIRE team by sending \n" +
                    "an email to repositoryusagestats@openaire.eu\n" +
                    "\n" +
                    "Best,\n" +
                    "The OpenAIRE team";

            this.sendMail(piwikInfo.getRequestorEmail(), subject, message, false, null);

        } catch (Exception e) {
            LOGGER.error("Error while sending request to enable metrics email to user: " + piwikInfo.getRequestorEmail(), e);
            throw e;
        }
    }

    @Override
    public void sendAdministratorMetricsEnabled(PiwikInfo piwikInfo) throws Exception {

        try {
            String subject = "[OpenAIRE-Usage Statistics] Usage statistics have been enabled";

            String message = "Dear administrator,\n" +
                    "\n" +
                    "The installation and configuration of OpenAIRE's tracking code for the following repository " +
                    "has been completed and validated and the usage statistics have been enabled in OpenAIRE.\n" +
                    "\n" +
                    "Repository - " + piwikInfo.getRepositoryName() + ", " + piwikInfo.getCountry() + " (" + piwikInfo.getRepositoryId() + ")\n" +
                    "Requestor - " + piwikInfo.getRequestorName() + ", " + piwikInfo.getRequestorEmail() + "\n" +
                    "Piwik ID - " + piwikInfo.getSiteId() + "\n" +
                    "Authentication token - " + piwikInfo.getAuthenticationToken() + "\n" +
                    "\n" +
                    "Best,\n" +
                    "The OpenAIRE team";

            this.sendMail(this.usageStatsAdminEmail, subject, message, false, null);

        } catch (Exception e) {
            LOGGER.error("Error while sending metrics enabled notification email to administator: " + this.usageStatsAdminEmail, e);
            throw e;
        }
    }

    @Override
    public void sendUserMetricsEnabled(PiwikInfo piwikInfo) throws Exception {

        try {
            String subject = "[OpenAIRE-Usage Statistics] Usage statistics have been enabled";

            String message = "Dear " + piwikInfo.getRequestorName() + ",\n" +
                    "\n" +
                    "The installation and configuration of OpenAIRE's tracking code for your repository \"" + piwikInfo.getRepositoryName() +
                    "\" has been completed and validated and the usage statistics have been enabled in OpenAIRE.\n" +
                    "\n" +
                    "You can preview the statistics in your repository's dashboard: \n" +
                    this.baseUrl + "/getImpact/" + piwikInfo.getRepositoryId() + "\n" +
                    "\n" +
                    " For more information and questions, you can contact the openaire support team by sending an email to " +
                    "repositoryusagestats@openaire.eu\n" +
                    "\n" +
                    "Best,\n" +
                    "The OpenAIRE team";

            this.sendMail(piwikInfo.getRequestorEmail(), subject, message, false, null);

        } catch (Exception e) {
            LOGGER.error("Error while sending metrics enabled notification email to user: " + piwikInfo.getRequestorEmail(), e);
            throw e;
        }
    }

    @Override
    public void sendAdminRegistrationEmail(Repository repository, Authentication authentication) throws Exception {
        try {
            String subject = "OpenAIRE content provider registration request started for " +
                    repository.getDatasourceType() + "[" + repository.getEnglishName() + "]";

            String message = "Dear administrator" + ",\n" +
                    "\n" +
                    "We received a request to register the " + repository.getDatasourceType() + "[" + repository.getEnglishName() + "]" +
                    " to the OpenAIRE compliant list of content providers. " +
                    "A validation process against the OpenAIRE guidelines compatibility " +
                    "has been started. You will be informed in another message once the process is finished." +
                    "\n\n" +
                    "Please do not reply to this message\n" +
                    "This message has been generated automatically.\n\n" +
                    "Regards,\n" +
                    "the OpenAIRE technical team\n";

            this.sendMail(this.provideAdminEmail, subject, message, false, null);

        } catch (Exception e) {
            LOGGER.error("Error while sending registration notification email to the administrator", e);
            throw e;
        }
    }

    @Override
    public void sendUserRegistrationEmail(Repository repository, Authentication authentication) throws Exception {
        try {
            String subject = "OpenAIRE content provider registration request started for " +
                    repository.getDatasourceType() + "[" + repository.getEnglishName() + "]";

            String message = "Dear " + ((OIDCAuthenticationToken) authentication).getUserInfo().getName() + ",\n" +
                    "\n" +
                    "We received a request to register the " + repository.getDatasourceType() + "[" + repository.getEnglishName() + "]" +
                    " to the OpenAIRE compliant list of content providers. " +
                    "A validation process against the OpenAIRE guidelines compatibility " +
                    "has been started. You will be informed in another message once the process is finished." +
                    "\n\n" +
                    "Please do not reply to this message\n" +
                    "This message has been generated automatically.\n\n" +
                    "If you have any questions, write to 'helpdesk@openaire.eu'. \n\n" +
                    "Regards,\n" +
                    "the OpenAIRE technical team\n";

            this.sendMail(repository.getRegisteredBy(), subject, message, false, null);

        } catch (Exception e) {
            LOGGER.error("Error while sending registration notification email to user: " + repository.getRegisteredBy(), e);
            throw e;
        }
    }

    @Override
    public void sendAdminUpdateRepositoryEmail(Repository repository, Authentication authentication) throws Exception {
        try {
            String subject = "OpenAIRE content provider update request started for " +
                    repository.getDatasourceType() + "[" + repository.getEnglishName() + "]";

            String message = "Dear administrator" + ",\n" +
                    "\n" +
                    "We received a request to update the " + repository.getDatasourceType() + "[" + repository.getEnglishName() + "]." +
                    "A new iteration process of the validation against the OpenAIRE guidelines compatibility has been started.\n\n" +
                    "Please do not reply to this message\n" +
                    "This message has been generated automatically.\n\n" +
                    "Regards,\n" +
                    "the OpenAIRE technical team\n";

            this.sendMail(this.provideAdminEmail, subject, message, false, null);

        } catch (Exception e) {
            LOGGER.error("Error while sending registration notification email to the administrator", e);
            throw e;
        }
    }

    @Override
    public void sendUserUpdateRepositoryEmail(Repository repository, Authentication authentication) throws Exception {
        try {
            String subject = "OpenAIRE content provider update request started for " +
                    repository.getDatasourceType() + "[" + repository.getEnglishName() + "]";

            String message = "Dear " + ((OIDCAuthenticationToken) authentication).getUserInfo().getName() + ",\n" +
                    "\n" +
                    "We received a request to update the " + repository.getDatasourceType() + "[" + repository.getEnglishName() + "]." +
                    "A new iteration process of the validation against the OpenAIRE guidelines compatibility has been started.\n\n" +
                    "Please do not reply to this message\n" +
                    "This message has been generated automatically.\n\n" +
                    "If you have any questions, write to 'helpdesk@openaire.eu'. \n\n" +
                    "Regards,\n" +
                    "the OpenAIRE technical team\n";

            this.sendMail(repository.getRegisteredBy(), subject, message, false, null);

        } catch (Exception e) {
            LOGGER.error("Error while sending registration notification email to user: " + repository.getRegisteredBy(), e);
            throw e;
        }
    }

    @Override
    public void sendSubmitJobForValidationEmail(Authentication authentication, JobForValidation jobForValidation) throws Exception {
        try {
            String subject = "OpenAIRE validator - Test submission ";

            String message = "Dear " + ((OIDCAuthenticationToken) authentication).getUserInfo().getName() + ",\n" +
                    "\n" +
                    "The validation request you have submitted has started.\n" +
                    "Please do not reply to this message.\n" +
                    "This message has been generated automatically.\n" +
                    "If you have any questions, write to 'helpdesk@openaire.eu'. \n\n" +
                    "Regards,\n" +
                    "the OpenAIRE technical team\n";

            this.sendMail(jobForValidation.getUserEmail(), subject, message, false, null);

        } catch (Exception e) {
            LOGGER.error("Error while sending validation submission notification email to user: " + jobForValidation.getUserEmail(), e);
            throw e;
        }
    }

    private void sendMail(String email, String subject, String message, boolean sendToSpecial, List<String> repoAdminMails) throws Exception {
        ArrayList<String> to = new ArrayList<String>();
        to.add(email);
        this.sendMail(to,subject,message,sendToSpecial,repoAdminMails);
    }

    private void sendMail(List<String> recipients, String subject, String message, boolean sendToSpecial, List<String> repoAdminMails) throws Exception {

        try {
            if (sendToSpecial) {
                recipients.addAll(this.specialRecipients);
            }

            if (repoAdminMails != null)
                recipients.addAll(repoAdminMails);

            if (this.override) {
                recipients.clear();
                recipients.add(overrideEmail);
            }
            if (!logonly)
                mailLibrary.sendEmail(recipients.toArray(new String[]{}), subject, message);
            LOGGER.debug("Sending mail to Recipients: " + recipients + " Subject: " + subject + " Message: " + message);
        } catch (Exception e) {
            LOGGER.error("Error sending mail to Recipients: " + recipients + " Subject: " + subject + " Message: " + message, e);
            throw new Exception(e);
        }
    }

    private String getEmailProperty(String key) {
        return pLoader.getProperties().getProperty(key);
    }

    public void setSpecialRecipients(String specialRecipients) {
        String[] recps = specialRecipients.split(",");

        for (String recp : recps) {
            recp = recp.trim();

            this.specialRecipients.add(recp);
        }
    }


    public void setOverride(boolean override) {
        this.override = override;
    }

    public void setOverrideEmail(String overrideEmail) {
        this.overrideEmail = overrideEmail;
    }

    public String getFrom() {
        return from;
    }

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

    public boolean isLogonly() {
        return logonly;
    }

    public void setLogonly(boolean logonly) {
        this.logonly = logonly;
    }


}
