package com.crm.pay.service.impl.pay;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.crm.pay.dto.xpay.XPayCryptocurrenciePaymentDataDto;
import com.crm.pay.entity.FinanceDepositCallbackUpdateEntity;
import com.crm.pay.entity.property.XPayCryptocurrenciePropertyEntity;
import com.crm.pay.service.CustomInfoService;
import com.crm.pay.service.FinanceDepositService;
import com.crm.pay.service.XPayCryptocurrencieService;
import com.crm.pay.service.impl.base.BasePayServiceImpl;
import com.crm.pay.utils.BitcoinjECDSAUtil;
import com.crm.rely.backend.model.constant.PayConstants;
import com.crm.rely.backend.model.entity.finance.deposit.FinanceDepositAddEntity;
import com.crm.rely.backend.model.pojo.table.FinanceDepositTable;
import com.crm.rely.backend.model.pojo.table.SysRemittanceChannelTable;
import com.crm.rely.backend.core.exception.PayValidatedException;
import com.crm.rely.backend.core.exception.ServiceException;
import com.crm.rely.backend.util.HAMCSHA256Util;
import com.crm.rely.backend.util.HttpUtil;
import com.crm.rely.backend.util.MapUtil;
import com.google.common.base.Strings;
import lombok.extern.slf4j.Slf4j;
import org.jsoup.Connection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;

/**
 * @program:
 * @description:
 * @author: houn
 * @create: 2024-04-23 11:45
 */
@Slf4j
@Service
public class XPayCryptocurrencieServiceImpl extends BasePayServiceImpl implements XPayCryptocurrencieService {
    @Autowired
    private FinanceDepositService financeDepositService;

    @Autowired
    private CustomInfoService customInfoService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String pay(FinanceDepositAddEntity balanceSaveEntity) throws Exception {

        //通道配置
        SysRemittanceChannelTable channel = getPayChannel(PayConstants.XPAY_PAY_CRYPTOCURRENCIE_TYPE);
        //通道配置实体
        XPayCryptocurrenciePropertyEntity payProperty = getPayProperty(channel,
                XPayCryptocurrenciePropertyEntity.class);

        FinanceDepositTable balanceTable = financeDepositService.save(balanceSaveEntity, channel);

        String url = payment(payProperty, balanceTable);
        balanceTable.setFormUrl(url);

        return url;
    }

