package zmo.technology.lite.signature;

import java.util.UUID;

import org.apache.commons.codec.digest.HmacAlgorithms;
import org.apache.commons.codec.digest.HmacUtils;

public abstract class ZeroSignature<T, I> {

    public static final String SIGN_APP_ID = "app";
    public static final String SIGN_TIMESTAMP = "timestamp";
    public static final String SIGN_NONCE = "nonce";
    public static final String SIGN_SIGNATURE = "signature";

    protected String hmacSHA256Signature(byte[] signString) {
        HmacUtils hmacUtils = new HmacUtils(HmacAlgorithms.HMAC_SHA_256, appSecret);
        return hmacUtils.hmacHex(signString);
    }

    public static class ZeroSignatureQuery {
        private String appID;
        private long timestamp;
        private String nonce;
        private String signature;

        private ZeroSignatureQuery(String appID, long timestamp, String nonce, String signature) {
            super();
            this.appID = appID;
            this.timestamp = timestamp;
            this.nonce = nonce;
            this.signature = signature;
        }

        private ZeroSignatureQuery(String appID) {
            super();
            this.appID = appID;
            this.timestamp = System.currentTimeMillis() / 1000;
            this.nonce = UUID.randomUUID().toString().replace("-", "");
        }

        public static ZeroSignatureQuery build(String appID, long timestamp, String nonce, String signature) {
            return new ZeroSignatureQuery(appID, timestamp, nonce, signature);
        }

        public static ZeroSignatureQuery build(String appID) {
            return new ZeroSignatureQuery(appID);
        }

        public ZeroSignatureQuery setSignature(String signature) {
            this.signature = signature;
            return this;
        }

        public String getAppID() {
            return appID;
        }

        public long getTimestamp() {
            return timestamp;
        }

        public String getNonce() {
            return nonce;
        }

        public String getSignature() {
            return signature;
        }
    }

    protected ZeroSignatureQuery signatureQuery;
    protected byte[] appSecret;
    protected T body;

    protected ZeroSignature(ZeroSignatureQuery signatureQuery, byte[] appSecret, T body) {
        super();
        this.signatureQuery = signatureQuery;
        this.appSecret = appSecret;
        this.body = body;
    }

    @SuppressWarnings("unchecked")
    public I setAppSecret(byte[] appSecret) {
        this.appSecret = appSecret;
        return (I) this;
    }

    public ZeroSignatureQuery getSignatureQuery() {
        return signatureQuery;
    }

    public byte[] getAppSecret() {
        return appSecret;
    }

    public T getBody() {
        return body;
    }

    public abstract I signature() throws Exception;

    public abstract I vaild() throws Exception;
}
