package com.paytend.api.service;

import cn.hutool.core.codec.Base64;
import cn.hutool.json.JSONUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.paytend.api.utils.AESUtils;
import com.paytend.api.utils.PaytendUtil;
import com.paytend.api.utils.RSAUtils;

import java.util.*;

/**
 * @author wanghuaiqing
 * @description
 * @date 2023/9/12 13:14
 */
public class IBANService {

    private static final Log log = LogFactory.get();

    private static final String PAYTEND_BASE_URL = "https://sandbox-api.paytend.com/";
    private static final String PAYTEND_PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCedW8W+zf1ni+uYu3lVBNGIPhBVIlKy4hnpjQ9VJQlWBpBofcD7K+lbH0UHnoJvreZGb4TajKuZVSJJeR5q2rUVEwlZrTQimWjN4zqMV5rBlBz06mxSMRz5B3ilsX1cccgoQOle/l9DCSqnLg6DpFmQmqMVrTuYv7Sr22PZf2DoQIDAQAB";
    private static final String PARTNER_ID = "888666000100260";
    private static final String PARTNER_PRIVATE_KEY = "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAJ51bxb7N/WeL65i7eVUE0Yg+EFUiUrLiGemND1UlCVYGkGh9wPsr6VsfRQeegm+t5kZvhNqMq5lVIkl5HmratRUTCVmtNCKZaM3jOoxXmsGUHPTqbFIxHPkHeKWxfVxxyChA6V7+X0MJKqcuDoOkWZCaoxWtO5i/tKvbY9l/YOhAgMBAAECgYEAmqXv8pThy3REAsUIeq2wVdwtjc0MZRP5H3dlOooGP+AZV/7Tjl/8GM2l0PHhlwssMl6eVGJr7ip085kov9odWm18ICuYni3d0SWtohMC1ZdlELNyOHX2zSVfvv2vRR5sGwFuubeW4Fn0wzn1cgFStCgv1O3TaYooUuAoAKkgzTECQQDJiXktB/hpmT7nRBMeOgq2ldepvHkCzvM7HdCe4XeLMa/QMvvW9kuv3n7l7hAJqWwvVFSKOwU9nY/ruI/bJ3RNAkEAyUfDY3YjytN2z5dK/adC9exwo6MaX9Nhn+IWIhXQjF4tY3EHHcSG4JH8/JXmgs3VwsgqeuCLNulBavEA5gzGpQJAJ1TS9zzU+BbWNeANMxr0uElp+1Ay9Z9ZzLG24yrxX5Lk0ucASyVqA/qSHWFmc9xCpsH4dbmq/ilfywsL2CNNCQJBAMcb5F65eUKk2P0VzqsJEKYxlGNrbyWn9wSwI/Dn33tblk6uermptTrlb3t11adDctfSJqOTCGPzbjEZ4yevL7kCQHzgXvHk1YIchcj2+TJe5bzagJFvKGHj0xlxbcbmG3r9dyvkAK9os3Tq3wEAfe7VCuKGcPrNdeMRG/eC/+oTfxM=";
    private static final String VERSION = "2.0";
    private static final String SIGN_TYPE = "RSA";

    public static void main(String[] args) throws Exception {

        /**
         * Verify mobile number
         */
//        verifyMobileNumber();

        /**
         * createIndividualUser
         */
//        createIndividualUser();

        /**
         * Create corporation user
         */
//        createCorporationUser();

        /**
         * uploadSupportingDocuments
         */
//        uploadSupportingDocuments();

        /**
         * Individual questionnaire
         */
//        individualQuestionnaire();

        /**
         * Corporation questionnaire
         */
//        corporationQuestionnaire();

        /**
         * Query user information
         */
//        queryUserInformation();

        /**
         * Query cities
         */
//        queryCities();

        /**
         * Query user fees
         */
//        queryUserFees();

        /**
         * Query user upgrade fee
         */
//        queryUserUpgradeFee();

        /**
         * Query account information
         */
//        queryAccountInformation();

        /**
         * Query account balance
         */
        queryAccountBalance();

    }

    /**
     * Verify mobile number
     *
     * @return
     * @throws Exception
     */
    public static boolean verifyMobileNumber() throws Exception {
        // 创建一个新的HashMap
        Map<String, Object> bizData = new HashMap<>();
        // 设置值
        bizData.put("language", "zh");
        bizData.put("mobile", "+8613261405203");
        bizData.put("type", "1");
        String requestStr = initCommonRequest(JSONUtil.toJsonStr(bizData), true);
        log.debug("REQUEST:{}", JSONUtil.toJsonPrettyStr(requestStr));
        String responseStr = PaytendUtil.sendPost(PAYTEND_BASE_URL + "/iban/verifyMobile", requestStr);
        handleResponse(responseStr);
        return true;
    }

