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

import be.iminds.ilabt.jfed.lowlevel.GeniUser;
import be.iminds.ilabt.jfed.lowlevel.ssh_key_info.putty.PpkHelper;
import be.iminds.ilabt.jfed.lowlevel.ssh_key_info.putty.PuTTYPrivateKeyFile;
import be.iminds.ilabt.jfed.util.JFedUtils;
import be.iminds.ilabt.jfed.util.KeyUtil;
import be.iminds.ilabt.jfed.util.tmp_file_helpers.PermanentFile;
import be.iminds.ilabt.jfed.util.tmp_file_helpers.TmpContentFile;
import be.iminds.ilabt.jfed.util.tmp_file_helpers.TmpFile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.File;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.interfaces.RSAPrivateCrtKey;
import java.security.interfaces.RSAPublicKey;

/**
 * User: twalcari
 * Date: 5/27/2016
 * Time: 09:49
 */
public class GeniUserSshKeyInfo implements SshFilesKeyInfo, PuTTYFilesKeyInfo {
    private static final Logger LOG = LoggerFactory.getLogger(GeniUserSshKeyInfo.class);
    @Nonnull
    protected final GeniUser geniUser;

    GeniUserSshKeyInfo(@Nonnull GeniUser geniUser) {
        this.geniUser = geniUser;
    }

    @Override
    public TmpFile getPrivateKeyFile() {
        if (geniUser.getPrivateKeyFile() != null) {
            return new PermanentFile(geniUser.getPrivateKeyFile());
        }

        LOG.debug("geniUser has no privateKeyFile. geniUser class: " + geniUser.getClass().getName());

        return getUnencryptedPrivateKeyFile();
    }

    @Override
    public TmpFile getUnencryptedPrivateKeyFile() {
        File tmpDir = new File(JFedUtils.getUserDataDirectoryFile(), "tmp");
        if (!tmpDir.exists()) //noinspection ResultOfMethodCallIgnored
            tmpDir.mkdir();
        String pemKey = new String(KeyUtil.privateKeyToAnyPem(geniUser.getPrivateKey()));
        return new TmpContentFile("sshKeyUsrUE", ".pem", pemKey, true /*assureUserOnlyPermissions*/);
    }

    @Override
    public boolean hasUnencryptedPrivateKey() {
        return true;
    }

    @Override
    public boolean isLocked() {
        return false;
    }

    @Override
    public boolean unlock(char[] password) {
        throw new IllegalStateException("Cannot unlock GeniUserSshKeyInfo, as this is always unlocked!");
    }

    @Nonnull
    @Override
    public PublicKey getPublicKey() {
        return geniUser.getPublicKey();
    }

    @Override
    public PrivateKey getPrivateKey() {
        return geniUser.getPrivateKey();
    }

    @Nonnull
    public GeniUser getGeniUser() {
        return geniUser;
    }

    @Override
    public TmpFile getPuttyKeyFile() {
        String ppkContent = PpkHelper.getUserEncryptedPPK(geniUser);
        if (ppkContent != null) {
            assert ppkContent.contains("aes256-cbc");

            //we have encrypted key file, so use that.
            TmpFile lockedPuttyFile = new TmpContentFile("sshKeyUsrE", ".ppk", ppkContent);
            LOG.debug("UserSshKeyInfo is using encrypted PPK");
            return lockedPuttyFile;
        } else {
            LOG.debug("UserSshKeyInfo falling back to unencrypted PPK");
            //fall back to unencrypted
            return getUnlockedPuttyKeyFile();
        }
    }

    @Override
    public TmpFile getUnlockedPuttyKeyFile() {
        File tmpDir = new File(JFedUtils.getUserDataDirectoryFile(), "tmp");
        if (!tmpDir.exists()) //noinspection ResultOfMethodCallIgnored
            tmpDir.mkdir();

        String ppkContent = PuTTYPrivateKeyFile.createContent("jFed-tmp-ppk",
                (RSAPublicKey) geniUser.getPublicKey(),
                (RSAPrivateCrtKey) geniUser.getPrivateKey(), null);

        return new TmpContentFile("sskKeyUsrE", ".ppk", ppkContent);
    }

    @Nullable
    @Override
    public String getComment() {
        return geniUser.getUserUrn().getEncodedResourceName() + "@" + geniUser.getUserUrn().getEncodedTopLevelAuthority();
    }
}
