package be.iminds.ilabt.jfed.experimenter_gui.preferences.subsections;

import be.iminds.ilabt.jfed.experimenter_gui.preferences.AbstractPreferencesSubPane;
import be.iminds.ilabt.jfed.experimenter_gui.util.ui.TextFieldWithStatus;
import be.iminds.ilabt.jfed.lowlevel.GeniUserProvider;
import be.iminds.ilabt.jfed.preferences.GuiPreferenceKey;
import be.iminds.ilabt.jfed.preferences.JFedGuiPreferences;
import be.iminds.ilabt.jfed.lowlevel.ssh_key_info.putty.PuTTYPrivateKeyFile;
import be.iminds.ilabt.jfed.ui.javafx.dialogs.JFDialogs;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.Label;
import javafx.stage.FileChooser;

import java.io.File;
import java.io.IOException;

public abstract class SshAuthenticationPane extends AbstractPreferencesSubPane {
    @FXML
    protected Node root;
    @FXML
    protected CheckBox useCertificateCheckBox;
    @FXML
    protected CheckBox useCustomKeyPairCheckBox;
    @FXML
    protected TextFieldWithStatus fileTextField;
    @FXML
    protected Label warnNoLoginKeyLabel;
    @FXML
    protected Button browseButton;

    protected final GeniUserProvider geniUserProvider;
    protected final JFedGuiPreferences jFedPreferences;

    SshAuthenticationPane(GeniUserProvider geniUserProvider, JFedGuiPreferences jFedPreferences) {
        super("SSH Authentication", false);
        this.geniUserProvider = geniUserProvider;
        this.jFedPreferences = jFedPreferences;
    }

    @FXML
    protected void initialize() {
        fileTextField.disableProperty().bind(useCustomKeyPairCheckBox.selectedProperty().not());
        browseButton.disableProperty().bind(useCustomKeyPairCheckBox.selectedProperty().not());

        fileTextField.focusedProperty().addListener((observableValue, oldValue, newValue) -> {
            if (newValue) {
                fileTextField.setStatus(TextFieldWithStatus.Status.NONE);
            } else {
                testPrivateKey();
            }
        });

        if (jFedPreferences.getBoolean(GuiPreferenceKey.PREF_SSH_USE_CUSTOM_KEY)) {
            useCustomKeyPairCheckBox.setSelected(true);

            if (jFedPreferences.getFile(GuiPreferenceKey.PREF_SSH_PUTTY_KEY_FILE) != null) {
                fileTextField.setText(jFedPreferences.getFile(GuiPreferenceKey.PREF_SSH_PUTTY_KEY_FILE).getPath());
            } else {
                if (jFedPreferences.getFile(GuiPreferenceKey.PREF_SSH_PRIVATE_KEY_FILE) != null) {
                    fileTextField.setText(jFedPreferences.getFile(GuiPreferenceKey.PREF_SSH_PRIVATE_KEY_FILE).getPath());
                }
            }
        } else {
            useCustomKeyPairCheckBox.setSelected(false);
            fileTextField.setText("");
            fileTextField.setStatus(TextFieldWithStatus.Status.NONE);
        }

        boolean userCertificateKeys = jFedPreferences.getBoolean(GuiPreferenceKey.PREF_SSH_USE_LOGIN_KEY, true);
        useCertificateCheckBox.setSelected(userCertificateKeys);

        if (!useCertificateCheckBox.isSelected() && !useCustomKeyPairCheckBox.isSelected())
            useCertificateCheckBox.setSelected(true);

        //evaluate inputs
        if (useCustomKeyPairCheckBox.isSelected())
            testPrivateKey();

        //make sure at least one checkbox is always selected
        useCustomKeyPairCheckBox.selectedProperty().addListener((observable, oldValue, newValue) -> {
            if (newValue == false && !useCertificateCheckBox.isSelected()) useCertificateCheckBox.setSelected(true);
        });
        useCertificateCheckBox.selectedProperty().addListener((observable, oldValue, newValue) -> {
            if (newValue == false && !useCustomKeyPairCheckBox.isSelected()) useCustomKeyPairCheckBox.setSelected(true);
        });

        warnNoLoginKeyLabel.visibleProperty().bind(useCertificateCheckBox.selectedProperty().not());
        warnNoLoginKeyLabel.managedProperty().bind(warnNoLoginKeyLabel.visibleProperty());
    }

