package foundation.e.mail.activity.setup;

import android.content.Context;
import android.content.res.XmlResourceParser;
import android.support.annotation.NonNull;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.Locale;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;

import foundation.e.mail.Account;
import foundation.e.mail.K9;
import foundation.e.mail.Preferences;
import foundation.e.mail.account.AccountCreator;
import foundation.e.mail.controller.MessagingController;
import foundation.e.mail.helper.EmailHelper;
import foundation.e.mail.helper.UrlEncodingHelper;
import foundation.e.mail.mail.ServerSettings;
import foundation.e.mail.mail.store.RemoteStore;
import timber.log.Timber;

public class EeloAccountCreator {
    private static AccountConfigImpl accountConfig;

    public static void createAccount(Context context, String emailId, String password) {
        Preferences preferences = Preferences.getPreferences(context);
	
	accountConfig = new AccountConfigImpl(preferences);
        try {
	    String[] emailParts = EmailHelper.splitEmail(emailId);
            AccountSetupPresenter.Provider provider = findProviderForDomain(context, emailParts[1]);
            if (provider != null) {
                modifyAccount(emailId, password, provider);
            }
        }
	catch (Exception e) {
            Timber.e(e, "Error while trying to initialise account configuration.");
        }

        Account account = preferences.newAccount();
        account.setDeviceAccount(true);
        account.loadConfig(accountConfig);

        MessagingController.getInstance(context).listFoldersSynchronous(account, true, null);
        MessagingController.getInstance(context)
                .synchronizeMailbox(account, account.getInboxFolderName(), null, null);

        account.save(preferences);

        preferences.setDefaultAccount(account);

        K9.setServicesEnabled(context);
    }

    private static void modifyAccount(String email, String password,
                                      @NonNull AccountSetupPresenter.Provider provider)
            throws URISyntaxException {
        accountConfig.init(email, password);
        accountConfig.setDescription(email);

        String[] emailParts = EmailHelper.splitEmail(email);
        String user = emailParts[0];
        String domain = emailParts[1];
        String userEnc = UrlEncodingHelper.encodeUtf8(user);
        String passwordEnc = UrlEncodingHelper.encodeUtf8(password);

        String incomingUsername = provider.incomingUsernameTemplate;
        incomingUsername = incomingUsername.replaceAll("\\$email", email);
        incomingUsername = incomingUsername.replaceAll("\\$user", userEnc);
        incomingUsername = incomingUsername.replaceAll("\\$domain", domain);

        URI incomingUriTemplate = provider.incomingUriTemplate;
        String incomingUserInfo = incomingUsername + ":" + passwordEnc;
        URI incomingUri = new URI(incomingUriTemplate.getScheme(), incomingUserInfo,
                incomingUriTemplate.getHost(), incomingUriTemplate.getPort(), null, null, null);

        String outgoingUsername = provider.outgoingUsernameTemplate;

        URI outgoingUriTemplate = provider.outgoingUriTemplate;


        URI outgoingUri;
        if (outgoingUsername != null) {
            outgoingUsername = outgoingUsername.replaceAll("\\$email", email);
            outgoingUsername = outgoingUsername.replaceAll("\\$user", userEnc);
            outgoingUsername = outgoingUsername.replaceAll("\\$domain", domain);

            String outgoingUserInfo = outgoingUsername + ":" + passwordEnc;
            outgoingUri = new URI(outgoingUriTemplate.getScheme(), outgoingUserInfo,
                    outgoingUriTemplate.getHost(), outgoingUriTemplate.getPort(), null,
                    null, null);

        } else {
            outgoingUri = new URI(outgoingUriTemplate.getScheme(),
                    null, outgoingUriTemplate.getHost(), outgoingUriTemplate.getPort(), null,
                    null, null);

        }

        accountConfig.setStoreUri(incomingUri.toString());
        accountConfig.setTransportUri(outgoingUri.toString());

        setupFolderNames(incomingUriTemplate.getHost().toLowerCase(Locale.US));

        ServerSettings incomingSettings = RemoteStore.decodeStoreUri(incomingUri.toString());
        accountConfig.setDeletePolicy(AccountCreator.getDefaultDeletePolicy(incomingSettings.type));
    }

    private static void setupFolderNames(String domain) {
        accountConfig.setDraftsFolderName(K9.getK9String(foundation.e.mail.R.string.special_mailbox_name_drafts));
        accountConfig.setTrashFolderName(K9.getK9String(foundation.e.mail.R.string.special_mailbox_name_trash));
        accountConfig.setSentFolderName(K9.getK9String(foundation.e.mail.R.string.special_mailbox_name_sent));
        accountConfig.setArchiveFolderName(K9.getK9String(foundation.e.mail.R.string.special_mailbox_name_archive));

        // Yahoo! has a special folder for Spam, called "Bulk Mail".
        if (domain.endsWith(".yahoo.com")) {
            accountConfig.setSpamFolderName("Bulk Mail");
        } else {
            accountConfig.setSpamFolderName(K9.getK9String(foundation.e.mail.R.string.special_mailbox_name_spam));
        }
    }

    private static AccountSetupPresenter.Provider findProviderForDomain(Context context,
                                                                        String domain) {
        try {
            XmlResourceParser xml = context.getResources().getXml(foundation.e.mail.R.xml.providers);
            int xmlEventType;
            AccountSetupPresenter.Provider provider = null;
            while ((xmlEventType = xml.next()) != XmlResourceParser.END_DOCUMENT) {
                if (xmlEventType == XmlResourceParser.START_TAG
                        && "provider".equals(xml.getName())
                        && domain.equalsIgnoreCase(getXmlAttribute(context, xml, "domain"))) {
                    provider = new AccountSetupPresenter.Provider();
                    provider.id = getXmlAttribute(context, xml, "id");
                    provider.label = getXmlAttribute(context, xml, "label");
                    provider.domain = getXmlAttribute(context, xml, "domain");
                    provider.note = getXmlAttribute(context, xml, "note");
                } else if (xmlEventType == XmlResourceParser.START_TAG
                        && "incoming".equals(xml.getName())
                        && provider != null) {
                    provider.incomingUriTemplate = new URI(getXmlAttribute(context, xml, "uri"));
                    provider.incomingUsernameTemplate = getXmlAttribute(context, xml, "username");
                } else if (xmlEventType == XmlResourceParser.START_TAG
                        && "outgoing".equals(xml.getName())
                        && provider != null) {
                    provider.outgoingUriTemplate = new URI(getXmlAttribute(context, xml, "uri"));
                    provider.outgoingUsernameTemplate = getXmlAttribute(context, xml, "username");
                } else if (xmlEventType == XmlResourceParser.END_TAG
                        && "provider".equals(xml.getName())
                        && provider != null) {
                    return provider;
                }
            }
            if (provider == null) {
                provider = new AccountSetupPresenter.Provider();
                provider.id = domain;
                provider.label = domain + " mail service";
                provider.domain = domain;
                provider.note = "";
                provider.incomingUriTemplate = new URI("imap+ssl+://mail." + domain);
                provider.incomingUsernameTemplate = "$email";
                provider.outgoingUriTemplate = new URI("smtp+tls+://mail." + domain);
                provider.outgoingUsernameTemplate = "$email";
            }

        } catch (Exception e) {
            Timber.e(e, "Error while trying to load provider settings.");
        }
        return null;
    }

    private static String getXmlAttribute(Context context, XmlResourceParser xml, String name) {
        int resId = xml.getAttributeResourceValue(null, name, 0);
        if (resId == 0) {
            return xml.getAttributeValue(null, name);
        } else {
            return context.getString(resId);
        }
    }
}

