package org.jboss.resteasy.test.crypto.resource;

import java.io.IOException;
import java.io.InputStream;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;

import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.WebApplicationException;

import org.jboss.logging.Logger;
import org.jboss.resteasy.plugins.providers.multipart.InputPart;
import org.jboss.resteasy.plugins.providers.multipart.MultipartInput;
import org.jboss.resteasy.security.PemUtils;
import org.jboss.resteasy.security.smime.EnvelopedInput;
import org.jboss.resteasy.security.smime.SignedInput;
import org.jboss.resteasy.utils.TestApplication;

@Path("/")
public class VerifyDecryptResource {
    private static Logger logger = Logger.getLogger(VerifyDecryptResource.class);

    @POST
    @Path("encrypt")
    public String encrypt(EnvelopedInput<String> input) throws Exception {
        String secret = input.getEntity(privateKey, cert);
        logger.info("secret: " + secret);
        return secret;
    }

    @POST
    @Path("sign")
    public String sign(SignedInput<String> input) throws Exception {
        if (!input.verify(cert)) {
            throw new WebApplicationException(500);
        }
        String secret = input.getEntity();
        logger.info("secret: " + secret);
        return secret;
    }

    @POST
    @Path("encryptSign")
    public String encryptSign(SignedInput<EnvelopedInput<String>> input) throws Exception {
        if (!input.verify(cert)) {
            throw new WebApplicationException(500);
        }
        final EnvelopedInput<String> envelop = input.getEntity();
        String secret = envelop.getEntity(privateKey, cert);
        logger.info("secret: " + secret);
        return secret;
    }

    @POST
    @Path("signEncrypt")
    public String signEncrypt(EnvelopedInput<SignedInput<String>> input) throws Exception {
        SignedInput<String> signedInput = input.getEntity(privateKey, cert);

        if (!signedInput.verify(cert)) {
            throw new WebApplicationException(500);
        }
        String secret = signedInput.getEntity();
        logger.info("secret: " + secret);
        return secret;
    }

    @Path("encryptedEncrypted")
    @POST
    public String encryptedEncrypted(EnvelopedInput<EnvelopedInput<String>> input) throws Exception {
        EnvelopedInput<String> envelope = input.getEntity(privateKey, cert);
        String secret = envelope.getEntity(privateKey, cert);
        logger.info("secret: " + secret);
        return secret;
    }

    @Path("encryptSignSign")
    @POST
    public String encryptSignSign(SignedInput<SignedInput<EnvelopedInput<String>>> input) throws Exception {
        if (!input.verify(cert)) {
            throw new WebApplicationException(500);
        }
        SignedInput<EnvelopedInput<String>> inner = input.getEntity();
        if (!inner.verify(cert)) {
            throw new WebApplicationException(500);
        }
        final EnvelopedInput<String> envelop = inner.getEntity();
        String secret = envelop.getEntity(privateKey, cert);
        logger.info("secret: " + secret);
        return secret;
    }

    @Path("multipartEncrypted")
    @POST
    public String post(EnvelopedInput<MultipartInput> input) throws Exception {
        MultipartInput multipart = input.getEntity(privateKey, cert);
        InputPart inputPart = multipart.getParts().iterator().next();
        String secret = inputPart.getBody(String.class, null);
        logger.info("secret: " + secret);
        return secret;
    }

    public static X509Certificate cert;
    public static PrivateKey privateKey;

    static {
        try {
            cert = PemUtils.decodeCertificate(loadString("mycert.pem"));
            privateKey = PemUtils.decodePrivateKey(loadString("mycert-private.pem"));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private static InputStream loadString(String name) throws IOException {
        InputStream stream = null;
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        if (classLoader != null) {
            stream = classLoader.getResourceAsStream(name);
        }
        if (stream == null) {
            stream = TestApplication.class.getResourceAsStream(name);
        }
        if (stream == null) {
            throw new RuntimeException();
        }
        return stream;
    }
}
