package be.iminds.ilabt.jfed.lowlevel.user;

import be.iminds.ilabt.jfed.lowlevel.authority.AuthorityFinder;
import be.iminds.ilabt.jfed.lowlevel.userloginmodel.InvalidLoginException;
import org.apache.commons.configuration.Configuration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Objects;

/**
 * User: twalcari
 * Date: 7/15/2016
 * Time: 09:00
 */
public class PreferencesUserLoginInfoManager implements UserLoginInfoManager {
    private static final Logger LOG = LoggerFactory.getLogger(PreferencesUserLoginInfoManager.class);

    private static final String PREFS_KEY_SOURCE = "source";

    /**
     * Used to save certificate location
     */
    private static final String PREFS_KEY_CERT_FILE_URI = "keyCertFileURI";

    /**
     * Used to save user authority URN when saving ManualUserLoginInfo
     */
    private static final String PREFS_USER_AUTH_URN = "userauthurn";
    /**
     * Used to save user URN when saving ManualUserLoginInfo
     */
    private static final String PREFS_USER_URN = "userurn";
    protected static final String SOURCE_FILE = "FILE";
    protected static final String SOURCE_URL = "URL";
    protected static final String SOURCE_STRING = "STRING";


    private final Configuration configuration;
    private final GeniUserFactory geniUserFactory;
    private final AuthorityFinder authorityFinder;

    public PreferencesUserLoginInfoManager(Configuration configuration, GeniUserFactory geniUserFactory, AuthorityFinder authorityFinder) {
        this.configuration = configuration;
        this.geniUserFactory = geniUserFactory;
        this.authorityFinder = authorityFinder;
    }


    @Override
    public void save(UserLoginInfo userLoginInfo) {
        clearConfiguration();

        if (userLoginInfo instanceof KeyCertFileUserLoginInfo) {
            KeyCertFileUserLoginInfo keyCertFileUserLoginInfo = (KeyCertFileUserLoginInfo) userLoginInfo;
            configuration.setProperty(PREFS_KEY_SOURCE, SOURCE_FILE);
            configuration.setProperty(PREFS_KEY_CERT_FILE_URI, keyCertFileUserLoginInfo.getFile().toURI().toString());
        } else if (userLoginInfo instanceof KeyCertUrlUserLoginInfo) {
            KeyCertUrlUserLoginInfo keyCertUrlUserLoginInfo = (KeyCertUrlUserLoginInfo) userLoginInfo;
            configuration.setProperty(PREFS_KEY_SOURCE, SOURCE_URL);
            configuration.setProperty(PREFS_KEY_CERT_FILE_URI, keyCertUrlUserLoginInfo.getUrl().toString());
        } else if (userLoginInfo instanceof ManualUserLoginInfo) {
            ManualUserLoginInfo manualUserLoginInfo = (ManualUserLoginInfo) userLoginInfo;
            configuration.setProperty(PREFS_KEY_SOURCE, SOURCE_STRING);
            if (manualUserLoginInfo.getUserUrn() != null)
                configuration.setProperty(PREFS_USER_URN, manualUserLoginInfo.getUserUrn().toString());
            if (manualUserLoginInfo.getUserAuthorityServer() != null)
                configuration.setProperty(PREFS_USER_AUTH_URN, manualUserLoginInfo.getUserAuthorityServer().getDefaultComponentManagerUrn());
        }
    }

    private void clearConfiguration() {
        configuration.clearProperty(PREFS_KEY_SOURCE);
        configuration.clearProperty(PREFS_KEY_CERT_FILE_URI);
        configuration.clearProperty(PREFS_USER_URN);
        configuration.clearProperty(PREFS_USER_AUTH_URN);
    }

    @Override
    public UserLoginInfo load() throws InvalidLoginException {
        final String sourceType = configuration.getString(PREFS_KEY_SOURCE);

        if (Objects.equals(SOURCE_FILE, sourceType)) {
            String fileLocation = configuration.getString(PREFS_KEY_CERT_FILE_URI);
            if (fileLocation == null)
                throw new InvalidLoginException("File location is not present in configuration");


            File file;
            try {
                URL fileUrl = new URL(fileLocation);
                file = new File(fileUrl.getPath());
            } catch (MalformedURLException e) {
                LOG.debug("Could not parse file URI in configuration. Trying to revert to non-URI file path.");
                file = new File(configuration.getString(PREFS_KEY_CERT_FILE_URI));
            }


            try {
                return new KeyCertFileUserLoginInfo(file, geniUserFactory, authorityFinder);
            } catch (IOException e) {
                throw new InvalidLoginException("Cannot process login file '" + fileLocation + "'", e);
            }
        } else if (Objects.equals(SOURCE_URL, sourceType)) {

            String url = configuration.getString(PREFS_KEY_CERT_FILE_URI);
            if (url == null)
                throw new InvalidLoginException("URL is not present in configuration");

            try {
                return new KeyCertUrlUserLoginInfo(new URL(url), geniUserFactory, authorityFinder);
            } catch (IOException e) {
                throw new InvalidLoginException("Cannot process login url '" + url + "'", e);
            }
        } else if (Objects.equals(SOURCE_STRING, sourceType)) {
            return null;
            //we cannot restore the ManualUserLoginInfo as the keyCertContent is not saved!

            //String userUrn = configuration.getString(PREFS_USER_URN);
            //String userAuthUrn = configuration.getString(PREFS_USER_AUTH_URN);

            //Server userAuthServer = authorityFinder.findByUrn(userAuthUrn, AuthorityFinder.Purpose.FIND_USERAUTH);
            //return new ManualUserLoginInfo(null, GeniUrn.parse(userUrn), userAuthServer, geniUserFactory);
        } else {
            LOG.info("No configuration found. Reverting to defaults");
            return defaults();
        }
    }

    @Override
    public UserLoginInfo reset() {
        clearConfiguration();

        return defaults();
    }

    @Override
    public UserLoginInfo defaults() {
        return null;
    }
}
