package de.ivu.elect.nl.interfaces.gbav;

import org.apache.cxf.helpers.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;


public class GbavKeyStoreInitializer {

  protected static final String ROOT_CERTIFICATE_ALIAS = "tnt";

  private static final Logger LOGGER = LoggerFactory.getLogger(GbavKeyStoreInitializer.class);

  public static final String GBAV_KEYSTORE_PFAD = "gbav_keystore";
  private final String keystorePassword;
  private final String privateKeyPassword;

  public GbavKeyStoreInitializer(KeyStoreDaten keyStoreDaten) throws CertificateException, NoSuchAlgorithmException, KeyStoreException, IOException {
    this.keystorePassword = keyStoreDaten.getPrivateKeyPassword();
    this.privateKeyPassword = keyStoreDaten.getPrivateKeyPassword();

    deleteKeyStoreIfExists();
    initialize(keyStoreDaten);
  }

  private void deleteKeyStoreIfExists() {
    File keyStore = new File(GBAV_KEYSTORE_PFAD);
    if (keyStore.exists()) {
      FileUtils.delete(keyStore);
    }
  }

  private void initialize(KeyStoreDaten keyStoreDaten) throws CertificateException, NoSuchAlgorithmException, KeyStoreException, IOException {
    KeyStore keyStore = loadKeyStore();

    importPrivateCertificate(keyStore, keyStoreDaten.getPrivateCertificatePath(), keyStoreDaten.getPrivateKeyPassword());
    importRootCertificate(keyStore, keyStoreDaten.getRootCertificatePath());

    saveKeyStore(keyStore);
  }


  public String getPrivateKeyPassword() {
    return privateKeyPassword;
  }

  private void importRootCertificate(KeyStore keyStore, String filename) throws IOException, CertificateException, KeyStoreException {
    keyStore.deleteEntry(ROOT_CERTIFICATE_ALIAS);
    Certificate certificate = generateCertificate(filename);
    keyStore.setCertificateEntry(ROOT_CERTIFICATE_ALIAS, certificate);
  }

  private void importPrivateCertificate(KeyStore keyStore, String filename, String password) throws CertificateException, NoSuchAlgorithmException, IOException {
    keyStore.load(new FileInputStream(filename), password.toCharArray());
  }

  private void saveKeyStore(KeyStore keyStore) throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException {
    FileOutputStream out = new FileOutputStream(GBAV_KEYSTORE_PFAD);
    keyStore.store(out, keystorePassword.toCharArray());
    out.close();
  }

  private Certificate generateCertificate(String filename) throws IOException, CertificateException {
    try (InputStream inputStream = new BufferedInputStream(new FileInputStream(filename))) {
      return CertificateFactory.getInstance("X.509").generateCertificate(inputStream);
    }
  }

  protected KeyStore loadKeyStore() throws KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException {
    File file = new File(GBAV_KEYSTORE_PFAD);
    KeyStore keyStore = KeyStore.getInstance("JKS");
    if (file.exists()) {
      try (FileInputStream stream = new FileInputStream(file)) {
        keyStore.load(stream, keystorePassword.toCharArray());
      }
    } else {
      keyStore.load(null, null);
      try (FileOutputStream stream = new FileOutputStream(file)) {
        keyStore.store(stream, keystorePassword.toCharArray());
      }
    }
    return keyStore;
  }


}
