package dev.rusatom.keycloak.modules;

import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.util.Base64;
import java.util.logging.Logger;
import java.util.logging.Level;

public class CliSigner implements Signer {

	private final static Logger LOGGER = Logger.getLogger(CliSigner.class.getName());

	public static void main(String[] args) {
		Signer s = new CliSigner();
		String data = "aaa";
		System.out.println(s.signString(data));
	}
	
	public CliSigner() {
		LOGGER.setLevel(Level.FINER);
		String v = System.getenv("KEYPATH");
		if (v != null && new File(v).exists()) {
			LOGGER.config("KEYPATH :" + v);
			KEYPATH=v;
		}
		v = System.getenv("CRTPATH");
		if (v != null && new File(v).exists()) {
			LOGGER.config("CRTPATH :" + v);
			CRTPATH=v;
		}
		v = System.getenv("KEYPASS");
		if (v != null) {
			LOGGER.config("KEYPASS :" + v);
			KEYPASS=v;
		}

	}
	public static boolean isAlive(Process p) {
		try {
			p.exitValue();
			return false;
		} catch (IllegalThreadStateException e) {
			return true;
		}
	}

	String CRTPATH = "/etc/private/crt.pem";
	String KEYPATH = "/etc/private/key.pem";
	String KEYPASS = "1";
	String CMD = "/usr/local/ssl/bin/openssl smime -sign -outform DER -binary -noattr -signer %s -inkey %s -passin pass:%s -in %s -out %s";
	public String signString(String data) {
		
		byte[] bufferArray = new byte[4000];
		ByteArrayOutputStream buffer = new ByteArrayOutputStream();
		File dataFile = null;
		File signFile = null;
		byte[] sign = null;
		try {
			dataFile = File.createTempFile("data", ".txt");
			signFile = File.createTempFile("sign", ".sgn");

			writeData(data, dataFile);
			ProcessBuilder builder = new ProcessBuilder(prepare(dataFile, signFile));
			builder.redirectErrorStream(true); // so we can ignore the error stream
			Process process = builder.start();
			InputStream out = process.getInputStream();
			while (isAlive(process)) {
				int no = out.available();
				if (no > 0) {
					int n = out.read(bufferArray, 0, Math.min(no, bufferArray.length));
					buffer.write(bufferArray, 0, n);
				}
			}
			sign = Files.readAllBytes(signFile.toPath());

		} catch (Exception e) {
			LOGGER.warning(e.toString());
		} finally {
			if(!LOGGER.isLoggable(Level.FINER)){
				if (dataFile != null && dataFile.exists()) dataFile.delete();
				if (signFile != null && signFile.exists()) signFile.delete();
			}
		}
		return Base64.getUrlEncoder().encodeToString(sign);
	}

	private void writeData(String data, File dataFile) throws IOException {
		BufferedWriter writer = new BufferedWriter(new FileWriter(dataFile, true));
		writer.append(data);
		writer.close();		
	}

	private String[] prepare(File dataFile, File signFile) throws IOException {
		String cmd = String.format(CMD, CRTPATH, KEYPATH, KEYPASS, dataFile.getCanonicalPath(), signFile.getCanonicalPath());
		LOGGER.config(cmd);
		return cmd.split(" ");
	}
}
