package com.qmth.boot.tools.signature;

import com.qmth.boot.tools.models.ByteArray;
import org.apache.commons.lang3.StringUtils;

import java.text.MessageFormat;

/**
 * 签名数据对象，包括构造、解析、验证的通用方法
 */
public class SignatureEntity {

    private static final String PATTERN = "{0} {1}{2}{3}";

    private static final String FIELD_JOINER = ":";

    private static final String PARAM_JOINER = "&";

    private SignatureType type;

    private String method;

    private String uri;

    private long timestamp;

    private String ciphertext;

    private String invoker;

    private String secret;

    private SignatureEntity() {
    }

    public SignatureType getType() {
        return type;
    }

    private void setType(SignatureType type) {
        this.type = type;
    }

    public String getMethod() {
        return method;
    }

    private void setMethod(String method) {
        this.method = method;
    }

    public String getUri() {
        return uri;
    }

    private void setUri(String uri) {
        this.uri = uri;
    }

    public long getTimestamp() {
        return timestamp;
    }

    private void setTimestamp(long timestamp) {
        this.timestamp = timestamp;
    }

    private String getCiphertext() {
        return ciphertext;
    }

    private void setCiphertext(String ciphertext) {
        this.ciphertext = ciphertext;
    }

    public String getInvoker() {
        return invoker;
    }

    private void setInvoker(String invoker) {
        this.invoker = invoker;
    }

    public String getSecret() {
        return secret;
    }

    private void setSecret(String secret) {
        this.secret = secret;
    }

    private static String encrypt(String... values) {
        return ByteArray.sha1(StringUtils.join(values, PARAM_JOINER)).toBase64();
    }

    /**
     * 基于解析好的签名对象，使用传入的保密信息进行签名内容验证
     *
     * @param secret
     * @return
     */
    public boolean validate(String secret) {
        if (method != null && uri != null && timestamp >= 0 && secret != null && ciphertext != null) {
            return encrypt(method, uri, String.valueOf(timestamp), secret).equals(ciphertext);
        }
        return false;
    }

    /**
     * 根据标准参数构造最终的签名字符串
     *
     * @param type
     * @param method
     * @param uri
     * @param timestamp
     * @param invoker
     * @param secret
     * @return
     */
    public static String build(SignatureType type, String method, String uri, long timestamp, String invoker,
            String secret) {
        if (type == null || method == null || uri == null || timestamp <= 0 || invoker == null || secret == null) {
            return "";
        }
        return MessageFormat.format(PATTERN, type.getName(), invoker, FIELD_JOINER,
                encrypt(method.toLowerCase(), uri, String.valueOf(timestamp), secret));
    }

    /**
     * 根据当前接口的的基本信息、header中的时间戳与签名字符串，尝试解析并构造签名数据对象
     *
     * @param method
     * @param uri
     * @param timestamp
     * @param signature
     * @return
     */
    public static SignatureEntity parse(String signature, String method, String uri, long timestamp) {
        String[] values = StringUtils.split(StringUtils.trimToEmpty(signature));
        if (values != null && values.length == 2) {
            SignatureType type = SignatureType.findByName(values[0]);
            if (type != null) {
                String[] array = StringUtils.split(values[1], FIELD_JOINER);
                if (array != null && array.length == 2) {
                    SignatureEntity entity = new SignatureEntity();
                    entity.setType(type);
                    entity.setMethod(method.toLowerCase());
                    entity.setUri(uri);
                    entity.setTimestamp(timestamp);
                    entity.setInvoker(array[0]);
                    entity.setCiphertext(array[1]);
                    return entity;
                }
            }
        }
        return null;
    }

}