    /**
     * 回调处理数据
     *
     * @param callbackEntity
     * @throws ServiceException
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void callback(Map<String, String> callbackEntity) throws Exception {

        log.info(String.format("callback orderNo:%s,callback data:%s",
                callbackEntity.get("customer_code"), JSON.toJSONString(callbackEntity)));

        if (!validate(callbackEntity)) {
            throw new ServiceException("fail");
        }


        FinanceDepositCallbackUpdateEntity balanceCallbackUpdateEntity =
                getFinanceDepositCallbackUpdateEntity(PayConstants.XPAY_PAY_CRYPTOCURRENCIE_SUCCESS_STATUS,
                        callbackEntity.get("customer_code"),
                        callbackEntity.get("transaction_id"),
                        callbackEntity.get("fund_status"), callbackEntity);


        balanceCallbackUpdateEntity.setTransformAmount(new BigDecimal(callbackEntity.get("value")).divide(new BigDecimal(1000000), 5, BigDecimal.ROUND_DOWN));


//        /**
//         * 更新数据
//         */
        financeDepositService.updateCallback(balanceCallbackUpdateEntity);
    }

    private String payment(XPayCryptocurrenciePropertyEntity propertyEntity,
                           FinanceDepositTable financeDepositTable) throws Exception {

        String nonce = String.valueOf(System.currentTimeMillis());
        Map<String, String> params = new HashMap<>(10);

        params.put("symbol", "TRC_USDT");
        params.put("customer_code", financeDepositTable.getSerial() + "_" + financeDepositTable.getLogin());

        String sign = getSign(propertyEntity, params, propertyEntity.getAddressCreate(), nonce);

        Map<String, String> headers = new HashMap<>(3);
        headers.put("BIZ-API-KEY", propertyEntity.getApiKey());
        headers.put("BIZ-API-SIGNATURE", sign);
        headers.put("BIZ-API-NONCE", nonce);

        String paymentUrl = propertyEntity.getBaseUrl() + propertyEntity.getAddressCreate();

        log.info(String.format("order:%s, payment send rul:%s,params:%s,headers:%s",
                params.get("customer_code"), paymentUrl,
                JSON.toJSONString(params), JSON.toJSONString(headers)));


        String data = JSON.toJSONString(params);

        Connection.Response response = HttpUtil.post(paymentUrl, headers, data);

        log.info(String.format("order:%s,payment response body is:%s", params.get("customer_code"),
                response.body()));


        JSONObject jsonObject = JSON.parseObject(response.body());

        if (!jsonObject.getInteger("code").equals(0)) {
            throw new PayValidatedException(jsonObject.getString("msg"));
        }

        XPayCryptocurrenciePaymentDataDto xPayPaymentDataDto = JSON.parseObject(jsonObject.getString("data"),
                XPayCryptocurrenciePaymentDataDto.class);


        if (Strings.isNullOrEmpty(xPayPaymentDataDto.getAddress())) {
            log.error("payment xPayPaymentDataDto.getAddress() is null");
            throw new PayValidatedException("Payment platform is abnormal, please try again later or contact customer" +
                    " service.");
        }

        String url = String.format(propertyEntity.getPayUrl(), financeDepositTable.getCurrency(),
                "TRC20",
                String.format("%.2f", financeDepositTable.getTransformAmount().doubleValue()),
                xPayPaymentDataDto.getAddress());
        log.info(String.format("xpayCryptocurrencie,payment orderNo:%s,url:%s",
                financeDepositTable.getSerial() + "_" + financeDepositTable.getLogin(),
                url));

        return url;

    }

    private boolean validate(Map<String, String> callbackEntity) throws Exception {
        XPayCryptocurrenciePropertyEntity payProperty = getPayProperty(PayConstants.XPAY_PAY_CRYPTOCURRENCIE_TYPE, false,
                XPayCryptocurrenciePropertyEntity.class);

        String callbackSign = callbackEntity.get("sign");
        callbackEntity.remove("sign");
        callbackEntity.remove("side");
        String signString = composeParams(callbackEntity).replace("+", "%20");

        String sign = HAMCSHA256Util.HMACSHA256(signString,
                payProperty.getPubKey());

        log.info(String.format("order:%s,signString:%s,HMACSHA256:%s", callbackEntity.get("customer_code"),
                signString,
                sign));


        return sign.equals(callbackSign);
    }

    private String getSign(XPayCryptocurrenciePropertyEntity propertyEntity, Map<String, String> params, String url,
                           String nonce) throws Exception {
        String signString = composeParams(params);
        signString =
                "POST|" + url + "|" + nonce + "|" + signString;
        String sign = BitcoinjECDSAUtil.sign(propertyEntity.getPriECDSA(), signString);

        log.info(String.format("signString:%s,signECDSA:%s", signString, sign));

        return sign;
    }

    private static String composeParams(Map<String, String> params) {
        StringBuffer sb = new StringBuffer();
        MapUtil.sortByKey(params, false).forEach((s, o) -> {
            try {
                if ("kyc_name".equals(s)) {
                    sb.append(s).append("=").append(URLEncoder.encode(String.valueOf(o), "UTF-8").replace("+", "%20")).append("&");
                } else {
                    sb.append(s).append("=").append(URLEncoder.encode(String.valueOf(o), "UTF-8")).append("&");
                }

            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        });
        if (sb.length() > 0) {
            sb.deleteCharAt(sb.length() - 1);
        }
        return sb.toString();
    }


    public static void main(String[] args) throws UnsupportedEncodingException {
//        System.out.println(AESUtil.decrypt("yi/5CoioHqnlpsoejjQW55tDVJZeRWCCZIcpFb" +
//                "/AnsdUXzBtn2ScNUTC8zt6jXOn1N5qvnBC7YBPqz8m7YsoOKe5uqqAlNjwoaQQ98nCSK/b" +
//                "+OKlQUPG3DgwXgrIZt80KnTcMaI2wlRA1IWp15Y8f7BvwF+bBG+FvM6yR0vBm7NcUgkF8kMs9C9Xi+yhN39P9/bIKgAyONT16r" +
//                "/SskIOSDxc5Bdz+V1OqHjIO8SX/zjhxdofbKm6vVfUy9KzY64OatBLyPExpxKohB1k6Kx6hLMk09HFYYyNoc3IC+LePRc8t" +
//                "/wG2Nr0phG+oNZNPgoPv6Fwsr4AJ8wPaIwpZSySnS+JaLmgXGawUx/nyw
//                +dj1aNUPU5AlmzIjpO95xZiif7IbsThw535RvAkTU3" +
//                "/lDxTfVCRZssOcUys/vaPkQVhmLc/bRLOrRe9XuWcrxhKDbAz4e94zJQyAsfwEQPBgvnqEhGbTD8oqHadL6m5LvGnwOQ" +
//                "+VRSRIx4n38snv8L+GCs\n", "bfa5559109f94c78af615bcf00d52060"));
////
//        System.out.println(AESUtil.encrypt("{\n" +
//                "    \"apiKey\":\"428083fa78da4006b00594e49a0f1454\",\n" +
//                "    \"pubKey\":\"028ad72dd432b025d5e10c6f674d936149b692066cc5c84a6352215b3c06a377fe\",\n" +
//                "    \"priECDSA\":\"bcaaa6a452bdc032311d85cd31b191c62540765037656d107cb03e948e8f4fd4\",\n" +
//                "    \"addressCreate\":\"/v1/custody/address/create\",\n" +
//                "    \"baseUrl\":\"https://api.xpay.pro\",\n" +
//                "    \"payUrl\":\"/pay/xpayaddress.html?currency=%s&currencyType=%s&amount=%s&address=%s\"\n" +
//                "}", "bfa5559109f94c78af615bcf00d52060"));
//
//
//        System.out.println(BitcoinjECDSAUtil.sign("bb06971bb6abb30da07f095a286e4e89ffd2b44cc83ea4d14fc68f85924884e1",
//                "123123"));

        String signString = "block_timestamp=1743579288000&callback_status=0&contract_addr" +
                "=TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t&created_time=2025-04-02%2007%3A35%3A55&customer_code" +
                "=PD1743571964_5566000&decimals=6&from=TMZjRQV1FcR9oyExa6CbqJPgzC8TnxM6rM&fund_status=0&is_deposit=1" +
                "&is_rollup=0&name=USDT&symbol=USDT&time=2025-04-02%2007%3A34%3A48&to" +
                "=TVXeGTmxFB49q2f1XmY4PK6JtLi8QGGZWW&token_info=1&transaction_id" +
                "=dfd9372261be3e2799bbba771c1a6f586a91480317515bce8d421abd5a56eca5&type=TriggerSmartContract&value" +
                "=17100000.00000000";
        String puk = "028ad72dd432b025d5e10c6f674d936149b692066cc5c84a6352215b3c06a377fe";
        System.out.println(HAMCSHA256Util.HMACSHA256(signString,
                puk));

//        System.out.println(URLEncoder.encode(String.valueOf("Wei Li-T").replace(" ", "%20"), "UTF-8"));
//        System.out.println(URLEncoder.encode(String.valueOf("Wei Li-T"), "UTF-8").replace("+", "%20"));

    }


}
