package zmo.technology.lite.signature;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import zmo.technology.lite.core.ZeroException;

public class ZeroRawSignature extends ZeroSignature<String, ZeroRawSignature> {

    public static final String RAW_SIGNATURE_PARAM = "raw";

    private Map<String, String> expands;

    private ZeroRawSignature(ZeroSignatureQuery signatureQuery, byte[] appSecret, String body) {
        super(signatureQuery, appSecret, body);
        expands = new HashMap<>();
    }

    public static ZeroRawSignature build(ZeroSignatureQuery signatureQuery, byte[] appSecret,
            String body) {
        return new ZeroRawSignature(signatureQuery, appSecret, body);
    }

    public void setExpands(Map<String, String> expands) {
        this.expands = expands;
    }

    public void addExpands(String key, String value) {
        expands.put(key, value);
    }

    private String makeSignature() {
        Map<String, String> copy = new HashMap<>();
        copy.put(SIGN_APP_ID, signatureQuery.getAppID());
        copy.put(SIGN_TIMESTAMP, String.valueOf(signatureQuery.getTimestamp()));
        copy.put(SIGN_NONCE, signatureQuery.getNonce());
        copy.put(RAW_SIGNATURE_PARAM, body);
        copy.putAll(expands);

        List<String> keys = new ArrayList<>(copy.keySet());
        keys.sort((a, b) -> a.compareTo(b));

        StringBuffer stringBuffer = new StringBuffer();

        for (String key : keys) {
            if (stringBuffer.length() > 0)
                stringBuffer.append("&");
            stringBuffer.append(key);
            stringBuffer.append("=");
            stringBuffer.append(copy.get(key));
        }
        return hmacSHA256Signature(stringBuffer.toString().getBytes());
    }

    @Override
    public ZeroRawSignature signature() {
        signatureQuery.setSignature(makeSignature());
        return this;
    }

    @Override
    public ZeroRawSignature vaild() throws ZeroException {
        if (!makeSignature().equals(signatureQuery.getSignature()))
            throw new ZeroException("invalid signature");
        return this;
    }
}
