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

import be.iminds.ilabt.jfed.ApplicationParametersModule;
import be.iminds.ilabt.jfed.lowlevel.GeniUserProvider;
import be.iminds.ilabt.jfed.lowlevel.user.UserLoginInfo;
import be.iminds.ilabt.jfed.lowlevel.user.UserLoginInfoFactory;
import be.iminds.ilabt.jfed.util.GeniUrn;
import be.iminds.ilabt.jfed.util.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.inject.Inject;
import javax.xml.bind.DatatypeConverter;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.Map;
import java.util.Objects;

/**
 * Checks whether the given parameters match the user that is currently signed in
 */
public class LoginValidationParameterHandler implements ParameterHandler<Boolean> {
    private static final Logger LOG = LoggerFactory.getLogger(LoginValidationParameterHandler.class);

    private final GeniUserProvider geniUserProvider;
    private final UserLoginInfoFactory userLoginInfoFactory;
    private final ApplicationParametersModule.ApplicationParameters applicationParameters;

    @Inject
    public LoginValidationParameterHandler(GeniUserProvider geniUserProvider,
                                           UserLoginInfoFactory userLoginInfoFactory,
                                           ApplicationParametersModule.ApplicationParameters applicationParameters) {
        this.geniUserProvider = geniUserProvider;
        this.userLoginInfoFactory = userLoginInfoFactory;
        this.applicationParameters = applicationParameters;
    }

    @Override
    public Boolean handleParameters() {
        Map<String, String> parameters = applicationParameters.getParameters();
        String loginCertificate = null;

        if (parameters.containsKey(StartupParameters.PARAM_LOGIN_CERTIFICATE_STRING)) {
            final String loginCertificateString = parameters.get(StartupParameters.PARAM_LOGIN_CERTIFICATE_STRING);

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

            try {
                byte[] decodedLoginCertificate = DatatypeConverter.parseBase64Binary(loginCertificateString);
                loginCertificate = new String(decodedLoginCertificate);
            } catch (IllegalArgumentException ex) {
                LOG.warn("Could not Base64-decode login-certificate-string. Ignoring!", ex);
            }
        }

        if (parameters.containsKey(StartupParameters.PARAM_LOGIN_CERTIFICATE)) {

            try {
                URL loginCertificateLocation = new URL(parameters.get(StartupParameters.PARAM_LOGIN_CERTIFICATE));
                loginCertificate = IOUtils.urlToString(loginCertificateLocation, Charset.defaultCharset());

            } catch (MalformedURLException ex) {
                LOG.error("Could not parse provided login certificate location", ex);
            } catch (IOException ex) {
                LOG.error("Could not fetch the login certificate", ex);

            }

        }

        if (loginCertificate != null) {
            GeniUrn newUserUrn =
                    deriveUserUrnFromCertificate(loginCertificate);

            if (geniUserProvider.isUserLoggedIn() && !Objects.equals(geniUserProvider.getLoggedInGeniUser().getUserUrn(), newUserUrn)) {
                LOG.error("Got an URI with different login credentials ({}) than the user currently logged in ({})",
                        newUserUrn, geniUserProvider.getLoggedInGeniUser().getUserUrn());

                return false;
            } else {
                LOG.info("Got an URI with same login credentials as currently logged in user ({})", newUserUrn);
                return true;
            }
        } else {
            LOG.debug("Got an URI without login information.");
            return true;
        }
    }


    private GeniUrn deriveUserUrnFromCertificate(String certificate) {
        UserLoginInfo userLoginInfo = userLoginInfoFactory.createManualUserLoginInfo(certificate);

        return userLoginInfo.getUserUrn();
    }
}