    /**
     * Create individual user
     *
     * @return boolean 是否成功
     */
    public static boolean createIndividualUser() throws Exception {
        // 创建一个新的HashMap
        Map<String, Object> bizData = new HashMap<>();
        Map<String, Object> person = new HashMap<>();


        Map<String, Object> address = new HashMap<>();
        address.put("addressLine", Base64.encode("北京朝阳"));
        address.put("addressLine2", Base64.encode("北京朝阳1号"));
        address.put("cityCode", "CN_11");
        address.put("state", "北京");
        address.put("postcode", "110110");
        address.put("countryCode", "CN");

        Map<String, Object> identity = new HashMap<>();
        identity.put("idType", "1");
        identity.put("idno", "110101202310205814");
        identity.put("issueDate", "2023-10-20");
        identity.put("expiryDate", "2023-10-20");

        person.put("lastName", "sss");
        person.put("firstName", "ssss");
        person.put("nativeLanguageName", Base64.encode("张三"));
        person.put("nationalityCode", "CN");
        person.put("gender", 1);
        person.put("birthday", "2023-10-11");
        person.put("residenceAddress", address);
        person.put("identityList", Arrays.asList(identity));

        // 设置值
        bizData.put("mobileCountryCode", "+86");
        bizData.put("mobile", "13261405202");
//        bizData.put("userType", "1");
        bizData.put("email", "3528111@qq.com");
        bizData.put("verifyCode", "666888");
        bizData.put("language", "zh");
        bizData.put("person", person);

        String requestStr = initCommonRequest(JSONUtil.toJsonStr(bizData), true);
        log.debug("REQUEST:{}", JSONUtil.toJsonPrettyStr(requestStr));
        String responseStr = PaytendUtil.sendPost(PAYTEND_BASE_URL + "/iban/createIndividual", requestStr);
        handleResponse(responseStr);
        /**
         {
         "respMsg": "",
         "respData": {
         "mobile": "+8613261405202",
         "uniqueId": "100342"
         },
         "respCode": "00"
         }
         */
        return true;
    }

    /**
     * Create corporation user
     *
     * @return boolean 是否成功
     */
    public static boolean createCorporationUser() throws Exception {
        // 创建一个新的HashMap
        Map<String, Object> bizData = new HashMap<>();

        /**
         * legalPerson.address
         */
        Map<String, Object> address = new HashMap<>();
        address.put("addressLine", Base64.encode("北京望京"));
        address.put("addressLine2", Base64.encode("北京望京"));
        address.put("cityCode", "CN_11");
        address.put("state", "北京");
        address.put("postcode", "110110");
        address.put("countryCode", "CN");

        /**
         * identityList
         */
        Map<String, Object> identity = new HashMap<>();
        identity.put("idType", "1");
        identity.put("idno", "110101202310205814");
        identity.put("issueDate", "2023-10-20");
        identity.put("expiryDate", "2023-10-20");

        /**
         * legalPerson
         */
        Map<String, Object> person = new HashMap<>();
        person.put("lastName", "si");
        person.put("firstName", "li");
        person.put("nativeLanguageName", Base64.encode("李四"));
        person.put("nationalityCode", "CN");
        person.put("gender", 1);
        person.put("birthday", "2023-10-11");
        person.put("residenceAddress", address);
        person.put("identityList", Arrays.asList(identity));

        /**
         * executiveList
         */
        Map<String, Object> executive = new HashMap<>();
        executive.put("lastName", "四");
        executive.put("firstName", "李");
        executive.put("birthday", "2023-10-20");
        executive.put("idType", "1");
        executive.put("idNo", "110101202310205814");
        executive.put("position", "1");

        /**
         * registrationAddress
         */
        Map<String, Object> registrationAddress = new HashMap<>();
        registrationAddress.put("addressLine", Base64.encode("北京望京"));
        registrationAddress.put("addressLine2", Base64.encode("北京望京"));
        registrationAddress.put("cityCode", "CN_11");
        registrationAddress.put("state", "北京");
        registrationAddress.put("postcode", "110110");
        registrationAddress.put("countryCode", "CN");

        // 设置值
        bizData.put("mobileCountryCode", "+86");
        bizData.put("mobile", "13261405203");
        bizData.put("email", "3528112@qq.com");
        bizData.put("verifyCode", "666888");
        bizData.put("language", "zh");
        bizData.put("corporationName", Base64.encode("Paytend"));
        bizData.put("registrationNo", "11101110");
        bizData.put("registrationDate", "2020-10-09");
        bizData.put("registrationAddress", registrationAddress);
        bizData.put("contactName", "王五");
        bizData.put("contactMobile", "+8613261405203");
        bizData.put("legalPerson", person);
        bizData.put("executiveList", Arrays.asList(executive));

        String requestStr = initCommonRequest(JSONUtil.toJsonStr(bizData), true);
        log.debug("REQUEST:{}", JSONUtil.toJsonPrettyStr(requestStr));
        String responseStr = PaytendUtil.sendPost(PAYTEND_BASE_URL + "/iban/createCorporation", requestStr);
        handleResponse(responseStr);
        /**
         * {
         *     "respMsg": "",
         *     "respData": {
         *         "mobile": "+8613261405203",
         *         "userId": "100345"
         *     },
         *     "respCode": "00"
         * }
         */
        return true;
    }


