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

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.crm.pay.entity.callback.NaceCallbackEntity;
import com.crm.pay.entity.property.NacePropertyEntity;
import com.crm.pay.service.FinanceDepositService;
import com.crm.pay.service.NaceService;
import com.crm.pay.service.impl.base.BasePayServiceImpl;
import com.crm.pay.utils.BigDecimalUtil;
import com.crm.rely.backend.core.constant.Constants;
import com.crm.rely.backend.model.constant.PayConstants;
import com.crm.rely.backend.model.entity.finance.deposit.FinanceDepositAddEntity;
import com.crm.pay.entity.FinanceDepositCallbackUpdateEntity;
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.*;
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.math.BigDecimal;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

import static com.alibaba.fastjson.JSON.parseObject;

/**
 * @description:
 * @author: houn
 * @create: 2024-05-08 23:44
 */
@Slf4j
@Service
public class NaceServiceImpl extends BasePayServiceImpl implements NaceService {

    @Autowired
    private FinanceDepositService balanceService;

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

        SysRemittanceChannelTable channel = getPayChannel(PayConstants.NACE_PAY_TYPE);

        NacePropertyEntity payProperty = getPayProperty(channel, NacePropertyEntity.class);

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

        String url = getUrl(balanceTable, payProperty);
        balanceTable.setFormUrl(url);
        
        return url;
    }

    /**
     * 回调处理数据
     *
     * @param
     * @throws Exception
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void callback(String body, String sign) throws Exception {
        NaceCallbackEntity callbackEntity = JSON.parseObject(body, NaceCallbackEntity.class);
        log.info(String.format("callback orderNo:%s,callback data:%s,sign:%s",
                callbackEntity.getRefId(), body, sign));
        callbackEntity.setSign(sign);
        boolean flag = validate(callbackEntity, body);
        if (!flag) {
            throw new ServiceException(Constants.FAIL);
        }

        FinanceDepositCallbackUpdateEntity balanceCallbackUpdateEntity =
                getFinanceDepositCallbackUpdateEntity(callbackEntity.getStatus(),
                        callbackEntity.getRefId(),
                        callbackEntity.getTransactionId(), PayConstants.NACE_PAY_SUCCESS_STATUS, callbackEntity);
        BigDecimal amount = new BigDecimal(callbackEntity.getAmount());
        balanceCallbackUpdateEntity.setTransformAmount(amount);
//        SysRemittanceChannelTable channel = getPayChannel(PayConstants.NACE_PAY_TYPE);
//        if (callbackEntity.getCurrency().equals(channel.getCurrency())) {
//            amount = new BigDecimal(callbackEntity.getTotal());
//            balanceCallbackUpdateEntity.setAmount(amount);
//        }


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

    /**
     * 获取支付url
     *
     * @param balanceTable
     * @return
     * @throws ServiceException
     */
    private String getUrl(FinanceDepositTable balanceTable,
                          NacePropertyEntity payProperty) throws Exception {


        Map<String, String> params = new LinkedHashMap<>(10);
        params.put("ref_id", String.format("%s_%d", balanceTable.getSerial(), balanceTable.getLogin()));
        params.put("url", payProperty.getCallbackUrl());
        params.put("timestamp", String.valueOf(balanceTable.getAddTime().getTime() / 1000));
        params.put("nonce", GetRandom.getRandom(6));
        params.put("currency", balanceTable.getCurrency());

        String data = JSON.toJSONString(params);

        String url = String.format(payProperty.getBaseUrl(), balanceTable.getBankCode().toLowerCase().replace("-",
                "/"));


        String bodyString = String.format("ref_id=%s&url=%s&timestamp=%s&nonce=%s&currency=%s", params.get("ref_id"),
                params.get("url"),
                params.get("timestamp"), params.get("nonce"), params.get("currency"));
        String sign = getSign(payProperty, bodyString);
        Map<String, String> header = new HashMap<>(4);

        header.put("apikey", payProperty.getApiKey());
        header.put("merchant_id", payProperty.getMerchantId());
        header.put("authentication", Base64Util.toBase64String(payProperty.getApiKey() + ":" + sign));

        log.info(String.format("nace send url:%s,params:%s,header:%s", url,
                data, JSON.toJSONString(header)));

        Connection.Response response = HttpUtil.post(url,
                header, data);
        String payString = response.body();

        log.info("nace response body:" + payString);

        JSONObject urlDataEntity = parseObject(payString);
        if (urlDataEntity == null) {
            throw ServiceException.exception();
        }

        if (!"success".equals(urlDataEntity.getString("status"))) {

            throw new PayValidatedException(urlDataEntity.getString("message"));
        }


//        balanceTable.setRate(new BigDecimal(urlDataEntity.getJSONObject("data").getString("price")));

        return String.format(payProperty.getPayUrl(), urlDataEntity.getJSONObject("data").get("address"),
                payProperty.getSuccessUrl(),
                String.valueOf(BigDecimalUtil.toStripTrailingZerosString(balanceTable.getTransformAmount())),
                balanceTable.getTransformCurrency());

    }

    /**
     * 验证回调参数是否被篡改
     *
     * @return
     * @throws ServiceException
     */
    private boolean validate(NaceCallbackEntity callbackEntity, String body) throws Exception {
        NacePropertyEntity payProperty = getPayProperty(PayConstants.NACE_PAY_TYPE, false,
                NacePropertyEntity.class);

        String vSign = getSign(payProperty, body);

        log.info(String.format("callback result sign compare,data:%s,HAMCSHA512--callback sign:%s,callback " +
                        "string HAMCSHA512Util:%s", body
                , callbackEntity.getSign(),
                vSign));
        return vSign.equals(callbackEntity.getSign());
    }

    public static void main(String[] args) {

//        System.out.println(AESUtil.decrypt("", "bfa5559109f94c78af615bcf00d52060"));
        System.out.println(AESUtil.encrypt("{\n" +
                "    \"merchantId\":\"57146\",\n" +
                "    \"apiKey\":\"32a1aacf-4d0c-4d16-b769-3b68299f3280\",\n" +
                "    \"secretKey\":\"5dfdbb02-d3b6-44a5-8500-ff5a8f76a06f\",\n" +
                "    \"baseUrl\":\"https://payapi.newagecrypto.com:5000/usr/wallet/%s/create\",\n" +
                "    \"payUrl\":\"/pay/nace.html?address=%s&successUrl=%s&amount=%s&currency=%s\",\n" +
                "    \"successUrl\":\"/nace/pickup\",\n" +
                "    \"callbackUrl\":\"https://pay.cwgvu.com/nace/callback\"\n" +
                "}", "bfa5559109f94c78af615bcf00d52060"));
//
//        System.out.println(Base64Util.toBase64String(HAMCSHAUtil.shaHMACByte("ref_id=PD202405131459416345_66703004" +
//                "&url=https://testpay" +
//                ".cwgvu" +
//                ".com/nace/callback&timestamp=1715583581&nonce=799751&currency=USD", "16a23c7c-dd7d-4d44-b079" +
//                "-df0c15a46a0e", "HmacSHA512")));
//        ;

    }

    private String getSign(NacePropertyEntity payProperty, String data) throws Exception {

        String sign = HAMCSHAUtil.sha512HMAC(data, payProperty.getSecretKey());

//        String sign = Base64Util.toBase64String(HAMCSHAUtil.shaHMACByte(data, payProperty.getSecretKey(), "HmacSHA512"
//        ));
        log.info(String.format("data:%s,HAMCSHA512-sign:%s", data, sign));
        return sign;
    }


}
