/*
 * Copyright 2018 Scytl Secure Electronic Voting SA
 *
 * All rights reserved
 *
 * See our extended copyright notice in *file 'Copyright.txt'
 * which is part of this source code package
 */

package com.scytl.slogger;

import static java.nio.file.Files.createTempDirectory;

import com.scytl.slogger.crypto.SecureLoggerCryptographyFactory;
import com.scytl.slogger.crypto.SecureLoggerCryptographyProvider;
import com.scytl.slogger.crypto.SecureLoggerKeyStore;
import com.scytl.slogger.policy.LogFileNamePolicies;
import com.scytl.slogger.policy.SequentialDateFileNamePolicy;
import com.scytl.slogger.util.LogValidator;

import org.apache.log4j.Level;
import org.apache.log4j.Logger;

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.security.GeneralSecurityException;
import java.security.KeyPair;
import java.security.PrivateKey;

/**
 * E2E test which uses {@link DeferredSecureAppender}.
 *
 * @author aakimov
 */
public class DeferredEndToEndTest {
  private static final String NAME = "AUDIT";

  private static final String VERIFY_PATTERN =
      "TIMESTAMP LEVEL - CLASS (FILE:LINE) [THREAD] - MESSAGE";

  private static final String PATTERN = "%d %p - %C (%F:%L) [%t] - %m%n";

  private static final char[] SIGNATURE_PKCS12_PASSWORD = "GXXCNJH48X5F649VRY52".toCharArray();

  private static final char[] CIPHER_PKCS12_PASSWORD = "649VRY52GXXCNJH48X5F".toCharArray();

  private static final String SIGNATURE_PKCS12_FILE = "/signatureKeyStore.p12";

  private static final String CIPHER_PKCS12_FILE = "/cipherKeyStore.p12";

  private static final String FILE_NAME = "test-audit.log";

  /**
   * The main method.
   *
   * @param args
   * @throws IOException
   * @throws SecureLoggerException
   * @throws GeneralSecurityException
   */
  public static void main(String[] args)
      throws IOException, SecureLoggerException, GeneralSecurityException {
    Path folder = createTempDirectory("slogger");
    Path file = generateLogFile(folder);
    validateLogFile(file);
    System.err.println(folder);
  }

  private static Path generateLogFile(Path folder)
      throws SecureLoggerException, GeneralSecurityException {
    Path file = folder.resolve(FILE_NAME);

    DeferredSecureAppender appender = new DeferredSecureAppender();
    appender.setName(NAME);
    appender.setPattern(PATTERN);
    appender.setVerifyPattern(VERIFY_PATTERN);
    appender.setFile(file.toString());
    appender.setEncoding(StandardCharsets.UTF_8.name());
    appender.setNumberLogLines(100);
    appender.setTimerLogMilliseconds(4000);
    appender.setTriggeringTime(1000);
    appender.setVerifyPattern(VERIFY_PATTERN);
    appender.setLogFileNamePolicyName(LogFileNamePolicies.SEQUENTIAL_DATE_FILENAME.name());

    SecureLoggerCryptographyProvider cryptographyProvider =
        new SecureLoggerCryptographyFactory().build();
    PrivateKey signaturePrivateKey = getSignaturePrivateKey(cryptographyProvider);
    KeyPair cipherKeyPair = getCipherKeyPair(cryptographyProvider);
    appender.activateOptions(signaturePrivateKey, cipherKeyPair.getPrivate(),
        cipherKeyPair.getPublic());

    Logger logger = Logger.getRootLogger();
    logger.setLevel(Level.INFO);
    logger.addAppender(appender);
    logger.info("Administration Board activating…");

    appender.close();

    return file;
  }

  private static PrivateKey getSignaturePrivateKey(
      SecureLoggerCryptographyProvider cryptographyProvider) throws GeneralSecurityException {
    SecureLoggerKeyStore store;
    try (InputStream stream =
        DeferredEndToEndTest.class.getResourceAsStream(SIGNATURE_PKCS12_FILE)) {
      store = cryptographyProvider.readKeyStore(stream, SIGNATURE_PKCS12_PASSWORD);
    } catch (IOException e) {
      throw new IllegalStateException("Failed to load the signature key store.", e);
    }
    return cryptographyProvider.getUserSignaturePrivateKey(store, SIGNATURE_PKCS12_PASSWORD);
  }

  private static KeyPair getCipherKeyPair(SecureLoggerCryptographyProvider cryptographyProvider)
      throws GeneralSecurityException {
    SecureLoggerKeyStore store;
    try (InputStream stream = DeferredEndToEndTest.class.getResourceAsStream(CIPHER_PKCS12_FILE)) {
      store = cryptographyProvider.readKeyStore(stream, CIPHER_PKCS12_PASSWORD);
    } catch (IOException e) {
      throw new IllegalStateException("Failed to load the signature key store.", e);
    }
    return new KeyPair(cryptographyProvider.getUserCipherPublicKey(store),
        cryptographyProvider.getUserCipherPrivateKey(store, CIPHER_PKCS12_PASSWORD));
  }

  private static void validateLogFile(Path file) {
    String certificateFile = DeferredEndToEndTest.class.getResource("/test.crt").getFile();
    String[] args = {"-c", certificateFile, "-l", file.toString(), "-e",
        StandardCharsets.UTF_8.name(), "-p", PATTERN, "-v", VERIFY_PATTERN, "-o",
        file.getParent().toString(), "-n", SequentialDateFileNamePolicy.class.getName()};
    LogValidator.main(args);
  }
}
