package lc.esp.job;

import lc.mecha.http.server.HttpServer;
import lc.mecha.log.MechaLogger;
import lc.mecha.log.MechaLoggerFactory;
import lc.mecha.security.CertUtil;
import lc.mecha.security.CertificateKeyStore;
import lc.mecha.security.KeyUtil;
import org.bouncycastle.operator.OperatorCreationException;

import java.io.IOException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Objects;
import java.util.UUID;

/**
 * @author Alex Leigh
 * @since mk20 (TOKYO PROTOCOL)
 */
public abstract class ESPJob {
    private static final MechaLogger logger = MechaLoggerFactory.getLogger(ESPJob.class);
    private final ESPControlPlane controlPlane;

    public ESPJob() throws CertificateException, KeyStoreException, IOException,
            NoSuchAlgorithmException, OperatorCreationException, CloneNotSupportedException {
        controlPlane = new ESPControlPlane(loadCertificateKeyStore());
    }

    public void start() {
        logger.info("Control plane starting.");
        controlPlane.start();
    }

    /**
     * Provide a certificate store for this ESP job's control plane. This must include a server certificate. The
     * default implementation of this method provides a self-signed key.
     */

    public CertificateKeyStore loadCertificateKeyStore() throws KeyStoreException, CertificateException,
            IOException, NoSuchAlgorithmException, OperatorCreationException {
        final var ks = KeyStore.getInstance(KeyStore.getDefaultType());
        final var pw = UUID.randomUUID().toString();
        ks.load(null, null);
        var kp = KeyUtil.generateRSAKeyPair(1024);
        var cert = CertUtil.selfSign(kp, "cn=localhost");
        var keyPass = pw.toCharArray();
        var chain = new X509Certificate[]{cert};
        ks.setKeyEntry(HttpServer.SSL_CERTIFICATE_ALIAS, kp.getPrivate(), keyPass, chain);
        return new CertificateKeyStore(ks, pw);
    }

    @Override
    public String toString() {
        return "EspJob{" +
                "controlPlane=" + controlPlane +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        ESPJob espJob = (ESPJob) o;
        return Objects.equals(controlPlane, espJob.controlPlane);
    }

    @Override
    public int hashCode() {
        return Objects.hash(controlPlane);
    }
}
