package org.jivesoftware.smackx.signed.xep0285.signing;

import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.bouncycastle.openpgp.PGPSignature;
import org.bouncycastle.util.io.Streams;
import org.pgpainless.PGPainless;
import org.pgpainless.algorithm.HashAlgorithm;
import org.pgpainless.algorithm.PublicKeyAlgorithm;
import org.pgpainless.decryption_verification.OpenPgpMetadata;
import org.pgpainless.encryption_signing.EncryptionStream;
import org.pgpainless.key.protection.SecretKeyRingProtector;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;

public class OpenPGPSigner implements Signer {

    private final SecretKeyRingProtector protector;
    private final PGPSecretKeyRing secretKey;

    public OpenPGPSigner(PGPSecretKeyRing secretKey, SecretKeyRingProtector protector) {
        this.protector = protector;
        this.secretKey = secretKey;
    }

    @Override
    public PGPSignature createSignature(byte[] data) throws IOException {
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        ByteArrayInputStream inputStream = new ByteArrayInputStream(data);
        try {
            EncryptionStream signer = PGPainless.createEncryptor().onOutputStream(outputStream)
                    .doNotEncrypt()
                    .createDetachedSignature()
                    .signWith(protector, secretKey)
                    .noArmor();
            Streams.pipeAll(inputStream, signer);
            signer.close();
            inputStream.close();
            outputStream.close();
            OpenPgpMetadata metadata = signer.getResult();
            return metadata.getSignatures().iterator().next();

        } catch (PGPException e) {
            throw new IOException(e);
        }
    }

    @Override
    public String getAlgorithmName(PGPSignature signature) {
        PublicKeyAlgorithm signAlgo = PublicKeyAlgorithm.fromId(signature.getKeyAlgorithm());

        String signAlgoName;
        switch (signAlgo) {
            case RSA_GENERAL:
            case RSA_ENCRYPT:
            case RSA_SIGN:
                signAlgoName = "RSA";
                break;
            case DSA:
                signAlgoName = "DSA";
                break;
            case ECDSA:
                signAlgoName = "ECDSA";
                break;
            default:
                throw new IllegalArgumentException("Signature was signed with unknown signature algorithm: " + signature.getKeyAlgorithm());
        }

        signAlgoName += HashAlgorithm.fromId(signature.getHashAlgorithm());
        return signAlgoName;
    }
}