    /**
     * Upload supporting documents
     *
     * @return
     * @throws Exception
     */
    public static boolean uploadSupportingDocuments() throws Exception {
        // 创建一个新的HashMap
        Map<String, Object> bizData = new HashMap<>();
        // 设置值
        bizData.put("userId", "100342");
        bizData.put("fileType", "13");
//        bizData.put("fileContent", Base64.encode(new File("C:\\Users\\Administrator\\Desktop\\uploadtest.png")));
//        bizData.put("suffix", ".png");
        bizData.put("fileURL", "www.baidu.com");
//        bizData.put("idNo", ".png");

        String requestStr = initCommonRequest(JSONUtil.toJsonStr(bizData), false);
        log.debug("REQUEST:{}", JSONUtil.toJsonPrettyStr(requestStr));
        String responseStr = PaytendUtil.postJson(PAYTEND_BASE_URL + "/iban/uploadDocument", requestStr);
        handleResponse(responseStr);
        return true;
    }

    /**
     * Individual questionnaire
     *
     * @return
     * @throws Exception
     */
    public static boolean individualQuestionnaire() throws Exception {
        // 创建一个新的HashMap
        Map<String, Object> bizData = new HashMap<>();
        bizData.put("pep", "2");
        bizData.put("userId", "100342");
        bizData.put("emStatus", "1");
        bizData.put("socialMediaPlatform", "Twitter");
        bizData.put("socialMediaAccount", "123123@qq.com");
        bizData.put("fundingCountriesList", "CN,US,GB");
        bizData.put("expectMonthTurnover", "1");
        bizData.put("singleTransAverage", "1");
        bizData.put("openPurpose", "1");


        String requestStr = initCommonRequest(JSONUtil.toJsonStr(bizData), true);
        log.debug("REQUEST:{}", JSONUtil.toJsonPrettyStr(requestStr));
        String responseStr = PaytendUtil.postJson(PAYTEND_BASE_URL + "/iban/individualQuestionnaire", requestStr);
        handleResponse(responseStr);
        return true;
    }

    /**
     * Corporation questionnaire
     *
     * @return
     * @throws Exception
     */
    public static boolean corporationQuestionnaire() throws Exception {
        // 创建一个新的HashMap
        Map<String, Object> bizData = new HashMap<>();

        Map<String, Object> corpStructureList = new HashMap<>();
        corpStructureList.put("legalPersonName", "paytend");
        corpStructureList.put("nationality", "CN");
        corpStructureList.put("idno", "110101202310207158");
        corpStructureList.put("shareholdingRatio", "50");

        Map<String, Object> corpPartnerList = new HashMap<>();
        corpPartnerList.put("corpName", Base64.encode("测试公司"));
        corpPartnerList.put("industry", "2");
        corpPartnerList.put("countryCode", "CN");
        corpPartnerList.put("cityCode", "CN_11");
        corpPartnerList.put("address", Base64.encode("测试地址"));

        bizData.put("pep", "2");
        bizData.put("userId", "100345");
        bizData.put("industry", "1");
        bizData.put("socialMediaPlatform", "Twitter");
        bizData.put("socialMediaAccount", "123123@qq.com");
        bizData.put("obtainBusiness", "1");
        bizData.put("businessActivity", Base64.encode("支付"));
        bizData.put("employees", "1");
        bizData.put("website", "www.paytend.com");
        bizData.put("fundingCountriesList", "CN,US,GB");
        bizData.put("annualTurnover", "1");
        bizData.put("expectMonthTurnover", "1");
        bizData.put("singleTransAverage", "1");
        bizData.put("openPurpose", "1");
        bizData.put("corpStructureList", Arrays.asList(corpStructureList));
        bizData.put("corpPartnerList", Arrays.asList(corpPartnerList));

        String requestStr = initCommonRequest(JSONUtil.toJsonStr(bizData), true);
        log.debug("REQUEST:{}", JSONUtil.toJsonPrettyStr(requestStr));
        String responseStr = PaytendUtil.postJson(PAYTEND_BASE_URL + "/iban/corporationQuestionnaire", requestStr);
        handleResponse(responseStr);
        return true;
    }