    protected boolean testPrivateKey() {
        if (fileTextField.getText().length() == 0) {
            fileTextField.setStatus(TextFieldWithStatus.Status.NONE);
            return false;
        }

        try {
            if (testPrivateKeyFile(new File(fileTextField.getText()))) {
                fileTextField.setStatus(TextFieldWithStatus.Status.OK);
                return true;
            } else {
                JFDialogs.create()
                        .owner(root)
                        .message(" Please select a valid private key.")
                        .masthead("The provided key is not valid.")
                        .title("Invalid key file")
                        .showWarning();
                fileTextField.setStatus(TextFieldWithStatus.Status.ERROR);
                return false;
            }
        } catch (IOException ex) {
            JFDialogs.create()
                    .owner(root)
                    .message("An error occured while processing the key file")
                    .masthead("Error")
                    .title("Error")
                    .showException(ex);

            fileTextField.setStatus(TextFieldWithStatus.Status.ERROR);
            return false;
        }
    }

    @FXML
    protected void onBrowsePrivateKeyButtonAction(ActionEvent actionEvent) {
        FileChooser fc = new FileChooser();
        fc.setTitle("Select your Private Key");
        if (getLoggedInUserPrivateKeyFile() != null)
            fc.setInitialDirectory(getLoggedInUserPrivateKeyFile().getParentFile());

        File selectedFile = fc.showOpenDialog(fileTextField.getScene().getWindow());
        if (selectedFile != null) {
            fileTextField.setText(selectedFile.getAbsolutePath());

            testPrivateKey();
        }

    }

    protected abstract boolean testPrivateKeyFile(File file) throws IOException;

    protected File getLoggedInUserPrivateKeyFile() {
        File privateKey;

        return geniUserProvider.getLoggedInGeniUser().getPrivateKeyFile();
    }

    @Override
    public boolean check() {
        if (useCustomKeyPairCheckBox.isSelected()) {
            if (fileTextField.getStatus() != TextFieldWithStatus.Status.OK) {
                JFDialogs.create()
                        .owner(root)
                        .message("The provided private key file is not valid")
                        .showError();
                return false;
            }

            File newPrivKeyFile = new File(fileTextField.getText());
            try {
                PuTTYPrivateKeyFile.isPuttyPrivateKey(newPrivKeyFile);
            } catch (IOException e) {
                JFDialogs.create()
                        .owner(root)
                        .message("The provided private key file is not valid")
                        .showError();
                return false;
            }
        }

        return true;
    }

    @Override
    public boolean save() {
        if (useCustomKeyPairCheckBox.isSelected()) {
            if (fileTextField.getStatus() != TextFieldWithStatus.Status.OK) {
                JFDialogs.create()
                        .owner(root)
                        .message("The provided private key file is not valid")
                        .showError();
                return false;
            }

            File newPrivKeyFile = new File(fileTextField.getText());
            boolean isPuttyFile;
            try {
                isPuttyFile = PuTTYPrivateKeyFile.isPuttyPrivateKey(newPrivKeyFile);
            } catch (IOException e) {
                JFDialogs.create()
                        .owner(root)
                        .message("The provided private key file is not valid")
                        .showError();
                return false;
            }
            if (isPuttyFile) {
                jFedPreferences.clear(GuiPreferenceKey.PREF_SSH_PRIVATE_KEY_FILE);
                jFedPreferences.setFile(GuiPreferenceKey.PREF_SSH_PUTTY_KEY_FILE, newPrivKeyFile);
            } else {
                jFedPreferences.clear(GuiPreferenceKey.PREF_SSH_PUTTY_KEY_FILE);
                jFedPreferences.setFile(GuiPreferenceKey.PREF_SSH_PRIVATE_KEY_FILE, newPrivKeyFile);
            }

            jFedPreferences.setBoolean(GuiPreferenceKey.PREF_SSH_USE_CUSTOM_KEY, true);
        } else
            jFedPreferences.setBoolean(GuiPreferenceKey.PREF_SSH_USE_CUSTOM_KEY, false);

        if (useCertificateCheckBox.isSelected()) {
            jFedPreferences.setBoolean(GuiPreferenceKey.PREF_SSH_USE_LOGIN_KEY, true);
        } else {
            jFedPreferences.setBoolean(GuiPreferenceKey.PREF_SSH_USE_LOGIN_KEY, false);
        }

        return true;
    }
}
