package com.workfusion.odf.core;

import java.util.Map;
import javax.inject.Named;

import groovy.lang.Binding;
import microsoft.exchange.webservices.data.core.enumeration.misc.ExchangeVersion;
import org.apache.commons.lang3.StringUtils;
import org.codejargon.feather.Provides;

import com.workfusion.bot.service.SecureEntryDTO;
import com.workfusion.odf.mail.impl.javax.EwsEmailsClient;
import com.workfusion.odf.service.mail.EmailManager;
import com.workfusion.odf.service.mail.impl.javax.ImapPop3EmailClient;
import com.workfusion.odf.service.mail.impl.javax.SMTPEmailSender;
import com.workfusion.rpa.core.security.SecurityUtils;

public class MailModule implements Module {
    public static final String PROTOCOL_EXCHANGE = "exchange";
    public static final String PROTOCOL_IMAP = "imap";
    public static final String PROTOCOL_POP3 = "pop3";

    // Parameter names ////////////////////////////////////////////////////////
    public static final String PARAM_PROTOCOL = "mail_protocol";
    public static final String PARAM_HOST = "mail_host";
    public static final String PARAM_PORT = "mail_port";
    public static final String PARAM_USER = "mail_user";
    public static final String PARAM_PASSWORD = "mail_password";

    @Provides
    public SMTPEmailSender smtpEmailSender(@Named("botConfigParams") Map<String, String> params) {
    	SMTPEmailSender.SupportedProtocol protocol = SMTPEmailSender.SupportedProtocol.forValue(params.get(PARAM_PROTOCOL));
    	String host = params.get(PARAM_HOST);
    	String port = params.get(PARAM_PORT);
    	String user = params.get(PARAM_USER);
    	String password = params.get(PARAM_PASSWORD);
    	SMTPEmailSender service = new SMTPEmailSender(protocol, host, port, user, password);

    	return service;
    }

    @Provides
    public EmailManager emailManager(Binding binding, @Named("botConfigParams") Map<String, String> params) {
        if (params == null) {
            throw new IllegalArgumentException("Cannot create EmailManager. Params are null");
        }

        String protocol = params.get("mail_protocol");
        if (PROTOCOL_EXCHANGE.equals(protocol)) {
            return createExchangeEmailManager(binding, params);
        }
        if (PROTOCOL_POP3.equals(protocol) || PROTOCOL_IMAP.equals(protocol)) {
            return createImapPop3EmailManager(binding, params);
        }

        throw new IllegalArgumentException("Cannot create EmailManager. Invalid protocol name: " + protocol);
    }

    private EmailManager createExchangeEmailManager(Binding binding, Map<String, String> params) {
        ExchangeParams exchangeParams = new ExchangeParams(binding, params);
        String server = exchangeParams.getServer();
        String domain = exchangeParams.getDomain();
        ExchangeVersion exchangeVersion = exchangeParams.getExchangeVersion();
        SecureEntryDTO userPasswordPair = exchangeParams.getUserPasswordPair();

        if (StringUtils.isEmpty(domain)) {
            return new EwsEmailsClient(
                    server,
                    userPasswordPair == null ? null : userPasswordPair.getKey(),
                    userPasswordPair == null ? null : userPasswordPair.getValue(),
                    exchangeVersion
            );
        } else {
            return new EwsEmailsClient(
                    server,
                    userPasswordPair == null ? null : userPasswordPair.getKey(),
                    userPasswordPair == null ? null : userPasswordPair.getValue(),
                    domain,
                    exchangeVersion
            );
        }
    }

    private EmailManager createImapPop3EmailManager(Binding binding, Map<String, String> params) {
        ImapPop3Params imapPop3Params = new ImapPop3Params(binding, params);
        SecureEntryDTO userPasswordPair = imapPop3Params.getUserPasswordPair();
        return new ImapPop3EmailClient(
                imapPop3Params.getProtocol(),
                imapPop3Params.getHost(),
                imapPop3Params.getPort(),
                userPasswordPair == null ? null : userPasswordPair.getKey(),
                userPasswordPair == null ? null : userPasswordPair.getValue(),
                imapPop3Params.isSsl()
        );
    }

    private static class ExchangeParams {
        private Map<String, String> params;
        private SecurityUtils securityUtils;

        public ExchangeParams(Binding binding, Map<String, String> params) {
            this.params = params;
            this.securityUtils = new SecurityUtils(binding);
        }

        public String getServer() {
            return params.get("mail_server");
        }

        public String getDomain() {
            return params.get("mail_domain");
        }

        public SecureEntryDTO getUserPasswordPair() {
            return securityUtils.getSecureEntry(params.get("mail_credential_alias"));
        }

        public ExchangeVersion getExchangeVersion() {
            return ExchangeVersion.valueOf(params.get("exchange_version"));
        }
    }

    private static class ImapPop3Params {
        private Map<String, String> params;
        private SecurityUtils securityUtils;

        public ImapPop3Params(Binding binding, Map<String, String> params) {
            this.params = params;
            this.securityUtils = new SecurityUtils(binding);
        }

        public ImapPop3EmailClient.SupportedProtocol getProtocol() {
            return ImapPop3EmailClient.SupportedProtocol.valueOf(params.get("mail_protocol").toUpperCase());
        }

        public String getHost() {
            return params.get("mail_host");
        }

        public String getPort() {
            return params.get("mail_port");
        }

        public SecureEntryDTO getUserPasswordPair() {
            return securityUtils.getSecureEntry(params.get("mail_credential_alias"));
        }

        public boolean isSsl() {
            return Boolean.valueOf(params.get("mail_ssl"));
        }
    }
}
