package be.iminds.ilabt.jfed.experimenter_gui.ext_requests;

import be.iminds.ilabt.jfed.ApplicationParametersModule;
import be.iminds.ilabt.jfed.experimenter_gui.login.UserLoginDirector;
import be.iminds.ilabt.jfed.lowlevel.user.UserLoginInfo;
import be.iminds.ilabt.jfed.lowlevel.user.UserLoginInfoFactory;
import javafx.stage.Stage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Provider;
import javax.xml.bind.DatatypeConverter;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Map;
import java.util.Objects;

/**
 * User: twalcari
 * Date: 6/26/2015
 * Time: 11:07
 */
public class FirstLoginParametersHandler implements ParameterHandler<UserLoginInfo> {
    private static final Logger LOG = LoggerFactory.getLogger(FirstLoginParametersHandler.class);
    private static final String SCHEME_FILE = "file";

    private final UserLoginInfoFactory userLoginInfoFactory;
    private final Provider<Stage> parentStageProvider;
    private final ApplicationParametersModule.ApplicationParameters applicationParameters;

    @Inject
    public FirstLoginParametersHandler(
            UserLoginInfoFactory userLoginInfoFactory, @Named("parentStage") Provider<Stage> parentStageProvider,
            ApplicationParametersModule.ApplicationParameters applicationParameters) {
        this.userLoginInfoFactory = userLoginInfoFactory;
        this.parentStageProvider = parentStageProvider;
        this.applicationParameters = applicationParameters;
    }


    @Override
    public UserLoginInfo handleParameters() {
        Map<String, String> params = applicationParameters.getParameters();
        LOG.debug("Handling FirstLoginParameters");

        //check if we got login-information via the parameters
        if (params.containsKey(StartupParameters.PARAM_LOGIN_CERTIFICATE)) {
            String loginCertificateLocation = params.get(StartupParameters.PARAM_LOGIN_CERTIFICATE);

            LOG.info("Found login-certificate in parameters. URI={}", loginCertificateLocation);
            try {
                URI uri = new URI(loginCertificateLocation);
                UserLoginInfo result = tryLoginWithUri(uri);
                if (result != null)
                    return result;
            } catch (URISyntaxException ex) {
                LOG.error("Could not parse provided login certificate location", ex);
            }
        }

        if (params.containsKey(StartupParameters.PARAM_LOGIN_CERTIFICATE_STRING)) {

            String loginCertificateString =
                    params.get(StartupParameters.PARAM_LOGIN_CERTIFICATE_STRING);

            LOG.info("Found login-certificate string in parameters. size={}", loginCertificateString.length());

            try {
                byte[] decodedLoginCertificate = DatatypeConverter.parseBase64Binary(loginCertificateString);

                String decodedLoginCertificateString = new String(decodedLoginCertificate);
                LOG.trace("Base64-decoded login certificate (size={})", decodedLoginCertificateString.length());

                UserLoginInfo result = tryLoginWithString(decodedLoginCertificateString);
                if (result != null)
                    return result;
            } catch (IllegalArgumentException ex) {
                LOG.warn("Could not Base64-decode login-certificate-string", ex);
            }

        }

        if (params.containsKey(StartupParameters.PARAM_LOGIN_HASH)) {

            File loginCertFile = UserLoginDirector.getLoginCertificateFile(params.get(StartupParameters.PARAM_LOGIN_HASH));

            if (loginCertFile.exists()) {
                LOG.info("Found cached certificate with hash {}", params.get(StartupParameters.PARAM_LOGIN_HASH));
                UserLoginInfo result = tryLoginWithUri(loginCertFile.toURI());
                if (result != null)
                    return result;
            } else {
                LOG.info("Could not find cached login certificate with hash {}", params.get(StartupParameters.PARAM_LOGIN_HASH));
            }
        }

        return null;
    }

    private UserLoginInfo tryLoginWithUri(URI uri) {
        //try to update KeyCertUserLoginModel with the new information
        if (Objects.equals(uri.getScheme(), SCHEME_FILE)) {
            File loginCertificateFile = new File(uri);

            try {
                return userLoginInfoFactory.createKeyCertFileUserLoginInfo(loginCertificateFile);
            } catch (IOException e) {
                LOG.error("Error while loading userLoginCertificate from file {}", loginCertificateFile.getAbsolutePath());
                return null;
            }
        } else {
            try {
                return userLoginInfoFactory.createKeyCertUrlUserLoginInfo(uri.toURL());
            } catch (IOException e) {
                LOG.error("Error while loading userLoginCertificate from uri {}", uri.toString());
                return null;
            }
        }
    }

    private UserLoginInfo tryLoginWithString(String loginString) {
        return userLoginInfoFactory.createManualUserLoginInfo(loginString);
    }
}