    /**
     * Query user information
     *
     * @return
     * @throws Exception
     */
    public static boolean queryUserInformation() throws Exception {
        // 创建一个新的HashMap
        Map<String, Object> bizData = new HashMap<>();
        // 设置值
        /**
         * 100342 100345
         */
        bizData.put("userId", "100342");
//        bizData.put("mobile", "+8613261405201");

        String requestStr = initCommonRequest(JSONUtil.toJsonStr(bizData), true);
        log.debug("REQUEST:{}", JSONUtil.toJsonPrettyStr(requestStr));
        String responseStr = PaytendUtil.postJson(PAYTEND_BASE_URL + "/iban/getUser", requestStr);
        handleResponse(responseStr);
        return true;
    }

    /**
     * @return
     * @throws Exception
     */
    public static boolean queryCities() throws Exception {
        // 创建一个新的HashMap
        Map<String, Object> bizData = new HashMap<>();
        bizData.put("countryCode", "CN");
        bizData.put("maxResult", "10");
        bizData.put("start", "0");
        String requestStr = initCommonRequest(JSONUtil.toJsonStr(bizData), true);
        log.debug("REQUEST:{}", JSONUtil.toJsonPrettyStr(requestStr));
        String responseStr = PaytendUtil.postJson(PAYTEND_BASE_URL + "/iban/getCities", requestStr);
        handleResponse(responseStr);
        return true;
    }


    /**
     * 查询费率列表
     *
     * @return
     * @throws Exception
     */
    public static boolean queryUserFees() throws Exception {
        // 创建一个新的HashMap
        Map<String, Object> bizData = new HashMap<>();
        // 设置值
        bizData.put("userId", "100342");

        String requestStr = initCommonRequest(JSONUtil.toJsonStr(bizData), true);
        log.debug("REQUEST:{}", JSONUtil.toJsonPrettyStr(requestStr));
        String responseStr = PaytendUtil.postJson(PAYTEND_BASE_URL + "/iban/queryUserFees", requestStr);
        handleResponse(responseStr);
        return true;
    }

    /**
     * Query user upgrade fee
     *
     * @return
     * @throws Exception
     */
    public static boolean queryUserUpgradeFee() throws Exception {
        // 创建一个新的HashMap
        Map<String, Object> bizData = new HashMap<>();

        String requestStr = initCommonRequest(JSONUtil.toJsonStr(bizData), true);
        log.debug("REQUEST:{}", JSONUtil.toJsonPrettyStr(requestStr));
        String responseStr = PaytendUtil.postJson(PAYTEND_BASE_URL + "/iban/getUserUpgradeFee", requestStr);
        handleResponse(responseStr);
        return true;
    }

    /**
     * Query account information
     * @return
     * @throws Exception
     */
    public static boolean queryAccountInformation() throws Exception {
        // 创建一个新的HashMap
        Map<String, Object> bizData = new HashMap<>();
        bizData.put("userId","100041");


        String requestStr = initCommonRequest(JSONUtil.toJsonStr(bizData), true);
        log.debug("REQUEST:{}", JSONUtil.toJsonPrettyStr(requestStr));
        String responseStr = PaytendUtil.postJson(PAYTEND_BASE_URL + "/iban/getAccounts", requestStr);
        handleResponse(responseStr);
        return true;
    }

