package com.tcl.ah.security;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;

import org.apache.commons.codecc.binary.Base64;

import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;

public class LaravelHelper {
    private static final int IV_LENGTH = 16;


    public static String encrypt(String key,String data)throws JsonProcessingException, NoSuchAlgorithmException, NoSuchPaddingException,
            InvalidKeyException, InvalidAlgorithmParameterException, BadPaddingException, IllegalBlockSizeException {
        byte[] IV = PayLoad.randomIV();
        byte[] keyByte = Base64.decodeBase64(key);
        PayLoad payLoad = new PayLoad();
        payLoad.value = Base64.encodeBase64String(OpenSslAES.openssl_encrypt(keyByte,data.getBytes(), IV));
        payLoad.iv = Base64.encodeBase64String(IV);
        payLoad.hmac = HmacSha256.encrypt(payLoad.iv+payLoad.value,keyByte);
        String jsonResult = payLoad.toJson();
        return Base64.encodeBase64String(jsonResult.getBytes());
    }

    /**
     *
     * @param key  //use base64 decode
     * @param data
     * @return
     * @throws IOException
     * @throws NoSuchAlgorithmException
     * @throws NoSuchPaddingException
     * @throws InvalidKeyException
     * @throws InvalidAlgorithmParameterException
     * @throws BadPaddingException
     * @throws IllegalBlockSizeException
     */
    public static String decrypt(String key,String data)throws IOException, NoSuchAlgorithmException, NoSuchPaddingException,
            InvalidKeyException, InvalidAlgorithmParameterException, BadPaddingException, IllegalBlockSizeException {
        //将密文通过Base64解码以后的数据
        String payloadStr = new String(Base64.decodeBase64(data));
        PayLoad payLoad = PayLoad.parse(payloadStr);
        if(payLoad.isLegal()){
            byte[] IV = payLoad.getIvOfByte();
            if (IV.length == IV_LENGTH) {
                byte [] keyByte= Base64.decodeBase64(key);
                byte [] value = Base64.decodeBase64(payLoad.value);
                return OpenSslAES.openssl_decrypt(keyByte,value, IV);
            }
        }
        throw new IOException("params is illegal");
    }
    private static class PayLoad{
        public static final String PARAM_IV="iv";
        public static final String PARAM_VALUE="value";
        public static final String PARAM_HMAC="mac";
        public String iv="";
        public String value="";
        public String hmac="";

        public String toJson()throws JsonProcessingException{
            ObjectMapper mapper = new ObjectMapper();
            ObjectNode root = mapper.createObjectNode();
            root.put(PARAM_IV,iv);
            root.put(PARAM_VALUE,value);
            root.put(PARAM_HMAC,hmac);
            return mapper.writeValueAsString(root);
        }

        public boolean isLegal(){
            if (iv!=null&&iv.length()!=0 &&
                    value!=null&&value.length()!=0&&
                    hmac!=null&hmac.length()!=0){
                return true ;
            }
            return false ;
        }
        public byte[] getIvOfByte(){
            return Base64.decodeBase64(iv);
        }
        public static PayLoad parse(String payLoadStr)throws IOException {
            ObjectMapper mapper = new ObjectMapper();
            JsonNode node = mapper.readTree(payLoadStr);
            PayLoad payLoad = new PayLoad();
            payLoad.iv = node.get(PARAM_IV).asText();
            payLoad.hmac = node.get(PARAM_HMAC).asText();
            payLoad.value = node.get(PARAM_VALUE).asText();
            return payLoad;
        }

        public static byte[] randomIV(){
            //TODO
            String IVStr ="Ym2SKPMCjT0yfzhAowxE6g==";
            return Base64.decodeBase64(IVStr);
        }
    }
}
