package com.jeequan.jeepay.core.utils;

import cn.hutool.core.util.CharsetUtil;
import cn.hutool.crypto.SecureUtil;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.exception.BizException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;

/*
 * jeepay工具类
 *
 * @author terrfly
 *
 * @date 2021/6/8 16:50
 */
@Slf4j
public class JeepayKit {

    public static byte[] AES_KEY = "4ChT08phkz59hquD795X7w==".getBytes();
    public static String MBR_ACCOUNT_SAFE_KEY = "jRavptkL3YVOOrUqZsRuBnkaHjXHvcor";

    /**
     * 参数前缀
     */
    public static String TOKEN_KEY = "tk";

    /**
     * 加密
     **/
    public static String aesEncode(String str) {
        return SecureUtil.aes(JeepayKit.AES_KEY).encryptHex(str);
    }

    public static String aesDecode(String str) {
        return SecureUtil.aes(JeepayKit.AES_KEY).decryptStr(str);
    }

    private static String encodingCharset = "UTF-8";


    /**
     * 获取签名串
     *
     * @param map
     * @return urlParam.append(key).append(" = ").append(paraMap.get ( key) == null ? "" : paraMap.get(key) );
     */
    public static String getStrSort(Map<String, Object> map) {
        ArrayList<String> list = new ArrayList<>();
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            if (null != entry.getValue() && !"".equals(entry.getValue())) {
                list.add(entry.getKey() + "=" + entry.getValue() + "&");
            }
        }
        int size = list.size();
        String[] arrayToSort = list.toArray(new String[size]);
        Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER);
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < size; i++) {
            sb.append(arrayToSort[i]);
        }
        return sb.substring(0, sb.length() - 1);
    }

    /**
     * <p><b>Description: </b>计算签名摘要
     * <p>2018年9月30日 上午11:32:46
     *
     * @param map 参数Map
     * @param key 商户秘钥
     * @return
     */
    public static String getSign(Map<String, Object> map, String key) {
        ArrayList<String> list = new ArrayList<String>();
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            if (null != entry.getValue() && !"".equals(entry.getValue())) {
                list.add(entry.getKey() + "=" + entry.getValue() + "&");
            }
        }
        int size = list.size();
        String[] arrayToSort = list.toArray(new String[size]);
        Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER);
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < size; i++) {
            sb.append(arrayToSort[i]);
        }
        String result = sb.toString();
        result += "key=" + key;
        log.info("signStr:{}", result);
        result = md5(result, encodingCharset).toUpperCase();
        log.info("sign:{}", result);
        return result;
    }


    /**
     * <p><b>Description: </b>MD5
     * <p>2018年9月30日 上午11:33:19
     *
     * @param value
     * @param charset
     * @return
     */
    public static String md5(String value, String charset) {
        MessageDigest md = null;
        try {
            byte[] data = value.getBytes(charset);
            md = MessageDigest.getInstance("MD5");
            byte[] digestData = md.digest(data);
            return toHex(digestData);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            return null;
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            return null;
        }
    }

    public static String toHex(byte input[]) {
        if (input == null) {
            return null;
        }
        StringBuffer output = new StringBuffer(input.length * 2);
        for (int i = 0; i < input.length; i++) {
            int current = input[i] & 0xff;
            if (current < 16) {
                output.append("0");
            }
            output.append(Integer.toString(current, 16));
        }

        return output.toString();
    }

    /**
     * map 转换为  url参数
     **/
    public static String genUrlParams(Map<String, Object> paraMap) {
        if (paraMap == null || paraMap.isEmpty()) {
            return "";
        }
        StringBuffer urlParam = new StringBuffer();
        Set<String> keySet = paraMap.keySet();
        int i = 0;
        for (String key : keySet) {
            urlParam.append(key).append("=").append(paraMap.get(key) == null ? "" : doEncode(paraMap.get(key).toString()));
            if (++i == keySet.size()) {
                break;
            }
            urlParam.append("&");
        }
        return urlParam.toString();
    }

    static String doEncode(String str) {
        if (str.contains("+")) {
            try {
                return URLEncoder.encode(str, "utf-8");
            } catch (Exception e) {
                return null;
            }
        }
        return str;
    }

    /**
     * 校验微信/支付宝二维码是否符合规范， 并根据支付类型返回对应的支付方式
     **/
    public static String getPayWayCodeByBarCode(String barCode) {

        if (StringUtils.isEmpty(barCode)) {
            throw new BizException("条码为空");
        }

        //微信 ： 用户付款码条形码规则：18位纯数字，以10、11、12、13、14、15开头
        //文档： https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=5_1
        if (barCode.length() == 18 && Pattern.matches("^(10|11|12|13|14|15)(.*)", barCode)) {
            return CS.PAY_WAY_CODE.WX_BAR;
        }
        //支付宝： 25~30开头的长度为16~24位的数字
        //文档： https://docs.open.alipay.com/api_1/alipay.trade.pay/
        else if (barCode.length() >= 16 && barCode.length() <= 24 && Pattern.matches("^(25|26|27|28|29|30)(.*)", barCode)) {
            return CS.PAY_WAY_CODE.ALI_BAR;
        }
        //云闪付： 二维码标准： 19位 + 62开头
        //文档：https://wenku.baidu.com/view/b2eddcd09a89680203d8ce2f0066f5335a8167fa.html
        else if (barCode.length() == 19 && Pattern.matches("^(62)(.*)", barCode)) {
            return CS.PAY_WAY_CODE.YSF_BAR;
        }
        //数字人民币：01开头
        //文档：https://paas.tianquetech.com/docs/#/api/bs
        else if (barCode.length() == 19 && Pattern.matches("^(01)(.*)", barCode)) {
            return CS.PAY_WAY_CODE.DCEP_BAR;
        } else {  //暂时不支持的条码类型
            throw new BizException("不支持的条码");
        }
    }

    /**
     * 生成账户数据保护 签名数据(根据数据库对象)
     */
    public static String genAccountSafeKey(String mbrId, Long balance) {
        StringBuffer signStr = new StringBuffer();
        signStr.append(mbrId).append("_");
        signStr.append(balance).append("_");
        return md5(signStr.append(MBR_ACCOUNT_SAFE_KEY).toString(), CharsetUtil.UTF_8);
    }

    /**
     * 支付接口克隆，调用三方接口时ifCode处理
     * 传入原始或克隆 ifCode或ifCode_1
     * 返回的是  原始ifCode
     */
    public static String getIfCodeOrigin(String ifCdoe) {
        if (StringUtils.isNotBlank(ifCdoe) && ifCdoe.contains("_")) {
            return ifCdoe.split("_")[0];
        }

        return ifCdoe;
    }

    /**
     * 微信支付目录配置判断
     **/
    public static String configPayUrlConvert(String payUrl) {
        if (StringUtils.isEmpty(payUrl)) return payUrl;
        // 截取末尾字符串判断
        String lastStr = payUrl.substring(payUrl.length() - 1);
        if ("/".equals(lastStr)) {
            return payUrl;
        } else {
            return payUrl + "/";
        }
    }

}
