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

import be.iminds.ilabt.jfed.call_log_output.SerializableApiCallDetails;
import be.iminds.ilabt.jfed.experimenter_gui.ui.TextFlowUtil;
import be.iminds.ilabt.jfed.lowlevel.GeniUserProvider;
import be.iminds.ilabt.jfed.lowlevel.JFedException;
import be.iminds.ilabt.jfed.lowlevel.XmlRpcApiCallReply;
import javafx.scene.control.Alert;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Priority;
import javafx.scene.text.TextFlow;
import org.apache.xml.security.utils.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.inject.Inject;
import javax.inject.Singleton;
import java.security.cert.CertificateEncodingException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * User: twalcari
 * Date: 9/30/2015
 * Time: 11:41
 */
@Singleton
public class BonfireLicenseUtil {
    private static final Logger LOG = LoggerFactory.getLogger(BonfireLicenseUtil.class);
    private static final String BONFIRE_LICENSE_ERROR_INDICATOR =
            "Could not find a registered BonFIRE user from the credentials";

    private static final Pattern FILTER_PATTERN =
            Pattern.compile("'([^']*" + BONFIRE_LICENSE_ERROR_INDICATOR + "[^']*)'");

    private final TextFlowUtil textFlowUtil;
    private final GeniUserProvider geniUserProvider;

    @Inject
    BonfireLicenseUtil(TextFlowUtil textFlowUtil, GeniUserProvider geniUserProvider) {
        this.textFlowUtil = textFlowUtil;
        this.geniUserProvider = geniUserProvider;
    }


    public boolean showBonfireLicenseAlert(Throwable t) {
        return showBonfireLicenseAlert(getBonfireLicenseExceptionText(t));
    }

    public boolean showBonfireLicenseAlert(SerializableApiCallDetails details) {
        return showBonfireLicenseAlert(getBonfireLicenseExceptionText(details));
    }

    private boolean showBonfireLicenseAlert(String bonfireLicenseExceptionText) {
        TextFlow exceptionTextFlow = textFlowUtil.textWithUrlsToTextFlow(
                bonfireLicenseExceptionText);

        Alert alert = new Alert(Alert.AlertType.ERROR);

        alert.setTitle("Bonfire License issue");
        alert.setHeaderText("Bonfire license issue");

        alert.getDialogPane().setContent(exceptionTextFlow);


        //set user certificate in expandable content

        Label label = new Label("You can register using the following certificate:");

        String certificateString = "-----BEGIN CERTIFICATE-----\n";
        certificateString +=
                geniUserProvider.getLoggedInGeniUser().getClientCertificateChain().stream().
                        map(x509Certificate -> {
                            try {
                                return Base64.encode(x509Certificate.getEncoded());
                            } catch (CertificateEncodingException e) {
                                LOG.error("Could not encode certificate");
                                return "";
                            }
                        }).collect(Collectors.joining());
        certificateString += "\n";
        certificateString += "-----END CERTIFICATE-----";


        TextArea textArea = new TextArea(certificateString);
        textArea.setEditable(false);
        textArea.setWrapText(true);

        textArea.setMaxWidth(Double.MAX_VALUE);
        textArea.setMaxHeight(Double.MAX_VALUE);
        GridPane.setVgrow(textArea, Priority.ALWAYS);
        GridPane.setHgrow(textArea, Priority.ALWAYS);

        GridPane expContent = new GridPane();
        expContent.setMaxWidth(Double.MAX_VALUE);
        expContent.add(label, 0, 0);
        expContent.add(textArea, 0, 1);
        alert.getDialogPane().setExpandableContent(expContent);


        alert.getDialogPane().setPrefWidth(500);
        alert.showAndWait();

        return true;
    }


    public static boolean isBonfireLicenseException(Throwable t) {
        return getBonfireLicenseExceptionText(t) != null;
    }

    private static String getBonfireLicenseExceptionText(Throwable t) {
        while (t != null) {
            if (t instanceof JFedException) {
                String bonfireException = getBonfireLicenseExceptionText(((JFedException) t).getXmlRpcReply());
                if (bonfireException != null)
                    return bonfireException;

            }
            t = t.getCause();
        }
        return null;
    }

    private static String getBonfireLicenseExceptionText(XmlRpcApiCallReply<?> xmlRpcApiCallReply) {
        if (xmlRpcApiCallReply == null)
            return null;

        if (xmlRpcApiCallReply.getOutput() != null &&
                xmlRpcApiCallReply.getOutput().contains("Could not find a registered BonFIRE user from the credentials")) {
            return xmlRpcApiCallReply.getOutput();
        } else if (xmlRpcApiCallReply.getValue() != null
                && xmlRpcApiCallReply.getValue() instanceof String
                && ((String) xmlRpcApiCallReply.getValue()).contains(BONFIRE_LICENSE_ERROR_INDICATOR)) {
            return cleanupError((String) xmlRpcApiCallReply.getValue());
        } else
            return null;
    }

    private static String getBonfireLicenseExceptionText(SerializableApiCallDetails details) {
        if (details == null)
            return null;
        if (details.getXmlRpcGeniResponseOutput() != null &&
                details.getXmlRpcGeniResponseOutput().contains(BONFIRE_LICENSE_ERROR_INDICATOR)) {
            return details.getXmlRpcGeniResponseOutput();
        } else if (details.getRawValue() != null && details.getRawValue().contains(BONFIRE_LICENSE_ERROR_INDICATOR)) {
            return cleanupError(details.getRawValue());

        } else
            return null;
    }

    private static String cleanupError(String result) {
        //if the bonfire-notice is surrounded by '-marks, then we filter this out
        Matcher matcher = FILTER_PATTERN.matcher(result);

        if (matcher.find()) {
            result = matcher.group(1); //group 1 contains everything between the '-marks
        }

        result = result.replace("\\n", "\n");

        return result;
    }

    public static boolean isBonfireLicenseException(SerializableApiCallDetails details) {
        return getBonfireLicenseExceptionText(details) != null;
    }
}