    /**
     * Query account balance
     * @return
     * @throws Exception
     */
    public static boolean queryAccountBalance() throws Exception {
        // 创建一个新的HashMap
        Map<String, Object> bizData = new HashMap<>();
        bizData.put("accountNum","LT343120023810001153");
        bizData.put("currency","EUR");


        String requestStr = initCommonRequest(JSONUtil.toJsonStr(bizData), true);
        log.debug("REQUEST:{}", JSONUtil.toJsonPrettyStr(requestStr));
        String responseStr = PaytendUtil.postJson(PAYTEND_BASE_URL + "/iban/getAccountBalance", requestStr);
        handleResponse(responseStr);
        return true;
    }



    /**
     * 初始化 公共请求信息
     *
     * @return
     */
    public static String initCommonRequest(String requestStr, boolean isAES) throws Exception {
        String aesKey = AESUtils.generateKey();

        Map<String, Object> commonRequestMap = new HashMap<>();

        commonRequestMap.put("requestId", PaytendUtil.genOutTradeNo() + PARTNER_ID);
        //commonRequestMap.put("requestId", "20240220140551409888666000100120");
        commonRequestMap.put("partnerId", PARTNER_ID);
        commonRequestMap.put("version", VERSION);
        commonRequestMap.put("signType", SIGN_TYPE);
        commonRequestMap.put("bizData", requestStr);
        commonRequestMap.put("randomKey", aesKey);
        String signDataString = getTreeValue(commonRequestMap, false);
        System.out.println("signData" + JSONUtil.parseObj(commonRequestMap));
        System.out.println("signDataString:" + signDataString);
        commonRequestMap.put("signature", RSAUtils.signSHA256(signDataString.getBytes("UTF-8"), PARTNER_PRIVATE_KEY));

        commonRequestMap.put("bizData", isAES == true ? AESUtils.encrypt(requestStr, aesKey) : JSONUtil.parseObj(requestStr));
        commonRequestMap.put("randomKey", RSAUtils.encryptPublicKey(aesKey, PAYTEND_PUBLIC_KEY));
        return JSONUtil.toJsonStr(commonRequestMap);
    }

    /**
     * 处理响应
     *
     * @param responseStr
     * @return
     * @throws Exception
     */
    public static void handleResponse(String responseStr) throws Exception {
        Map<String, Object> responseMap = JSONUtil.toBean(responseStr, Map.class);

        String respCode = String.valueOf(responseMap.get("respCode"));
        if (!"00".equals(respCode)) {
            log.debug("Request exception");
            log.debug(JSONUtil.toJsonStr(responseStr));
            return;
        }

        String randomKey = String.valueOf(responseMap.get("randomKey"));
        String respData = String.valueOf(responseMap.get("respData"));
        String signature = String.valueOf(responseMap.get("signature"));

        /**
         * randomKey RSA 解密
         */
        String randomKeyMsg = RSAUtils.decryptPrivateKey(randomKey, PARTNER_PRIVATE_KEY);
        responseMap.put("randomKey", randomKeyMsg);
        /**
         * respData AES 解密
         */
        String respDataMsg = "";
        if (StrUtil.isNotBlank(respData)) {
            respDataMsg = AESUtils.decrypt(respData, randomKeyMsg);
            responseMap.put("respData", JSONUtil.parseObj(respDataMsg));
        }

        /**
         * 验证 signature
         */
        responseMap.remove("encryptFlag");// 预留字段 不参与签名
        responseMap.remove("signature"); // 不参与签名
        String signDataString = getTreeValue(responseMap, false); // 计算签名串
        boolean flag = RSAUtils.verifySHA256(signDataString.getBytes("UTF-8"), PAYTEND_PUBLIC_KEY, signature);

        if (flag) {
            responseMap.put("respData", StrUtil.isNotBlank(respDataMsg) ? JSONUtil.parse(respDataMsg) : "");
            log.debug("RESPONSE:{}", JSONUtil.toJsonPrettyStr(responseMap));
        } else {
            log.debug("Response verification fail");
        }

    }

    public static String getTreeValue(Map<String, Object> toSortData, boolean emptyParamIsSign) {
        TreeMap<String, Object> params = new TreeMap<String, Object>();
        params.putAll(toSortData);
        StringBuffer orgin = new StringBuffer();
        Iterator<String> iter = params.keySet().iterator();
        while (iter.hasNext()) {
            String key = iter.next();
            String value = String.valueOf(params.get(key));
            if (emptyParamIsSign) {//空值参数参与签名
                orgin.append("&").append(key).append("=").append(value);
            } else {//空值参数不参与签名
                if (!StrUtil.isEmpty(value)) {
                    orgin.append("&").append(key).append("=").append(value);
                }
            }
        }
        return orgin.toString().substring(1);
    }
}
